クラウドの「鍵」を盗ませない:IMDSv2強制によるSSRF完全防御の実践ガイド
「クラウドの設定なんて、デフォルトのままでいいだろう」――そう高を括ったシステムが、どれほど無惨な結末を迎えるか。私は現場で何度も見てきました。
攻撃者は、あなたのWebアプリのほんのわずかな隙間、例えばfile_get_contentsのパラメータバリデーション漏れや、無防備なプロキシ設定を見逃しません。そこからSSRF(Server-Side Request Forgery)を仕掛け、メタデータサービス(IMDS)を叩いてIAMロールの認証情報を奪い取る。これが、現代のクラウド侵入の「定石」です。
今日は、この「クラウドの心臓部」を守るための、IMDSv2強制設定と防御の実装について、現場の知見を叩き込みます。
—
1. なぜIMDSv1は「死」を招くのか
AWSを例に挙げましょう。IMDSv1は、http://169.254.169.254/latest/meta-data/ へリクエストを送るだけで、IAMロールの認証情報(AccessKey/SecretKey/Token)が平文で返ってきます。
攻撃者のPoCは驚くほどシンプルです。脆弱なWebアプリの入力値に、以下のようなURLを突っ込むだけです。
# 攻撃者が実行する典型的なコマンド
curl http://<脆弱なWebアプリのドメイン>/proxy?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/<ロール名>
これだけで、攻撃者はあなたのサーバーに付与された権限を「乗っ取ります」。この後、S3バケットを全ダウンロードしたり、DBを破壊したりするのは彼らにとって朝飯前です。
2. IMDSv2による「セッション指向」の防壁
IMDSv2は、この脆弱性を「セッション認証」という概念で封じ込めます。
1. PUTリクエストによるトークン生成: まずトークンを取得しなければ、データにアクセスできない。
2. ヘッダーの強制: トークンを X-aws-ec2-metadata-token ヘッダーに含める必要がある。
3. ホップ制限: X-Forwarded-For などのヘッダーを悪用した転送を阻止する。
これらが導入されることで、単純なSSRF攻撃は「トークンが取得できない」ため、完全に無効化されます。
—
3. 実践:IMDSv2を強制する設定(Terraform/AWS CLI)
まずはインフラ側で「v1を殺す」設定です。これをやらない限り、アプリケーション側の対策は無意味です。
# Terraformでの設定例
resource "aws_instance" "secure_server" {
ami = "ami-xxxxxxxx"
instance_type = "t3.micro"
metadata_options {
http_endpoint = "enabled" # メタデータサービスを有効化
http_tokens = "required" # 【重要】IMDSv2を強制
http_put_response_hop_limit = 1 # 【重要】ホップ数を制限し、SSRFによる中継を防止
}
}
この設定を行うと、http_tokens = "required" により、トークンなしのリクエストは即座に 401 Unauthorized となり、攻撃の入り口が物理的に閉ざされます。
—
4. セキュアな実装:アプリケーションコードの守り方
もしあなたがアプリ開発者なら、メタデータを叩く必要がない限り、以下のような「URLバリデーション」を必ず実装してください。
Pythonでの実装例(requests使用時)
import requests
from urllib.parse import urlparse
def safe_get(url):
# 169.254.169.254 へのアクセスを禁止するブラックリストチェック
blocked_host = "169.254.169.254"
parsed_url = urlparse(url)
if parsed_url.hostname == blocked_host:
raise ValueError("悪意のあるアクセスを検出しました")
# 許可されたドメインのみ通信を許可する(ホワイトリスト方式が推奨)
return requests.get(url, timeout=5)
JavaScript (Node.js/Express) の場合
// プロキシ等の実装でURLを扱う場合
const url = require('url');
function isSafeUrl(targetUrl) {
const parsed = url.parse(targetUrl);
// メタデータサービスのIPをブロック
if (parsed.hostname === '169.254.169.254') {
return false;
}
return true;
}
—
5. 現場のセキュリティ担当者からの提言
最後に、一つだけ覚えて帰ってください。「技術的な防御は、設定の不備で容易に崩れる」ということです。
- IaCの自動テスト:
metadata_optionsがrequiredになっていないインスタンスをCI/CDでデプロイ拒否するガードレールを設けてください。 - IAMの最小権限: 万が一SSRFが突破された時のために、そのインスタンスに割り当てるIAMロールは「そのアプリがS3の特定のフォルダにしかアクセスできない」程度の最小限に抑えておくこと。
- ログの監視:
169.254.169.254へのアクセス試行をVPCフローログで検知し、即座にアラートが飛ぶ仕組みを作ってください。
セキュリティとは、ただの「設定」ではなく、こうした「多層防御の積み重ね」のプロセスそのものです。次回のデプロイから、このIMDSv2の強制を標準装備にしてください。それが、あなたのシステムを「選ばれる堅牢なプラットフォーム」にするための第一歩です。
コメント