漏えいした鍵は、最初に見つけた人のものになる
クラウドのアクセスキー、アプリケーションのシークレット、APIトークンは、人を介さずに使えるパスワードです。公開リポジトリ、ビルドログ、コンテナイメージ、盗まれたノートPCに載れば、見つけた人は誰でも自社のワークロードとして振る舞えます。データの一覧、マシンの起動、新しい利用者や鍵の作成、他のすべてを開く秘密情報の読み取りです。露出した鍵を探す自動スキャナーは常に動いています。
この再利用可能なクラウド鍵漏えいプレイブックには36の判断ポイントがあり、はい・いいえの処置、証拠、担当者を示します。新たな侵害の報道ではなく、SecOpsNomad独自の手順です。AWSアクセスキーとMicrosoft Entraアプリケーションの認証情報を想定していますが、同じ考え方は他の事業者やトークンにも当てはまります。鍵が端末から盗まれた場合はアカウント侵害プレイブックと端末の調査も、委託先から漏えいした場合は委託先侵害プレイブックも並行して実施します。
まず無効化、次に調査、削除は最後。 無効化した鍵は、重要なワークロードが止まった場合に戻せますが、削除した鍵は戻せません。また、鍵を無効にしても、新しい利用者、新しい鍵、稼働中のマシンなど、鍵ですでに始められたものは元に戻りません。鍵で取得された一時的な認証情報も、別の手順で無効にする必要があります。鍵を止めた後も調査を続けます。

