クラウドの「鍵」を盗まれる前に。IMDSv2強制によるSSRF完全防御の極意
エンジニア諸君、お疲れ様。今日もどこかのサーバーで脆弱性が突かれ、インシデント対応に追われている現場があることだろう。
今回は、AWS等のクラウド環境における「SSRF(Server-Side Request Forgery)」の防波堤として、今や必須事項であるIMDSv2(Instance Metadata Service Version 2)の強制について語る。
「まだIMDSv1を使っている?」「http://169.254.169.254 へのアクセスなんて、うちのアプリはしないから大丈夫?」……その甘い認識が、企業の重要資産を路頭に迷わせる。この設定は、単なる「推奨」ではなく「生存戦略」だ。
—
1. なぜIMDSv1は「終わった」のか?
IMDSv1は、認証なしでリクエストを投げるだけでインスタンスのメタデータを取得できる仕組みだった。攻撃者は、Webアプリに存在するSSRFの脆弱性を突き、このエンドポイントを叩く。
攻撃シナリオ(PoC)
例えば、ユーザーがURLを入力するとその内容をサーバー側で取得して表示するような機能があるとしよう。攻撃者は以下のようにリクエストを操作する。
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/[ロール名]
これだけで、IAMロールの認証情報(AccessKey/SecretKey/Token)が平文で返ってくる。これを入手した攻撃者は、君たちのAWSアカウントの「中身」を好き勝手に操作できる状態になる。これが「メタデータ盗難」の恐ろしさだ。
IMDSv2では、これに「セッショントークン」という物理的な壁を設けることで、SSRFによる単発のGETリクエストではメタデータを取得できないように設計されている。
—
2. IMDSv2への移行と強制手順
まずは、IMDSv2を強制するための設定を確認しよう。TerraformやCloudFormationを使っているなら、今すぐ以下の設定を確認してほしい。
AWS CLIによる強制設定
既存インスタンスに対して、IMDSv2を必須化するコマンドだ。
# IMDSv2を必須化し、v1を無効化する
aws ec2 modify-instance-metadata-options \
--instance-id i-xxxxxxxxxxxxxxxxx \
--http-tokens required \
--http-put-response-hop-limit 1 \
--http-endpoint enabled
http-tokens required: これが肝だ。セッショントークン必須を強制する。http-put-response-hop-limit 1: これを 1 にすることで、コンテナ内からのアクセスや、多段プロキシを経由したアクセスを遮断し、SSRFの影響範囲を最小化する。
—
3. アプリケーションコードでのセキュアな実装
「じゃあ、プログラムからメタデータを取得したいときはどうすればいいのか?」という疑問に対して、正しい実装サンプルを提示する。Python(boto3)や標準的なHTTPクライアントを使う場合だ。
Pythonでの実装例
boto3 を使うのがベストだが、もし低レイヤーでHTTPリクエストを叩く必要がある場合のロジックがこれだ。
import requests
def get_metadata_token():
"""IMDSv2用のセッショントークンを取得する"""
headers = {'X-aws-ec2-metadata-token-ttl-seconds': '21600'}
# PUTメソッドでトークンを要求
response = requests.put(
'http://169.254.169.254/latest/api/token',
headers=headers
)
return response.text
def get_metadata(path):
"""トークンをヘッダーに付与してメタデータを取得"""
token = get_metadata_token()
headers = {'X-aws-ec2-metadata-token': token}
response = requests.get(
f'http://169.254.169.254/latest/{path}',
headers=headers
)
return response.text
# 利用例: インスタンスIDを取得
print(get_metadata('meta-data/instance-id'))
見ての通り、ステップが2つに増えている。単純なSSRFの脆弱性だけでは「トークン取得(PUT)」と「メタデータ取得(GET)」の両方を完遂することは非常に困難だ。
—
4. 現場のプロとしての提言:防御の多層化
IMDSv2の強制は「最低限の防御」だ。さらに堅牢なインフラにするために、以下の対策を忘れないでほしい。
1. IAMロールの最小権限化: 万が一メタデータを盗まれても、被害を最小限にするために、インスタンスに付与するIAMロールには「必要な権限のみ」を記述すること。
2. ネットワーク分離: メタデータエンドポイントへのアクセスを、アプリケーションが必要とする通信以外制限できないか検討する。
3. WAFによる防御: Webアプリの入り口で、URLパラメータに 169.254.169.254 や metadata という文字列が含まれるリクエストをブロックするWAFルールを設定しておく。これは「多層防御」のセオリーだ。
NginxでのSSRFブロック例(設定ファイル)
もし、どうしてもWebアプリでSSRFの懸念が拭えない場合、リバースプロキシで止めるのも手だ。
# nginx.conf 内のサーバーブロック
location / {
# メタデータIPへのリクエストを拒否
if ($arg_url ~* "169.254.169.254") {
return 403;
}
proxy_pass http://backend_app;
}
—
最後に
セキュリティとは、完璧な製品を導入することではない。「攻撃者が嫌がる面倒な仕組み」を幾重にも積み重ねることだ。IMDSv2の強制は、その中でも最も費用対効果が高く、かつ即効性のある防御策である。
明日と言わず、今すぐ君の環境の http-tokens 設定を確認してくれ。もし optional になっていたら、それが君のシステムの「穴」だ。健闘を祈る。
コメント