ポリシーリスクを可視化。自然な言葉でポリシーに関する疑問を解決します。 デモを申し込む →

Published:

侵害されたEC2認証情報を(できる限り)影響を及ぼさずに封じ込める

by FireMon

侵害されたインスタンス認証情報を封じ込める手法は複数あります。簡単な手法ほど何かを壊してしまう可能性が高いのですが、アプリケーションを壊さずに攻撃者を締め出す工夫を凝らした選択肢も存在します。

ここ数年、Amazon は AWS インスタンスに割り当てられた認証情報を攻撃者が窃取し悪用するリスクを低減するため、大きな進歩を遂げてきました。確かに、その多くは誰もがいまだに語り継ぐあの大規模侵害の後に起きたことですが、現在ではこの種の攻撃を防ぐためのはるかに優れたツールが揃っています。とはいえ、この攻撃は依然として非常に一般的であり、あらゆるクラウド脅威リストの上位に位置しています。

先月、AWS はインスタンス認証情報を保護する新しいポリシーオプションを公開しました。これが本稿を書くきっかけとなりました。もう一つのきっかけは、後ほど触れるクラウドセキュリティコミュニティからの興味深い発見です。この新機能は素晴らしく、AWS が認証情報の窃取に対する GuardDuty の検知を大幅に改善したこととあわせても、いずれ当社のようなツールからアラートを受け取り、インシデント対応プロセスを始動させなければならない場面が訪れるかもしれません。

AWS がインスタンス認証情報を保護する新しいポリシーオプションを公開したことを示す画像。

私は長年にわたり多数の封じ込め手法をまとめ、検証してきました。その大半については、Will Bengtson氏と共同で作成したクラウドインシデント対応トレーニングにラボを用意しています。何も壊さずに攻撃者を封じ込めるには、驚くほど多くの微妙な考慮点があります。インスタンス認証情報を扱う際、実質的に次の3つのコンポーネントとやり取りすることになります。権限を管理する IAM サービス、その認証情報をインスタンスに受け渡すインスタンスメタデータサービス(IMDS)、そしてインスタンス内で認証情報を使用してアプリケーションを実行するコード/SDK です。なお、ここでは意図的に一部を単純化しており、Service Control Policy やリソース(バケット)ポリシーについては触れていません。(本稿のスクリーンショットはすべて、私自身のトレーニングから堂々と拝借したものですので、当局に通報しないでください。)

ご存じない方のために簡単に背景を説明すると、インスタンスに IAM ロールを割り当てると、そのインスタンスには当該ロールの権限を付与する、自動的にローテーションされる認証情報が提供されます。しかし攻撃者が SSRF 攻撃や SSH のブルートフォースなど何らかの方法でインスタンスにアクセスできれば、その認証情報をコピーし、AWS の外部や攻撃者が管理する AWS アカウントから使用できてしまいます。

準備として、Will は S3 バケットへの内部接続を試み、認証情報が有効かどうかを報告する小さなアプリケーションを作成しました(なお、表示されている IP アドレスはすでに有効ではありません)。

インスタンスに割り当てられた IAM ロールが、自動的にローテーションされる認証情報を提供する様子を示す画像。

選択肢1:ロールに Deny All ポリシーを追加する

これは群を抜いて最も簡単かつ迅速な方法です。IAM ロールに Deny All ポリシーを追加すれば、すべての API 呼び出しが失敗し、攻撃者はそれ以上の被害を与えられなくなります。

選択肢1:ロールに Deny All ポリシーを追加する様子を示す画像。

迅速かつ簡単ですが、正当な API 呼び出しもすべて停止するため、アプリケーションを手っ取り早く壊す方法でもあります。

選択肢1:Deny All ポリシーを適用してアプリケーションの API 呼び出しを制限する様子を示す画像。

思い出してください。私たちの目的は、稼働中の正当なアプリケーションを壊さずに攻撃者を締め出すことです。

失敗です。

選択肢2:セッションを失効させる

AWS には、アクティブなセッションを失効させる便利な機能があります。コンソールでボタンをクリックするだけで、ボタンをクリックした時点より前に開始されたセッションのみアクセスを拒否するカスタム Deny All ポリシーを追加できます(これに相当する単純な API 呼び出しはありませんが、同じことを行うポリシーを自分で記述するのは難しくありません)。

選択肢2:セッションを失効させる様子を示す画像。

攻撃者が新しいセッションを侵害できないようブロックできていると仮定すれば、理論上は窃取された認証情報を失効させることで攻撃者を締め出し、アプリケーションは新しい認証情報で動作し続けられるはずです。しかし……

選択肢1:Deny All ポリシーを適用してアプリケーションの API 呼び出しを制限する様子を示す画像。

うまくいきません。失敗その2です。なぜでしょうか。

IMDS は認証情報が期限切れになったときにのみ更新します。IMDS は IAM とは別のサービスであり、認証情報を失効させたことを知りませんし、新しい認証情報を取得してインスタンスに提供する理由も動機もありません。IMDS はセッションが終了するまで、失効した認証情報を提供し続けます。

選択肢3:IAM ロールを変更し、旧ロールを拒否する

ここから少し凝った手法になります。新しいロールを作成してインスタンスをそちらに切り替え、古いロールをブロックするとどうなるでしょうか。前述と同様、これは攻撃者が新しいロールの認証情報を窃取できないと分かっている場合にのみ有効です。

選択肢3:IAM ロールを変更し、旧ロールを置き換える様子を示す画像。

うまくいきません。失敗その3です。ここでは何が起きているのでしょうか。

選択肢1:Deny All ポリシーを適用してアプリケーションの API 呼び出しを制限する様子を示す画像。