全体図:露出 → 認証情報の封じ込め → 影響範囲 → 操作 → 永続化 → 被害 → 交換。初動を最初に行い、復旧は判定を経て進めます。図と同じ判断を直後の表で確認できます。
まずここから:最初の1時間
初めて対応する方は、この順番で進めてください。詳しい調査は、このあとの各段階で行います。最後の削除以外はすべて元に戻せる操作で、漏えいしたシークレットそのものは一度も使いません。
- 0〜5分:キーを試さない。 どこで見つけたか(URL、ファイル、コミット、メッセージ)、いつ、誰が報告したかを書き留めます。スクリーンショットはシークレット部分を隠して撮ります。シークレットをスキャナー、チャット、チケットに貼り付けないでください。
- 5〜10分:キーを特定する。
AKIAで始まるAWSのキーIDはIAMユーザーの長期キー、ASIAは一時キーです。自分の管理者セッションからaws sts get-access-key-info(どのアカウントか)とaws iam get-access-key-last-used(どのユーザーか、最後にいつ使われたか)を実行します。コマンドは段階0にあります。 - 10分:案件を作る。 インシデント責任者と、AWSアカウントまたはEntraテナントの管理者を決めます。UTCで時系列の記録を始めます。
- 10〜15分:1つだけ質問する。 「このキーが止まると何が壊れますか」。持ち主に5分だけ確認します。誰も分からなくても先へ進みます。キーの無効化はワンクリックで元に戻せます。
- 15分:キーを無効化する(Inactiveにする)。Entraのアプリケーションならシークレットを削除します。段階2を参照してください。
- 20分:そのキーで作られたセッションを止める。 段階2の「現時点より前に発行されたトークンを拒否する」ポリシーを付けます。キーを無効にしただけでは、発行済みの一時認証情報は止まりません。
- 25分:同じIDの他の入口を確認する。 2本目のアクセスキー、コンソールのパスワード、同じアプリの別のシークレットも封じ込めます。
- 30分:証拠を保存する。 片付けが始まる前に、キーが使われた全リージョンのCloudTrailイベント履歴(段階4)と、IAMのスナップショット(段階3)をダウンロードします。
- 40分:置き土産を探す。 保存したイベントから、新しいユーザー、アクセスキー、ロール、ポリシー変更を探します(段階5)。新しく作られたものは最優先です。
- 50分:請求を確認する。 Billing and Cost Management →「Cost Explorer」で日次表示にし、リージョン別に分けます。使っていないリージョンや見慣れないインスタンスタイプがあれば、誰かがあなたの費用で計算資源を使っています。
- 60分:最初の状況報告を送る。 このページ末尾のテンプレートを使い、次の報告時刻を決めます。
やってはいけないこと: 最初の1時間でキーを削除すること(履歴とのつながりが失われ、影響が分からないまま本番を壊すおそれがあります)。「修正」コミットを出して終わりにすること(履歴とフォークにはキーが残ります)。ログを読む前に「何も起きていない」と発表すること。
事前準備と判断ルール
平常時から、長期間有効な認証情報を一覧にしておきます。事業者、ID、所有者、利用するワークロード、保管場所、最終交換日です。監査ログがすべてのアカウントとリージョンを対象にしているか、機微なデータの保管先でデータアクセスのイベントが記録されるかを確認します。承認を待たずに本番の鍵を無効化できる担当者を事前に決めておきます。
- はい: 処置を行い、他の該当する確認もすべて実施します。
- いいえ: 回答を裏付ける証拠、範囲、時間帯を記録します。アラートなしだけでは不十分です。
- 不明: 未解決の作業として担当と再確認時刻を決め、調査中もリスクに応じて封じ込めます。
- 対象外: 理由と確認者を記録し、ログ不足の代わりに使いません。
案件ID、事業者と認証情報の識別子(秘密の値ではなく鍵ID)、所有するID、最初に分かっている露出時刻、UTC確認期間、回答・根拠、証拠保管先、処置・結果、実担当、再確認時刻を残します。秘密の値を、チケット、チャット、検索エンジン、オンラインの確認ツールに貼り付けないでください。
日本語の判断台帳をダウンロード(CSV)。空欄は非公開の案件記録用です。表計算ソフトへ追記する文字列は信頼できない入力として扱ってください。
担当: クラウド基盤担当は認証情報の無効化とセッションの制限、IAMは権限と永続化の確認、SOC/SIEMは操作の時系列、リポジトリ担当またはDevOpsは露出元の除去、アプリ担当は新しい認証情報へのワークロードの移行、DFIRは端末と証拠、FinOpsまたは経理は想定外の費用、法務/プライバシーは報告・通知の判断を担当します。責任者が再開と終結を承認します。
この手順で使う言葉
| 用語 | 意味 |
|---|---|
| アクセスキー | プログラムがIAMユーザーとしてAWSを呼び出すための値の組です。アクセスキーID(AKIA…、チケットに書いてよい)とシークレットアクセスキー(絶対に共有しない)からなります。 |
| IAMユーザー/IAMロール | ユーザーはアクセスキーを持てる長期のIDです。ロールはプログラムが短時間だけ「身につける」IDで、一時認証情報を受け取ります。 |
| 一時認証情報 | AWS STSが発行する短期のキー(ASIA…)とセッショントークンです。元のキーを無効にしても、有効期限(通常15分〜36時間)までは使えます。 |
| CloudTrail/イベント履歴 | AWSの操作記録です。イベント履歴では、直近90日の管理イベントを、リージョンごとに追加費用なしで見られます。 |
| 管理イベントとデータイベント | 管理イベントは設定操作(ユーザー作成、サーバー起動など)です。データイベントはデータの読み書き(S3からのファイル取得など)で、事前に有効にしていた場合だけ記録されます。 |
| リージョン | AWSの地理的な拠点です。攻撃者は、あなたが見ないであろう未使用のリージョンをよく使います。 |
| 影響範囲(ブラスト半径) | キーが届くすべての範囲です。権限、引き受けられるロール、読めるシークレットを含みます。 |
| 永続化 | 後で戻ってくるために攻撃者が作るもの、たとえば新しいユーザーやアクセスキーです。 |
| 隔離ポリシー | AWSCompromisedKeyQuarantineV3。キーの公開を検知したAWSが自動で付けることがあるポリシーです。一部の操作を制限しますが、インシデントを終わらせるものではありません。 |
| アプリ登録/クライアントシークレット | Microsoft Entra IDにおけるアプリケーションのIDと、そのパスワードです。プログラムはシークレットを使ってアプリとしてサインインします。 |
| シークレットスキャン/プッシュ保護 | コード内の秘密情報を見つけ、秘密情報を含むプッシュを止めるGitHubの機能です。 |
| 最小権限 | 認証情報に、仕事に必要な権限だけを与えることです。漏れたときの被害が小さくなります。 |
セキュリティ担当がいない場合の役割分担
表に出てくる担当は「役割」であり、肩書きではありません。小さな会社では1人が複数の役割を持つのが普通です。それでも「変更した人だけが、その効果を確認する」状態は避けてください。
| この手順での役割 | 小規模な会社での担当例 | 事前に用意しておくもの |
|---|---|---|
| インシデント責任者 | CTO、開発責任者、または経営者 | サービスを止める判断と、外部支援に費用を出す権限 |
| クラウド基盤担当/IAM | AWSの管理者、またはEntraのアプリケーション管理者の権限を持つ人 | MFAで守られた管理者アカウントと、漏えいに関係しない端末 |
| SOC/SIEM | 上と同じ管理者、または運用委託先(MSP) | CloudTrailの閲覧権限。SIEMがあればそのアクセス |
| リポジトリ所有者/DevOps | キーをコミットした開発者と、リポジトリ管理者 | リポジトリとCIの管理者権限 |
| アプリケーション担当 | キーを使っていたサービスを運用する開発者 | 設定変更をデプロイできること |
| FinOps/経理 | AWSの請求を払っている人 | 請求コンソールの閲覧権限 |
| 法務/個人情報 | 顧問弁護士、または個人情報の窓口担当 | 平易な言葉でまとめた、確認済みの事実 |
| 外部の支援 | AWSサポート、MSP、インシデント対応会社。国内ではJPCERT/CCがインシデント対応の依頼を受け付けています | アカウントID、案件の概要と時系列(シークレットは渡さない) |
画面の項目名は英語表示の名称で書いています。日本語表示では訳語が異なる場合があります。
0. 初動:認証情報と所有者を特定
- 鍵を使わずに、形式と見つかった場所から認証情報を特定します。事業者、鍵ID、所有するID、依存するワークロードです。
- 状態は、信頼できる管理者セッションから事業者のコンソールやAPIで確認します。自分のPCで秘密情報を試してはいけません。
- 案件を起票して基盤担当とIDの所有者を決め、最初に分かっている露出時刻を記録します。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K01. 露出した値は、失効済み・テスト用・ダミーではなく、有効な認証情報か? | インシデントとして扱い、直ちに封じ込める(段階2)。 | 証拠を記録し、露出中に一時でも有効だったかを確認する。 | 認証情報の状態、作成日と最終利用日、露出場所。 | クラウド基盤+SOC |
| K02. 認証情報の種類、事業者、所有するIDが特定できているか? | 種類に応じた手順を適用し、所有者に連絡する。 | 先に台帳、事業者のコンソール、見つかった場所から特定する。 | 鍵ID、IDのARNまたはアプリケーションID、所有者、依存するワークロード。 | クラウド基盤+IAM |
| K03. 本番、管理者、データへのアクセス権を持つか? | 深刻度を引き上げ、直ちに封じ込める。 | それでも速やかに封じ込める。低権限の鍵でも調査や連鎖に使える。 | 付与されたポリシー、ロール、届くデータの保管先。 | IAM+責任者 |
| K04. 事業者やスキャナーがすでに対応したか(隔離用ポリシーや通知など)? | その時刻を露出の遅くとも時点として記録し、封じ込めを続ける。 | 誰も見ていないと考えず、収集されたものとして進める。 | 事業者の通知、サポートケース、スキャナーの通知、ポリシーの付与。 | クラウド基盤+SOC |
AWSは、公開された場所で露出したアクセスキーを検知すると、AWSCompromisedKeyQuarantineマネージドポリシーのいずれかの版をIAM利用者に付与し、サポートケースを作成する場合があります。このポリシーは、利用者や鍵の作成、インスタンスや関数の起動など危険度の高い一部の操作を拒否しますが、すべての操作を止めるわけではありません。封じ込めではなく、時間稼ぎとして扱ってください。AWSマネージドポリシー、Unit 42の分析。
具体的な操作手順
漏えいしたキーではなく、自分の管理者アカウントでAWSコンソールにサインインします。漏えいに関係していない端末を使います。
コンソール: IAM →「Users」→ ユーザーを検索 →「Security credentials」タブ →「Access keys」。状態、作成日、「Last used」の内容を記録します。
CLI(AWS CloudShellまたは管理用端末): 下のキーIDとアカウント番号はAWSのドキュメント用の例です。実際の値に置き換えてください。
# Which AWS account owns this key ID? (uses your credentials, not the leaked secret) aws sts get-access-key-info --access-key-id AKIAIOSFODNN7EXAMPLE # Run in that account: which IAM user owns it, and when, where and for which service was it last used? aws iam get-access-key-last-used --access-key-id AKIAIOSFODNN7EXAMPLE # Every key of that user and its status aws iam list-access-keys --user-name example-userEntraのアプリのシークレット: Entra管理センター →「Entra ID」→「App registrations」→「All applications」→ アプリを開く →「Certificates & secrets」→「Client secrets」。「Value」列には各シークレットの先頭数文字だけが表示されます。漏えいした値と照合してどれかを特定し、Secret IDを記録します。
案件記録に、提供元、アカウントIDまたはテナントID、キーIDまたはSecret ID、所有するID、最終使用時刻、持ち主が挙げた依存ワークロードを書きます。
確認: K01〜K04に、推測ではなく証拠で答えられること。
1. 露出:鍵がどこに、どれだけの期間あったか
- 最初の露出を特定します。鍵を含むコミット、アップロード、ログ行、メッセージとその時刻です。
- すべての写しを一覧にします。フォーク、クローン、キャッシュ、ビルド成果物、コンテナのレイヤー、バックアップ、チケット、チャットです。
- 鍵が端末から漏えいした場合は、端末を侵害されたものとして扱います。端末上の他の秘密情報も露出しています。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K05. 鍵は公開リポジトリ、パッケージ、イメージ、貼り付けサイトなど公開された場所にあったか? | 収集されたものと考え、露出時刻を期間の開始にする。 | 非公開の場所に誰がいつからアクセスできたかを特定する。 | リポジトリの公開設定、コミット履歴、パッケージ・イメージのレジストリ。 | リポジトリ担当/DevOps+SOC |
| K06. 最初の露出時刻が分かっているか? | 余裕を引いた時刻を、すべての検索の開始にする。 | 鍵の作成日または最終交換日を開始にする。 | コミットの時刻、アップロードのログ、鍵の作成日。 | SOC+リポジトリ担当/DevOps |
| K07. 鍵はフォーク、クローン、ビルドログ、成果物、チャットにもあるか? | 管理できる範囲は除去するが、対策は削除ではなく交換に頼る。 | 検索した場所を記録する。 | 秘密情報の検査結果、成果物の保管庫、ログの検索。 | リポジトリ担当/DevOps |
| K08. 鍵は端末から盗まれたか(情報窃取型マルウェアなど)? | 端末を隔離して調査し、端末にあったすべての秘密情報を交換する。 | 端末が漏えい元でない理由を記録する。 | EDRのアラート、プロセスとファイルのイベント、利用者の申告。 | EDR+DFIR |
具体的な操作手順
キーが最初に入ったコミットを探します(リポジトリのクローン内で実行。全ブランチを検索します)。
git log -S 'AKIAIOSFODNN7EXAMPLE' --all --date=iso-strict --format='%H %ad %an %s'どの程度公開されていたかを確認します。 GitHubのリポジトリページで、Publicかどうかとフォーク数が分かります。公開リポジトリは数分で攻撃者に走査されます。キーはコピーされたものと考えてください。
ほかの場所も探します: CIのログ(最近のワークフロー実行を開き、ログ内をキーIDで検索)、コンテナイメージ(
docker history --no-trunc <image>でビルド手順と環境変数が見えます)、パッケージレジストリ、Wiki、チケット、チャット。検索はシークレットではなくキーIDで行います。キーがPCやサーバーから盗まれた場合(インフォスティーラー型マルウェアなど)は、その端末と持ち主についてアカウント侵害プレイブックも開始します。
表を作ります:場所、最初に確認された時刻(UTC)、誰が見られるか、誰が片付けるか。最も早い時刻が調査期間の開始です。
確認: すべてのコピーに担当者がいて、調査期間が「気づいた時刻」ではなく最初の露出から始まっていること。
2. 認証情報とセッションの封じ込め
- 認証情報を無効にします。AWSのアクセスキーは非アクティブにし、Entraアプリケーションのシークレットは削除します。鍵そのものの削除は、調査とワークロードの移行が終わってから行います。
- その鍵で作られた一時的な認証情報とセッションを、別の手順として無効にします。AWSは、これを鍵の無効化とは別に扱っています。
- 同じIDの他の認証情報も封じ込めます。2つ目の鍵、コンソールのパスワード、同じアプリケーションの他のシークレットです。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K09. 許容できない停止を起こさずに、認証情報を今すぐ無効にできるか? | 無効にして時刻を記録する。戻すのは承認された例外の場合だけ。 | 拒否ポリシーやネットワーク条件で直ちに制限し、数時間以内に交換する。 | 鍵の状態変更、ワークロードの稼働状況、例外の承認。 | クラウド基盤+アプリ担当 |
| K10. その鍵で一時的な認証情報(セッショントークン、フェデレーション、ロールの引き受け)が作られた可能性があるか? | 発行時刻による無効化やロールのセッション取り消しを行い、確認する。 | そのような呼び出しがなかった監査上の証拠を記録する。 | GetSessionToken、GetFederationToken、AssumeRoleのイベント。 | クラウド基盤+SOC |
| K11. ルート利用者または組織全体の認証情報か? | ルートのアクセスキーを削除し、ルートのサインインを保護して、アカウント所有者と事業者のサポートに連絡する。 | IDごとの手順で進める。 | 認証情報レポート、ルートの鍵の状態、組織の構成。 | クラウド基盤+責任者 |
| K12. 同じIDの他の認証情報が有効になっているか? | それらも封じ込め、ハンティングの対象に含める。 | 確認した認証情報の一覧を記録する。 | IAM利用者の認証情報、アプリケーションのシークレットと証明書。 | IAM |
AWSは、露出した認証情報を削除する前に無効化することを勧めています。アプリケーションが止まった場合に、無効化した認証情報は戻せるためです。AWSによれば、IAM利用者の鍵を交換しても、その鍵ですでに取得された一時的な認証情報は無効になりません。これらの有効期間は15分から36時間です。権限は要求のたびに評価されるため、可能なら利用者を削除する、指定時刻より前に発行されたトークンを拒否するポリシーを付与する、ロールの場合はアクティブなセッションの取り消しを使う、のいずれかで止めます。AWS:アクセスキーを露出させた場合、AWS:一時的な認証情報の権限の無効化、AWS:ロールのセッションの取り消し。
具体的な操作手順
AWSのキーを無効化します。 コンソール:IAM →「Users」→ ユーザー →「Security credentials」→「Access keys」→「Actions」→「Deactivate」。またはCLIで:
aws iam update-access-key --user-name example-user --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive現時点より前に発行された一時認証情報を止めます。 次のファイルを保存し、時刻を封じ込めた時点(UTC)に書き換えます。
{ "Version": "2012-10-17", "Statement": [{ "Sid": "DenyCredentialsIssuedBeforeContainment", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "DateLessThan": { "aws:TokenIssueTime": "2026-10-06T09:30:00Z" } } }] }続けて、ユーザーにインラインポリシーとして付けます。
aws iam put-user-policy --user-name example-user --policy-name deny-sessions-before-containment --policy-document file://deny-sessions-before-containment.jsonキーで引き受けられたロール: IAM →「Roles」→ ロール →「Revoke sessions」タブ →「Revoke active sessions」。現時点より前に発行された、そのロールのすべてのセッションが拒否されます。自社ワークロードのセッションも含まれ、新しい認証情報の取得が必要になるため、サービス担当に伝え、重要なサービスは実行後に動作を確認します。
同じユーザーの別の入口: 2本目のキーがあれば無効化し、パスワードがあればコンソールアクセスを外します(IAM → ユーザー →「Security credentials」→「Console sign-in」→「Manage」で無効化)。CLIでは
aws iam delete-login-profile --user-name example-userです。Entraのアプリのシークレット: 「Certificates & secrets」で削除するか、Azure CLIで削除します。
az ad app credential list --id <application-client-id> az ad app credential delete --id <application-client-id> --key-id <secret-id>
確認: aws iam list-access-keysでキーがInactiveと表示される。ユーザーの「Permissions」タブにインラインポリシーがある。この時刻以降にそのキーで署名された新しいCloudTrailイベントは、雑音ではなく警報として扱う。AWS:一時認証情報の取り消し
3. 影響範囲:鍵で何ができたか
- 実際の権限を算出します。IDのポリシー、グループ、権限の境界、組織のガードレール、セッションポリシーです。
- 信頼関係をたどります。他のアカウントを含め引き受けられるロールと、そのIDを直接指定するリソースポリシーです。
- 読み取れた秘密情報、鍵、パラメーターを一覧にします。それぞれが別のシステムを開く可能性があります。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K13. ポリシーがIAM全体や全サービスなど、広い操作を許可しているか? | 深刻度を高く扱い、永続化のハンティングを優先する(段階5)。 | 境界とガードレールを含めた実際の権限を記録する。 | ポリシーの内容、アクセス分析、境界とガードレールの設定。 | IAM |
| K14. 他のアカウントを含め、そのIDが他のロールを引き受けられるか? | それらのロールとアカウントを範囲に加え、そのログもハンティングする。 | 確認した信頼ポリシーを記録する。 | ロールの信頼ポリシー、アカウント間の関係。 | IAM+クラウド基盤 |
| K15. ストレージ、鍵、キューのリソースポリシーが、そのIDに直接アクセスを許可しているか? | それらのリソースを範囲に加える。 | 確認したリソースの種類を記録する。 | そのIDを指定するバケット、鍵、キューのポリシー。 | IAM+データ担当 |
| K16. 他のシステムを開く秘密情報、鍵、パラメーターを読み取れたか? | 読み取れたものすべての交換を計画する(段階7)。 | 秘密情報に届かなかった理由を記録する。 | シークレット管理とパラメーターストアの権限。 | クラウド基盤+アプリ担当 |
具体的な操作手順
最初にIAMのスナップショットを保存します。 後で比較でき、キーが何に届いたかを示せます。
aws iam get-account-authorization-details --output json > iam-snapshot-$(date -u +%Y%m%dT%H%MZ).jsonユーザーの権限を一覧にします。 コンソールではIAM → ユーザー →「Permissions」タブ(ポリシー、グループ、アクセス許可の境界)。CLIでは:
aws iam list-groups-for-user --user-name example-user aws iam list-attached-user-policies --user-name example-user aws iam list-user-policies --user-name example-user危険な操作をポリシーシミュレーターで試します。 「allowed」はキーでその操作ができたことを意味します。
aws iam simulate-principal-policy \ --policy-source-arn arn:aws:iam::111122223333:user/example-user \ --action-names iam:CreateUser iam:CreateAccessKey sts:AssumeRole s3:GetObject secretsmanager:GetSecretValue ssm:GetParameter ec2:RunInstancesこのユーザーを信頼しているものを探します。 スナップショットをユーザーのARNで検索します。ロールの信頼ポリシーや、バケット・鍵のポリシーに一致があれば、それも入口です。
grep -n 'user/example-user' iam-snapshot-*.jsonシミュレーターの結果は目安であり、証明ではありません。他アカウントのポリシーなど、見えない制御があります。つながっている各アカウントの管理者にも確認を依頼します。
確認: 危険な操作ごとの許可・拒否、引き受けられるロール、読めたシークレットを文書にしていること(K13〜K16)。
4. 操作:鍵が実際に何をしたか
- 期間の開始から封じ込め後まで、すべてのアカウントとリージョンで、その鍵とIDが署名した監査イベントをすべて取得します。
- 自社のワークロードの通常の呼び出しと、新しい接続元、ユーザーエージェント、操作を分けます。
- データアクセスの記録がない場合のデータ読み取りなど、ログでは分からないことを記録します。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K17. 期間中に、鍵またはそのIDが未知の接続元やツールから呼び出しを行ったか? | 不正利用の確認として扱い、時系列を作る。 | 期間、アカウント、リージョン、ログの種類を記録する。 | 接続元アドレス、ユーザーエージェント、操作を含む監査イベント。 | SOC/SIEM |
| K18. 身元の確認、一覧の取得、アクセス拒否のエラーの集中があるか? | 攻撃者が権限を調べていると考え、成功した呼び出しを確認する。 | 検索したエラーと列挙の型を記録する。 | GetCallerIdentity、List・Describe系の呼び出し、エラーコード。 | SOC/SIEM |
| K19. 鍵が届く保管先で、データアクセスのイベントが記録されているか? | 読み取り、複製、ダウンロードを検索する。 | 死角として記録し、可能ならストレージのアクセスログなど他の情報源を使う。 | データイベントの設定、ストレージのアクセスログ。 | クラウド基盤+SOC |
| K20. 普段使わないリージョンやアカウントで操作があったか? | それらのリージョンとアカウントで新しいリソースを確認する。 | 検索したリージョンの範囲を記録する。 | イベントごとのリージョン、リソースの一覧。 | クラウド基盤 |
具体的な操作手順
コンソール: CloudTrail →「Event history」→ 検索属性「AWS access key」→ キーIDを貼り付け → 調査期間の開始から時間範囲を指定 →「Download events」(CSVまたはJSON)。イベント履歴は1リージョンずつしか表示されないため、リージョンごとに繰り返します。IAMなどグローバルサービスのイベントは米国東部(バージニア北部)に記録されます。
CLIで全リージョンを一度に取得します(開始時刻は調査期間に合わせます)。
KEY=AKIAIOSFODNN7EXAMPLE for r in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do aws cloudtrail lookup-events --region "$r" \ --lookup-attributes AttributeKey=AccessKeyId,AttributeValue="$KEY" \ --start-time 2026-09-01T00:00:00Z --output json > "events-$KEY-$r.json" doneファイルを1本の時系列にまとめます(時刻、操作、サービス、送信元IP、ユーザーエージェント)。
jq -r '.Events[] | (.CloudTrailEvent | fromjson) as $e | [.EventTime, .EventName, .EventSource, $e.sourceIPAddress, $e.userAgent] | @tsv' events-*.json | sort > timeline.tsv送信元ごとに「自社」か「不明」かを付けます。 自社の拠点、CIランナー、サーバーのアドレスとツールは「自社」です。不明な送信元からの
GetCallerIdentityや一覧取得は、攻撃者がキーで何ができるかを確かめている動きです。一時認証情報を追います。 時系列に
GetSessionToken、GetFederationToken、AssumeRoleがあれば、応答に新しいASIA…のキーIDが含まれています。そのキーIDも同じ方法で検索します。限界を知っておきます。 イベント履歴に残るのは管理イベントの90日分だけです。S3オブジェクトの読み取りなどのデータアクセスは、証跡でデータイベントを記録していた場合にだけ残ります。その場合は下のハンティングクエリで、証跡の保存先、Athena、SIEMを検索します。AWS:イベント履歴
確認: 不明な送信元がすべて説明済みかエスカレーション済みの時系列と、ログで確認できなかった事項のメモがあること(K17〜K20)。
5. 永続化:攻撃者が残したものを探す
- 最初に、新しいIDと認証情報を探します。利用者、アクセスキー、ログインプロファイル、アプリケーションのシークレット、IDプロバイダーです。
- 信頼関係と権限の変更を確認します。ロールの信頼ポリシー、付与されたポリシー、ポリシーの新しい版です。
- コンピュートとログを確認します。新しいインスタンス、関数、キーペア、開放されたネットワークのルール、監査ログや脅威検知の設定変更です。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K21. 利用者、アクセスキー、ログインプロファイル、アプリケーションのシークレットが作成・変更されたか? | イベントを保全してから削除し、新しいIDもハンティングの対象にする。 | 検索したイベントの種類とアカウントを記録する。 | CreateUser、CreateAccessKey、CreateLoginProfile、認証情報のイベント。 | IAM+SOC |
| K22. ロール、信頼ポリシー、権限、IDプロバイダーが変更されたか? | 正常な版に戻し、他に誰が引き受けられるようになったかを確認する。 | 確認したポリシーの履歴を記録する。 | ポリシーの版、信頼ポリシーの変更、IDプロバイダーのイベント。 | IAM |
| K23. インスタンス、関数、キーペア、開放されたネットワークのルールが作られたか? | スナップショットなどの証拠を保全してから削除する。 | 比較したリソースの一覧を記録する。 | RunInstances、CreateFunction、CreateKeyPair、セキュリティグループのイベント。 | クラウド基盤+DFIR |
| K24. 監査ログや脅威検知が停止、変更、削除されたか? | 元に戻し、時系列の空白は不明な活動として扱う。 | 確認したログ設定の履歴を記録する。 | StopLogging、証跡とイベントセレクターの変更、検知機能のイベント。 | クラウド基盤+SOC |
具体的な操作手順
保存したイベントから、典型的な置き土産を探します。
jq -r '.Events[] | select(.EventName | test("^(Create(User|AccessKey|LoginProfile|Role|PolicyVersion|SAMLProvider|OpenIDConnectProvider|KeyPair)|UpdateLoginProfile|UpdateAssumeRolePolicy|(Attach|Put)(User|Role|Group)Policy|RunInstances|CreateFunction.*|ImportKeyPair|AuthorizeSecurityGroupIngress|StopLogging|DeleteTrail|UpdateTrail|PutEventSelectors|DeleteDetector)$")) | [.EventTime, .EventName, .Username] | @tsv' events-*.json | sortキーのイベントだけでなく、アカウント全体を見ます。 IAMの認証情報レポートをダウンロードし、調査期間中に作られたユーザーやキーを探します。
aws iam generate-credential-report aws iam get-credential-report --query Content --output text | base64 --decode > credential-report.csv自社で作っていないものは: 詳細(スクリーンショット、
aws iam get-user、aws iam get-role、ポリシーのJSON)を案件に保存してから無効化します。新しいキーは無効化、新しいコンソールパスワードは削除、新しいポリシーは外し、信頼ポリシーはIAMスナップショットから元に戻します。計算資源とログを確認します。 全リージョンの新しいインスタンス、関数、キーペア、
0.0.0.0/0に開かれたセキュリティグループ。CloudTrailとGuardDutyが有効なままか(CloudTrail →「Trails」で状態が「Logging」、GuardDuty →「Settings」)。
確認: 調査期間中の作成・付与・変更のイベントがすべて、自社の作業として説明済みか、元に戻されており、ログ記録が有効だと確認できていること(K21〜K24)。
6. 被害:データ、費用、損害
- データへのアクセスを評価します。読み取り、複製、共有されたスナップショットやイメージ、自社が所有しないアカウントへの出力です。
- 費用を評価します。採掘やスパム用の新しいリソース、大きなインスタンス、上限の引き上げ申請です。請求は被害の後に届きます。
- 完全性を評価します。削除、上書き、攻撃者の鍵による暗号化、鍵の削除予約です。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K25. スナップショットやイメージなどを通じて、データが読み取り、複製、共有されたか? | 法務/プライバシーとデータ担当に連絡し、データを特定して証拠を保全する。 | ログの死角を踏まえ、証拠がないこととアクセスがないことを区別する。 | データイベント、スナップショット・イメージの共有、出力先。 | DFIR+法務/プライバシー |
| K26. 採掘、スパムなど費用のかかる用途にリソースが悪用されたか? | 停止して費用を算出し、請求について事業者のサポートに連絡する。 | 確認した費用とリソースを記録する。 | 費用のレポート、新しいリソース、上限の申請。 | FinOps/経理+クラウド基盤 |
| K27. 鍵で秘密情報やパラメーターが読み取られたか? | 読み取られた秘密情報をすべて交換し、それが守るシステムを調査する。 | 確認した秘密情報へのアクセスのイベントを記録する。 | GetSecretValueとパラメーター読み取りのイベント。 | クラウド基盤+アプリ担当 |
| K28. 何かが削除、暗号化、上書きされた、または身代金を要求されたか? | 該当する場合はランサムウェア対応プレイブックを実施し、信頼できるバックアップから復元する。 | 機密性と費用の確認を続ける。 | 削除・上書きのイベント、鍵の削除予約、脅迫文。 | 責任者+クラウド基盤 |
具体的な操作手順
- データ: 時系列から
ModifySnapshotAttribute、ModifyImageAttribute、CopySnapshot、PutBucketPolicy、PutBucketAcl、DeletePublicAccessBlockを探します。データの共有や公開につながる操作です。S3のデータイベントを記録していれば、証跡の保存先かSIEMでキーによるGetObjectを検索します。記録していなければ、読み取りを否定できないと記録します。 - 費用: Billing and Cost Management →「Cost Explorer」→ 粒度「Daily」→ リージョン別、続いてサービス別・インスタンスタイプ別に分けます。GPUインスタンスや使ったことのないリージョンは、暗号資産のマイニングによくある兆候です。
- 完全性: 削除操作と、KMSの
ScheduleKeyDeletionを探します。削除が予約されたKMSキーは待機期間中なら取り消せます:aws kms cancel-key-deletion --key-id <key-id>。 - AWSに伝えます: サポートケース(下のテンプレート)で不正な活動を報告します。それによる請求についても相談できますが、調整はAWSの判断なので、誰にも返金を約束しないでください。AWS:アカウント内の不正な活動
確認: 影響の種類(データ、費用、完全性、シークレット)ごとに、「確認済み」「可能性あり(理由)」「検索したログでは確認されず」のいずれかを1行で記録していること(K25〜K28)。
7. 交換:鍵を置き換え、露出元を片付ける
- 最小権限で代わりの認証情報を発行します。可能ならロールやフェデレーションによる短期の認証情報に移します。
- 依存するすべてのワークロードを新しい認証情報へ移し、動作を確認してから古い鍵を削除します。
- 露出元とその履歴から秘密情報を除去します。すでに取得された写しは取り戻せないことを前提にします。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K29. 代わりの認証情報は最小権限で、可能な範囲で短期間のものか? | 新しい設計と担当を記録する。 | 範囲を絞った認証情報を今すぐ発行し、短期のアクセスへの移行を計画する。 | 新しいポリシー、認証情報の種類、交換の予定。 | クラウド基盤+IAM |
| K30. すべてのワークロードが新しい認証情報に移り、古いものを削除したか? | 利用がないことを確認してから、削除を記録する。 | 残るワークロードを追跡し、古い鍵は無効のままにする。 | ワークロードの一覧、最終利用の情報、削除の記録。 | アプリ担当+クラウド基盤 |
| K31. 露出元、その履歴、ビルドの成果物から秘密情報を除去したか? | 除去を記録する。管理外の写しには交換で対処する。 | 担当を決めて除去の日程を組む。 | コミット、履歴の書き換えの記録、成果物の削除。 | リポジトリ担当/DevOps |
| K32. 顧客、取引先、規制当局への連絡が必要か? | 法務/プライバシーの判断に従い、確認できた範囲を添えて連絡する。 | 判断根拠を記録し、後でデータアクセスが見つかれば見直す。 | 法的評価、データの範囲、連絡の記録。 | 法務/プライバシー |
具体的な操作手順
できればキーそのものをなくします。 ワークロードをロールに移します。EC2のインスタンスプロファイル、ECSのタスクロール、Lambdaの実行ロール、GitHub ActionsならAWSへのOpenID Connect連携です。
どうしてもキーが必要なら、 最小権限で新しいキーを作り、シークレットはコードやチャットではなく、直接シークレット管理の仕組みに入れます。IAMユーザーが持てるキーは2本までです。必要なら使っていない方を先に削除します。
aws iam create-access-key --user-name example-userデプロイしてから確認します。 新しい認証情報でサービスが動き、
get-access-key-last-usedで新しいキーが使われていることを確かめます。ここで初めて古いキーを削除します(元に戻せない手順です)。
aws iam delete-access-key --user-name example-user --access-key-id AKIAIOSFODNN7EXAMPLEキーの交換後に出どころを片付けます。 ファイルや行を削除し、共有リポジトリならGitHubの機密データ削除ガイドに従って履歴を書き換えます。既存のフォークやクローンには届かないため、先にキーを交換するのです。AWS:アクセスキーの更新
確認: 古いキーが存在しない。すべてのワークロードが新しい認証情報かロールで動いている。自社で管理するファイルとビルド成果物からシークレットが消えている(K29〜K31)。
8. 復旧:次の漏えいを無害にする
- リポジトリで秘密情報の検査とプッシュ時の保護を有効にし、ビルドログとイメージも検査します。
- 可能な限り、長期間有効な鍵を、ロール、マネージドID、CIパイプラインのフェデレーションに置き換えます。
- 新しい場所からの鍵の利用、事業者の隔離通知、永続化の操作を通知するようにし、残るリスクを受け入れたうえで終結します。

