💣

誤ってIAMロールを大量削除した話

に公開

はじめに

数年前、私たちSREチームが管理するステージング環境で、複数のIAMロールが予期せず削除されるというヒヤリハットが発生しました。この記事では、その事例から得られた教訓を共有したいと思います。

タイトル

経緯

Terraformで管理しているセキュリティグループのポリシー更新作業中に、ステージング環境の複数のIAMロールが意図せず削除される事象が発生しました。

  1. 緊急のセキュリティグループポリシー変更依頼があった
  2. 依頼内容の対応時に、別環境の設定を参考にしてstateファイルのリファクタリングを実施した
  3. レビュー時に、S3に保管されているstateファイルのkey変更を見落としてしまった
  4. 誤ったstateファイルのkeyの状態でapplyを実行し、その結果別環境のIAMロールが削除された

影響範囲

以下にIAMロール消失による影響をまとめます。

早期に復旧できたため開発作業への影響は発生しませんでしたが、復旧に時間を要した場合や本番環境で発生していた場合、重大な影響をもたらす可能性がありました。

サービス名 影響
ECS タスクの起動失敗、CloudWatch Logsへのログ転送失敗
CloudWatch Logs Firehoseへの書き込みが失敗
Firehose エラーが発生した際のログS3書き込み失敗
Lambda 実行失敗
S3 レプリケーション失敗

復旧作業

基本的な復旧はTerraformでIAMロールを再作成するだけで完了しましたが、一部のサービスでは追加の対応が必要でした。

CloudWatch Logs

CloudWatch Logs のサブスクリプションは、IAM ロールが削除されると即座にストリーム送信が失敗し、失敗したログイベントはバッファやリトライキューに保持されません。

そこで、影響期間中のログを再度ログループにPutすることで、連携先への再送を実施しました。

Lambda

IAMロールを再作成したところ、下記のようなエラーログが出力されるようになりました。

Status Code: 502; Error Code: KMSAccessDeniedException;

調査したところ、IAMロールを同じ名前で再作成した場合に発生する問題だと判明しました。

KMSAccessDeniedException エラーは、通常、Lambda 関数の IAM ロールが削除され、同じ名前で再作成されたときに発生します。これが起こった場合は、関数に新しい IAM ロールを設定します。その後、関数を再度デプロイし、以前の IAM ロールを再設定します。
https://repost.aws/ja/knowledge-center/lambda-troubleshoot-invoke-error-502-500

このエラーは説明の通り、一時的に別のロールを割り当てた後、元のロールを再度割り当てることで解消できます。

S3

2点のレプリケーションに関する復旧作業が必要でした。

1点目として、影響期間中に失敗したレプリケーションをS3バッチオペレーションを使用して復旧しました。このツールを使用することで、s3apiなどよりも迅速な復旧が実現できました。実際に使用したバッチオペレーションの設定は次の通りです。

設定項目 設定値
オペレーション レプリケート
レプリケーションステータス 失敗

2点目は、レプリケーション先のバケットポリシーにIAMロールIDベースの制限が設定されているケースです。この場合、IAMロールを再作成するとロールIDが変更されるため、追加の復旧作業が必要となります。

原因と対策

本件についてチームで振り返りを行い、原因分析と対策を実施しました。

CI/CDパイプラインの未整備

弊社は数年前から、とあるTerraformのSaaSを利用していましたが、途中で課金モデルがapply数課金からリソース数課金に変更になりました。この変更に対し、テスト・ステージング環境のリソース数が本番比で10倍あること、かつ変更頻度も低いという理由から、本番環境以外はPCローカルでplan/applyする方針としました。

つまり、手動での変更作業が増え、人的ミスが発生しやすい状態であり、環境によって反映方法が違うため開発体験も悪い状態でした。

現在は一部リソースを除きGitHub Actionsに移行しています。

PRテンプレートの未整備

従来は、リスクが高いと判断されたPRについて、レビュアーが手元でpullしてplanを実行することで品質を担保していました。しかし今回は、SecurityGroupのポリシー追加とbackendファイルの軽微な変更だったため、手元でのplanを省略して承認してしまいました。

暫定対応として、PRテンプレートにplan結果の貼り付けを必須とする運用ルールを導入しました。

恒久対応として、一部リソースを除いてGitHub Actionsへ移行し、plan結果が自動でPRコメントとして投稿される仕組みを構築しました。また、リソースの削除が発生する場合は自動でPRラベルが付与されるよう改善を図りました。

さらに最近では、AI(pr-agent)を活用したレビュー品質の向上にも取り組んでいます。

もしもを考える

今回は幸いにも早期に問題を解決できましたが、問題が長期化した場合のシナリオについても、振り返りの際に考えてみるべきだったと考えています。

例えば、EventBridgeやSNSにはリトライ機能が備わっていますが、IAMロールの削除に気付かず問題が長期化すると、これらのサービスでデータが失われる可能性があります。参考までに、EventBridgeやEventBridgeのリトライ仕様を掲載します。

障害パターン リトライ仕様(2024年時点)
EventBridge→SNS(SNSに連携ができない場合) • 24時間リトライし続ける(185回)
• リトライ間隔は指数バックオフ
• リトライ期間は変更できない
• CloudWatch Logsへのエラーログ出力不可(DLQには出力可能)
SNS→SQS(SQSに連携ができない場合) • 23日間リトライし続ける
• リトライ感覚は指数バックオフ
• リトライ期間は変更できない
• CloudWatch Logsへのエラーログ出力可
• 23日間経っても配信に成功しないイベントはDLQ行き

また、長期化は可用性に深刻な影響を及ぼす恐れがあります。

ECSでAWS Logsドライバを使用する場合、デフォルトではブロッキングモードが有効※になっています。IAMロールが削除され即座の復旧が難しい状況に備え、影響を最小限に抑えるためにノンブロッキングモードの採用を検討すべきです。
※2025年6月25日にノンブロッキングモードがデフォルトになりました
https://dev.classmethod.jp/articles/amazon-ecs-default-log-driver-mode-change-20250625/

このように、「もしもを考える」というアプローチは、インシデントを未然に防ぐことに大きく寄与してくれると考えています。

障害が起きている短い時間ではなく、期待通りに進んでいる残りの時間に焦点を当てることに大きなメリットがあることを示唆しています。物事がうまく機能している原因を学び、システムのその部分を強化できれば、インシデントを未然に防ぐことに大きな影響を与えるでしょう。
SREをはじめよう: 10章 失敗から学習する / うまくいった点を無視する(学習機会の損失)より

https://www.oreilly.co.jp/books/9784814400904/

まとめ

今回の問題は、インフラ管理における基本的なプロセスの不備と自動化の欠如によって引き起こされました。しかし、チームでの振り返りを通じて得られた改善策により、システムの強靭性を高める重要な転機となりました。

私たちのチームには昨年から新卒メンバーが加わっており、今後は開発者にもTerraformの利用機会を広げていきたいと考えています。スキルレベルに関わらず、誰もが安全にTerraformを扱える環境づくりに引き続き取り組んでまいります。


自戒の念を込めて待ち受けにしました

WealthNavi Engineering Blog

Discussion