ほとんどのコードや SDK は、起動時に IAM セッションを確立し、メタデータサービスから認証情報を取得します。これらの認証情報にはセッション期間があり、これは Time to Live(TTL)のようなものです。認証情報はメモリ内に保持され、その期間の終わり近くまで使用されます。たとえば、このデモで使用した Python の Boto ライブラリでは、認証情報の有効期限の15分前になるまで新しい認証情報を探しに行きません。

したがって、アプリケーションは更新された認証情報を探しに行くまで失敗し続けます。設定によりますが、EC2 インスタンスではこれが既定で6時間ごとになる傾向があります。もちろん、API 呼び出しが失敗したら新しい認証情報の取得を試みるような優れたエラー処理を実装する素晴らしい開発者がいるかもしれませんが、一般的なユースケースではないため、その可能性は低いでしょう。

インスタンス内のコードは、それ以外の方法を知らないため、依然として古いロールを使おうとします。選択肢2では、IMDS が IAM に問い合わせて認証情報を更新すべきだと知らなかったために問題が生じました。今回は、コードが IMDS に問い合わせて新しい認証情報を取得すべきだと知らないのです。

選択肢4:VPC エンドポイントを挿入する

これは私が凝ってみた手法で、群を抜いて複雑ですが、非常にうまく機能します。すべてのインスタンスは VPC(Virtual Private Cloud)内に存在し、これが AWS における仮想ネットワークです。通常、すべての API 呼び出しはインターネット経由でパブリックな AWS エンドポイントに到達します。実際、インターネットへのアウトバウンドルートを持たないプライベートサブネットにインスタンスがある場合、これらの API 呼び出しは失敗します。

自分のプライベートインスタンスから自分のプライベート S3 バケットに接続したい場合、これはかなり大きな問題です。かつてはインターネットアクセスを有効にする必要がありましたが、これはコストがかかり、私たちセキュリティ担当者が最小化したいと考える形で環境を外部に開いてしまいます。

Amazon の回答が、サービスエンドポイントと呼ばれるものです。これは内部のソフトウェア定義ルーティング構造であり、VPC 内のリソースが Amazon の内部ネットワーク上で API エンドポイント(およびその他のもの。ただし本稿ではそこには踏み込みません)と通信できるように設定できます。興味深いのは、VPC エンドポイントを使用すると、AWS がプライベートヘッダーにデータを埋め込めるようになるため、ネットワークトラフィックに追加のコンテキストが挿入され、それを IAM ポリシーの条件として利用できる点です。

まず、インスタンスが存在するサブネットに S3 用の VPC エンドポイントを追加します。

選択肢4:VPC エンドポイントを挿入する手順を示す画像。

次に、想定される VPC から発信されていないトラフィックをすべて拒否する条件を IAM ポリシーに追加します。トレーニングラボでは次のように実施しています。

選択肢4:想定される VPC から発信されていないトラフィックを拒否する条件を IAM ポリシーに追加する様子を示す画像。

これが機能すれば、インスタンスからの API 呼び出しは引き続き動作しますが、この VPC 以外の場所から使用された場合、認証情報は失敗します(したがって、攻撃者が VPC 内の別のリソースにアクセスできないことを願うばかりです)。

選択肢4:想定される VPC から発信されていないトラフィックを拒否する IAM ポリシーの条件を検証する様子を示す画像。

成功です。認証情報は VPC 内からのみ機能し、攻撃者は締め出されます。これは、先ほど触れた Service Control Policy とまったく同じ仕組みです。SCP の問題は、サービスエンドポイントがコストと複雑性を増すことと、必要なエンドポイントをすべて整備しないままそのポリシーを有効にすると何かを壊してしまうこと、しかも今度はエンタープライズ規模で壊してしまうことです。

予期しない挙動

前述のとおり、このラボは約2年前に構築し、これまで数百名の受講者に実施してきました。先週、Uptycs の Andre Rall 氏が、私たちが共に参加しているクラウドセキュリティコミュニティに次のような投稿をしました(本人の許可を得て掲載)。

これは起こるべき挙動なのか、ご存じの方はいますか。インスタンスに関連付けられたインスタンスプロファイルにアタッチされたロールがあります。(CLI で)そのロールをインスタンスプロファイルから削除しても、インスタンスプロファイル自体はインスタンスに関連付けたままにしておくと、インスタンスは依然としてそのロールの認証情報を使用できてしまいます。ロールがアタッチされていない以上、インスタンスはそれを使い続けられないはずだと私は考えているのですが、何か見落としているのかもしれません。

これもまた、サービス間の相互作用に行き着きます。裏側では、インスタンスプロファイルは AWS がメタデータサービス内でロールとインスタンスを結び付けるために使用するものです。Andre 氏はインスタンスプロファイルからロールを削除しましたが、ロールは依然として存在し、インスタンスプロファイルも依然として存在しています。

IMDS は認証情報を提供できなくなるはずだと思われるかもしれませんが、IMDS は依然として認証情報を保持しており、IAM サービス側で何が起きたのかを知りません。IMDS は引き続き認証情報を提供し、ロールも引き続きその認証情報を許可するため、依然として機能してしまいます。このケースでは、認証情報を失効させる方法なら有効です。インスタンスプロファイルとロールが切り離された後、IMDS は新しい認証情報を取得できなくなるからです。

IAM 認証情報の封じ込めには多くの微妙な考慮点があり、ここで示したのは1つのサービス(EC2)における一例にすぎません。しかし、IAM サービスが IMDS とやり取りし、IMDS が SDK とやり取りするという流れを理解すれば、他の状況でも活用できる中核的な原則の確かな土台が得られます。

また、提供を開始したばかりの FireMon Cloud Defense 無償プランもぜひご確認ください

侵害された EC2 認証情報への対処法 | FireMon