独自の判断図。各分岐は独立して確認し、不明は未解決として管理します。
| 判断 | はい | いいえ | 証拠・不明時の確認先 | 主担当 |
|---|---|---|---|---|
| K33. リポジトリで秘密情報の検査とプッシュ時の保護が有効か? | 対象範囲と、通知を処理する担当を記録する。 | 公開リポジトリと危険度の高いリポジトリから有効にする。 | リポジトリの設定、通知の経路、検査結果。 | リポジトリ担当/DevOps |
| K34. 長期間有効な鍵を、ロール、マネージドID、フェデレーションに置き換えたか? | 残るものとその理由を記録する。 | 担当と期日を決めて置き換えを計画する。 | 認証情報の台帳、フェデレーションの設定、残る鍵。 | クラウド基盤+IAM |
| K35. 新しい場所からの鍵の利用、隔離の通知、永続化の操作を通知できるか? | ルール、担当、対応の目標を記録する。 | 終結の前に追加する。 | アラートのルール、試験結果、通知の経路。 | SOC/SIEM+クラウド基盤 |
| K36. 残る不確実性を明示的に受け入れたうえで、責任者が終結できるか? | 終結、費用とデータに関する判断、改善の期限を記録する。 | 未解決の分岐ごとに担当を付け、案件を継続する。 | 最終時系列、範囲、費用、連絡、承認。 | 責任者+法務/プライバシー |
具体的な操作手順
- GitHub: リポジトリの「Settings」→「Advanced Security」→「Secret Protection」を有効化し、続けて「Push protection」を有効化します。組織のオーナーは全リポジトリに一括で設定できます。GitHub:プッシュ保護の有効化
- 長期キーを減らします。 IAMの認証情報レポート(段階5)で一覧にし、それぞれロールか連携への移行計画を立てます。90日を超えたキーには、持ち主と理由が必要です。
- 今回の兆候にアラートを設定します。
CreateUser、CreateAccessKey、CreateLoginProfileのEventBridgeルールかSIEMアラートを作り、GuardDutyを有効にします。AWS Healthの通知や、認証情報の露出に関するAWSからのメールは、個人ではなく監視されている共有メールボックスに届くようにします。 - 短い振り返りをします。 キーがコードに入った理由、気づくまでの時間、足りなかったもの(データイベント、担当者一覧、アラート)、それぞれを誰がいつまでに直すか。
確認: ダミーのAWSキーを含むテストプッシュが止められ、テストのCreateAccessKeyで誰かが見るアラートが上がること(K33〜K35)。
ハンティング:鍵に限定したKQLとSplunk
実際のIOCは掲載していません。 案件記録にある、露出した鍵ID、所有するIDのARNまたはアプリケーションID、露出の可能性がある最初の時刻を使います。4例とも読み取り専用で、文書・スキーマを照合したものです。実環境では実行していません。
KQLの対象は、AWS CloudTrailコネクター(AWSCloudTrail)とMicrosoft Entra IDのログを接続したMicrosoft Sentinel/Azure Monitor Log Analyticsです。鍵が届き得るすべてのAWSアカウントとリージョンでテーブルに取り込まれていること、保持期間が対象期間を含むことを確認してください。各例の表示上限は500件です。
1. 鍵とその利用者が行ったすべての操作: 露出したUserIdentityAccessKeyId、または所有する利用者のUserIdentityArnでAWSCloudTrailを絞り込みます。2つ目の条件が重要です。GetSessionTokenで得た一時的な認証情報は、利用者のARNを保ったまま新しい鍵IDで要求に署名します。AssumeRoleの後の操作は、ロールのセッションARNで記録されるため、その呼び出しのRequestParametersとResponseElementsから追跡します。
2. 永続化、権限、隠蔽: 攻撃者が居座る、または隠れるための操作を抽出します。新しい利用者、鍵、ログインプロファイル、ポリシー、ロールと信頼関係の変更、IDプロバイダー、コンピュートとキーペア、秘密情報の読み取り、ログ設定の変更です。Lambda関数の作成はイベント名に版の接尾辞が付いて記録されるため、startswithを使います。一覧の操作があるだけでは不正ではありません。変更記録と照合してください。
3. 露出したEntraアプリケーションの認証情報によるサインイン: AADServicePrincipalSignInLogsには、使われたシークレットや証明書のServicePrincipalCredentialKeyIdが記録されます。鍵IDはアプリケーションの「証明書とシークレット」の画面から取得します。比較のため、同じアプリケーションの他の認証情報によるサインインも含めています。
4. Splunkで鍵とその利用者が行ったすべての操作: Splunk Add-on for AWSのsourcetype aws:cloudtrailで、JSONの項目userIdentity.accessKeyId、userIdentity.arn、eventSource、eventName、sourceIPAddress、errorCodeを使います。indexと検索期間を露出の期間に合わせてください。
KQL:鍵とそのIAM利用者が行ったすべての操作
// Microsoft Sentinel / Log Analytics. Read-only; not live-tested.
// CloudTrail events signed by the exposed key, or by its IAM user
// (temporary credentials from GetSessionToken keep the user's ARN).
let ExposedKeyId = "REPLACE_WITH_ACCESS_KEY_ID";
let KeyOwnerArn = "REPLACE_WITH_IAM_USER_ARN";
let WindowStart = datetime(2026-01-01T00:00:00Z); // REPLACE: first possible exposure, UTC
AWSCloudTrail
| where TimeGenerated between (WindowStart .. now())
| where UserIdentityAccessKeyId == ExposedKeyId or UserIdentityArn =~ KeyOwnerArn
| project TimeGenerated, UserIdentityAccessKeyId, UserIdentityType, UserIdentityArn,
EventSource, EventName, ReadOnly, AWSRegion, SourceIpAddress, UserAgent,
ErrorCode, RecipientAccountId
| order by TimeGenerated asc
| take 500
KQL:永続化、権限、隠蔽の操作
cloud-key-persistence.kqlをダウンロード
// Microsoft Sentinel / Log Analytics. Read-only; not live-tested.
// Actions an attacker uses to stay, escalate or hide, by the key owner's identity.
let KeyOwnerArn = "REPLACE_WITH_IAM_USER_ARN";
let WindowStart = datetime(2026-01-01T00:00:00Z); // REPLACE: first possible exposure, UTC
let Watched = dynamic(["CreateUser", "CreateAccessKey", "CreateLoginProfile",
"UpdateLoginProfile", "AttachUserPolicy", "PutUserPolicy", "AddUserToGroup",
"CreateRole", "UpdateAssumeRolePolicy", "AttachRolePolicy", "PutRolePolicy",
"CreatePolicyVersion", "CreateOpenIDConnectProvider", "CreateSAMLProvider",
"GetSessionToken", "GetFederationToken", "AssumeRole", "RunInstances",
"CreateKeyPair", "ImportKeyPair", "AuthorizeSecurityGroupIngress",
"PutBucketPolicy", "GetSecretValue", "StopLogging", "DeleteTrail", "UpdateTrail",
"PutEventSelectors", "DeleteDetector", "LeaveOrganization"]);
AWSCloudTrail
| where TimeGenerated between (WindowStart .. now())
| where UserIdentityArn =~ KeyOwnerArn
| where EventName in (Watched) or EventName startswith "CreateFunction"
| project TimeGenerated, EventSource, EventName, ErrorCode, AWSRegion,
SourceIpAddress, UserIdentityAccessKeyId, RequestParameters, ResponseElements
| order by TimeGenerated asc
| take 500
KQL:露出したEntraアプリケーションの認証情報によるサインイン
cloud-key-entra-app-signins.kqlをダウンロード
// Microsoft Sentinel / Log Analytics. Read-only; not live-tested.
// Service principal sign-ins for one application, flagging the exposed credential.
let TargetAppId = "REPLACE_WITH_APPLICATION_CLIENT_ID";
let ExposedCredentialKeyId = "REPLACE_WITH_SECRET_OR_CERTIFICATE_KEY_ID";
let WindowStart = datetime(2026-01-01T00:00:00Z); // REPLACE: first possible exposure, UTC
AADServicePrincipalSignInLogs
| where TimeGenerated between (WindowStart .. now())
| where AppId =~ TargetAppId
| extend UsedExposedCredential = ServicePrincipalCredentialKeyId =~ ExposedCredentialKeyId
| project TimeGenerated, ServicePrincipalName, AppId, ServicePrincipalCredentialKeyId,
UsedExposedCredential, ClientCredentialType, IPAddress, ResourceDisplayName,
ResultType
| order by TimeGenerated asc
| take 500
Splunk:鍵とそのIAM利用者が行ったすべての操作
index="REPLACE_WITH_AWS_INDEX" sourcetype="aws:cloudtrail" earliest=-30d latest=now (userIdentity.accessKeyId="REPLACE_WITH_ACCESS_KEY_ID" OR userIdentity.arn="REPLACE_WITH_IAM_USER_ARN")
| table _time userIdentity.accessKeyId userIdentity.type userIdentity.arn eventSource eventName readOnly awsRegion sourceIPAddress userAgent errorCode recipientAccountId
| sort 0 _time
| head 500
コピーして使えるテンプレート
[角かっこ]の部分をすべて置き換えてください。シークレット、パスワード、トークンは決して書かないでください(キーIDは問題ありません)。社外に出す文面は、法務または個人情報の担当者が確認します。
社内向け状況報告
開発部門と経営層向けに、決めた報告時刻ごとに使います。
件名:【インシデント 案件番号】クラウドのキー露出 第[番号]報([時刻 UTC]時点)
状況:[封じ込め済み/調査中/復旧中]
概要:[ユーザーまたはアプリ名]のAWSアクセスキー([キーID])が、[場所]で[最初の露出時刻 UTC]から公開されていました。
実施済みの対応:
・[時刻]にキーを無効化し、[時刻]より前に発行されたセッションを拒否しました。
・[リージョン]の操作ログを[開始]から[終了]まで保存しました。
判明していること:[例:不明なIPアドレスからの操作が○時に発生。新規ユーザーなし/新規ユーザーを発見し無効化済み]
未確認の事項:[例:バケットXのファイルが読まれたか。データアクセスの記録が無効だったため]
サービスへの影響:[なし/サービスYを○時まで停止]
次の対応と担当:[対応 - 担当者 - 期限]
次回報告:[時刻 UTC]
連絡先:[インシデント責任者の氏名と連絡手段]
リポジトリやワークロードの担当者への確認依頼
段階0と段階1に必要な事実を、責めることなく素早く集めるために使います。
件名:【至急】キー[キーID]について30分以内に3点ご回答ください
[氏名]さん
セキュリティインシデントの対応中です。キー[キーID]が[場所]で見つかりました。目的は早く直すことであり、誰かを責めることではありません。
次の3点を返信してください。
1. このキーを使っているサービス、スクリプト、パイプラインはどれですか。止まると何が壊れますか。
2. このキーをほかに保存した場所はありますか(別のリポジトリ、CIの変数、PC、Wiki、チャットなど)。
3. いつ[場所]に追加しましたか。公開リポジトリ、フォーク、イメージに入ったことはありますか。
キーの削除、履歴の書き換え、修正のプッシュはまだ行わないでください。片付けは一緒に段取りします。
よろしくお願いします。[インシデント責任者]
AWSサポートへのケース
段階6で使います。サポートプランで選べるアカウント・請求または技術のカテゴリを選びます。AWSサポートには英語で送るのが確実なため、英語の文面にしています。
Subject: Unauthorized activity using a compromised access key – account [account ID]
We identified unauthorized use of the IAM access key [key ID] (IAM user [user name]) in account [account ID].
Exposure: the key was publicly exposed in [location] from [time UTC].
Actions taken: key deactivated at [time UTC]; sessions issued before [time UTC] denied; unauthorized resources [list] [disabled/removed] after evidence was saved.
Observed activity: [e.g. RunInstances in Regions X and Y; CreateUser "name" at time].
We request: [review of the account for further unauthorized activity / guidance on charges resulting from this activity / anything else].
Contact: [name, phone, time zone]
経営層向けの要約(5行)
最初の数時間が過ぎたあと、経営者や取締役会への要約に使います。
1. 何が起きたか:[システム名]のクラウド用アクセスキーが、[場所]で[期間]公開されていました。
2. 現在の状態:キーは無効化済みです。攻撃者のアクセスは[遮断済み/確認中]です。
3. これまでに確認した影響:[例:未使用リージョンでサーバーが起動され、推定費用は○円。データアクセスの証拠はないが、データアクセスの記録は無効だった]
4. 必要な判断:[例:外部のフォレンジック支援の承認/サービスYの停止の容認/顧客Zへの連絡]
5. 次回報告:[時刻]。責任者:[氏名]
具体例:公開リポジトリにプッシュされたキー
架空の事例です。会社、人物、時刻、数値はすべて創作で、判断のつながりを示すためのものです。
状況: 従業員40人のソフトウェア会社。UTC 08:47、開発者が個人の公開GitHubリポジトリにテスト用スクリプトをプッシュしました。スクリプトには、夜間バックアップ用の本番アクセスキーが含まれていました。
- 09:05 アラート。 AWSからアカウント所有者に、キーが公開されていたことと、隔離ポリシーを付けたことを知らせるメールが届きます(K04)。隔離は一部の操作を制限するだけなので、誰もこれで終わりとは考えません。
- 09:12 初動。 CTOがインシデント責任者になります。
get-access-key-infoで本番アカウントと確認し、get-access-key-last-usedで08:53に見慣れないアドレスから使われたと分かります(K01〜K03)。UTCの時系列で案件を作ります。 - 09:20 封じ込め。 担当者によると、キーを使うのは夜間バックアップだけで、止めても失うのは1回分のバックアップです(K09)。キーをInactiveにし、発行時刻で拒否するポリシーを付け、ユーザーのコンソールパスワードを削除します(K10、K12)。
- 09:40 活動の確認。 全リージョンのイベント履歴から、08:52の
GetCallerIdentityとListBuckets、隔離前の08:55に実在のサービスアカウントに似た名前のユーザーのCreateUserとCreateAccessKey、そして会社が使ったことのない2つのリージョンでのRunInstancesの失敗が見つかります(K17、K18、K20、K21)。 - 10:10 永続化の除去。 新しいユーザーの詳細とポリシーを案件に保存し、そのキーを無効化し、ユーザーにはすべての操作を拒否します。認証情報レポートで、ほかに新しいユーザーがないことを確認します(K21)。
- 10:40 影響。 キーは顧客データのエクスポートを置くバケットを読めました。S3のデータイベントは有効にしていなかったため、読み取りは確認も否定もできません(K19、K25)。その日のうちに、その表現のまま法務に伝えます(K32)。Cost Explorerでは新しい費用は見つかりません(K26)。
- 14:00 キーの交換。 バックアップ処理をIAMロールに移し、証拠を保存したうえで古いキーと攻撃者のユーザーを削除します。開発者はリポジトリを削除し、履歴も片付けます(K29〜K31)。
- 2日目 再発防止。 組織全体でプッシュ保護を有効にし、新しいユーザーとキーのアラートを作り、エクスポート用バケットのデータイベントを有効にします(K33〜K35)。責任者は、30分間にエクスポート用バケットが読まれた可能性という1つの残存リスクを受け入れて案件を閉じます(K36)。
分かれ目になったこと: アラートから15分でキーを無効化したこと。封じ込めを宣言する前に新しいユーザーを探したこと。ログで示せないのに「データへのアクセスはなかった」と言わなかったこと。
未解決事項と事後の改善
監査ログが答えるのは「どのAPIが呼ばれたか」であり、「どのデータが読まれたか」とは限りません。データアクセスの記録がなければ、ストレージからの読み取りは何も残らない場合があります。封じ込め前に作られたセッション、フォークやキャッシュに残る鍵の写し、ログのないアカウントやリージョンも未解決事項です。明記してください。すべての行を埋めても、網羅の保証にはなりません。
終結時は、なぜ長期間有効な鍵が存在し、見つかった場所に届き得たのかを問います。可能な範囲で短期間・フェデレーションによるアクセスに置き換え、コードのプッシュ前に秘密情報の検査を有効にし、検証用アカウントで権限のないテスト用の鍵を意図的に露出させて対応を演習してください。
参考資料と更新履歴
以下は2026-10-06に確認した資料です。製品・ライセンス・ログ構成が変わるため、実行前に自環境の仕様を確認してください。
- AWS Security Blog: what to do if you inadvertently expose an AWS access key
- AWS IAM: disabling permissions for temporary security credentials
- AWS IAM: revoke IAM role temporary security credentials
- AWS managed policy: AWSCompromisedKeyQuarantine
- Unit 42: how AWS neutralizes compromised IAM credentials
- Microsoft: compromised and malicious applications investigation
- AWSCloudTrail schema (Microsoft Sentinel)
- AADServicePrincipalSignInLogs schema
- Splunk: AWS CloudTrail data source fields
2026-10-06:初版。 EN/日本語の判断IDとクエリを一致させて公開。
