EC2のIMDSv2強制が「httpTokensEnforced」でさらに堅牢に — Capital One事件から始まったIMDSセキュリティ強化の現在地

AWSAmazon EC2IMDSv2セキュリティSSRF

AWS CLIの2.33.29で、ModifyInstanceMetadataDefaults APIに httpTokensEnforced プロパティが追加されました。アカウントレベルでIMDSv1を使ったインスタンス起動を完全にブロックできるようになっています。

この機能を理解するには、なぜIMDSv1が危険なのかを知る必要があります。2019年のCapital One事件まで遡って、IMDSセキュリティ強化の流れを整理してみます。

そもそもIMDSとは

EC2インスタンスの中から http://169.254.169.254/ にHTTPリクエストを送ると、そのインスタンス自身のメタデータを取得できます。これがInstance Metadata Service(IMDS)です。

取得できる情報には、インスタンスID、AMI ID、ネットワーク情報などがありますが、セキュリティ上最も重要なのは IAMロールの一時的な認証情報です。EC2にIAMロールをアタッチすると、インスタンス内のアプリケーションはIMDS経由で自動的に認証情報を受け取れます。AWS SDKやCLIが裏側でやっているのもこの仕組みです。

便利な反面、この仕組みが大規模な情報漏洩に悪用されたのが2019年のCapital One事件でした。

Capital One事件(2019年)

2019年3月、元AWSエンジニアのPaige Thompsonが、Capital OneのAWS環境から1億件以上の顧客データを窃取しました。攻撃の流れはこうです。

  1. Capital OneのWAF(Web Application Firewall)に設定ミスがあり、WAFがリバースプロキシとして機能していた
  2. このWAFに対してSSRF(Server-Side Request Forgery)攻撃を実行
  3. WAFを経由して http://169.254.169.254/latest/meta-data/iam/security-credentials/ISRM-WAF-Role にアクセス
  4. IAMロールの一時認証情報を取得
  5. その認証情報で700以上のS3バケットにアクセスし、約30GBのデータをダウンロード

ここで問題になったのが IMDSv1の仕様です。IMDSv1は単純なHTTP GETリクエストだけでメタデータを返します。つまり、SSRFでリクエストを飛ばせさえすれば、認証情報が取れてしまいます。

Capital Oneは8,000万ドルの罰金を科され、Paige Thompsonはワイヤー詐欺を含む複数の罪で有罪判決を受けています。2025年3月には控訴審で「量刑が軽すぎる」との判断が下され、再量刑で禁固刑こそ免れたものの、3年間の自宅軟禁と4,070万ドルの賠償命令が確定しています(2025年3月 TechTarget、2025年11月 CyberScoop)。

AWSの対応 — IMDSv2の登場

Capital One事件が公になったのが2019年7月。その4か月後の2019年11月にAWSはIMDSv2をリリースしました(2019年11月19日 AWS Security Blog)。

IMDSv2はセッションベースの認証を導入しています。メタデータを取得するには2ステップが必要になります。

# ステップ1: PUTリクエストでセッショントークンを取得
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

# ステップ2: トークンをヘッダに付けてメタデータを取得
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/

SSRFでGETリクエストは飛ばせても、PUTリクエストでトークンを取得するのは格段に難しくなります。さらに、PUTリクエストに X-Forwarded-For ヘッダが含まれている場合は拒否されるため、プロキシ経由のアクセスも防げます。

IMDSv2強制化のタイムライン

IMDSv2がリリースされてから「v1を完全に無効化する」までの道のりは長いものでした。AWS SDKやサードパーティツールのIMDSv2対応が必要だったためです。

  • 2019年11月: IMDSv2リリース
  • 2023年11月: EC2コンソールのクイックスタートがIMDSv2のみに(2023年11月 AWS News Blog
  • 2024年3月: ModifyInstanceMetadataDefaults APIリリース。アカウントレベルでIMDSv2をデフォルトに設定可能に(2024年3月 AWS What’s New
  • 2024年中頃: 新しいEC2インスタンスタイプはIMDSv2のみがデフォルトに
  • 2024年12月: Organizations宣言的ポリシーでIMDSv2を組織全体に強制可能に(2024年12月 AWS News Blog
  • 2025年頃: httpTokensEnforced プロパティの追加(今回の話)

段階的に「デフォルトをv2にする」→「v1を使えなくする」へと強化が進んでいるのが分かります。

httpTokensEnforced — 何が変わったのか

見落としがちですが、従来の HttpTokens=required と今回の HttpTokensEnforced=enabled別のものです。ここが今回のアップデートで最も重要なポイントだと思います。

HttpTokens=required だけでは不十分だった

2024年3月に追加された ModifyInstanceMetadataDefaults APIで、アカウントレベルのデフォルトを HttpTokens=required に設定できるようになりました。しかしこれは、あくまでデフォルト値です。

インスタンスの起動時に --metadata-options HttpTokens=optional を明示的に指定すれば、デフォルト設定が上書きされてIMDSv1が有効なインスタンスを起動できてしまいます。例えば、古いCloudFormationテンプレートや起動テンプレートに HttpTokens: optional が残っていた場合、アカウントのデフォルトをいくら required に設定していても、IMDSv1のインスタンスが立ち上がります。

アカウントデフォルト: HttpTokens=required

起動パラメータ: HttpTokens=optional  ← これが優先される

結果: IMDSv1が有効なインスタンスが起動してしまう

せっかくアカウントレベルで設定していても、個々の起動パラメータで迂回できてしまうのでは、管理者としては安心できません。

HttpTokensEnforced が塞ぐもの

HttpTokensEnforced=enabled は、この抜け道を塞ぎます。

アカウントデフォルト: HttpTokens=required + HttpTokensEnforced=enabled

起動パラメータ: HttpTokens=optional  ← 指定しても…

結果: UnsupportedOperation エラーで起動がブロックされる
シナリオHttpTokens=required のみ+ HttpTokensEnforced=enabled
起動時に何も指定しないデフォルトでIMDSv2必須デフォルトでIMDSv2必須
起動時に HttpTokens=optional を明示指定IMDSv1で起動できてしまうブロックされる
既存のIMDSv2インスタンスをIMDSv1に変更変更できるブロックされる

さらに、既存のIMDSv2専用インスタンスに対してIMDSv1を有効にしようとする操作もブロックされます。「デフォルトを設定する」と「強制する」は別の話だということです。

ここは注意が必要です。HttpTokensEnforced を有効にした状態で、IMDSv2に対応していないAMIやツールを使うとインスタンスが起動できなくなります。有効化の前に、環境内のIMDSv1依存を洗い出しておく必要があります。

自分の環境で試してみました

検証環境

  • AWS CLI: 2.34.8
  • リージョン: ap-northeast-1

httpTokensEnforced パラメータは AWS CLI 2.33.29 で追加されています(CHANGELOG 2.33.29)。

現在の設定を確認

まず、何も設定していない状態を確認します。

$ aws ec2 get-instance-metadata-defaults --region ap-northeast-1

{
    "AccountLevel": {
        "ManagedBy": "account"
    }
}

HttpTokensHttpTokensEnforced も表示されていません。何も設定されていないデフォルト状態です。

httpTokensEnforcedを有効化

IMDSv2を必須にしつつ、強制を有効にします。

$ aws ec2 modify-instance-metadata-defaults \
    --http-tokens required \
    --http-tokens-enforced enabled \
    --region ap-northeast-1

{
    "Return": true
}

設定を確認します。

$ aws ec2 get-instance-metadata-defaults --region ap-northeast-1

{
    "AccountLevel": {
        "HttpTokens": "required",
        "ManagedBy": "account",
        "HttpTokensEnforced": "enabled"
    }
}

HttpTokensEnforcedenabled になりました。

IMDSv1でのインスタンス起動を試みる

--metadata-options HttpTokens=optional を明示的に指定してインスタンスを起動してみます(--dry-run で実際には起動しません)。

$ aws ec2 run-instances \
    --image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64 \
    --instance-type t4g.nano \
    --subnet-id subnet-xxxxxxxxxxxxxxxxx \
    --metadata-options "HttpTokens=optional,HttpEndpoint=enabled" \
    --dry-run \
    --region ap-northeast-1

An error occurred (UnsupportedOperation) when calling the RunInstances operation:
You can't launch instances with IMDSv1 because httpTokensEnforced is enabled
for this account. Either launch the instance with httpTokens=required or
contact your account owner to disable httpTokensEnforced using the
ModifyInstanceMetadataDefaults API or the account settings in the EC2 console.

UnsupportedOperation で明確にブロックされました。エラーメッセージも分かりやすく、何が原因で何をすればいいのかが書かれています。

IMDSv2での起動は成功する

同じ条件で HttpTokens=required に変えると、起動は成功します。

$ aws ec2 run-instances \
    --image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64 \
    --instance-type t4g.nano \
    --subnet-id subnet-xxxxxxxxxxxxxxxxx \
    --metadata-options "HttpTokens=required,HttpEndpoint=enabled" \
    --dry-run \
    --region ap-northeast-1

An error occurred (DryRunOperation) when calling the RunInstances operation:
Request would have succeeded, but DryRun flag is set.

DryRunOperation は「dry-runだから実行しなかったが、権限も設定も問題ない」という意味です。IMDSv2であれば正常に起動できることが確認できました。

実運用での活用方法

段階的に導入する

いきなり httpTokensEnforced を有効にすると、IMDSv1に依存したワークロードが起動できなくなります。以下の順序で進めるのがおすすめです。

  1. CloudWatchの MetadataNoToken メトリクスを確認 — IMDSv1呼び出しをしているインスタンスを特定する
  2. AWS Configの ec2-imdsv2-check ルールを有効化 — IMDSv1が有効なインスタンスを継続的に検出する
  3. HttpTokens=required をアカウントデフォルトに設定 — 新規インスタンスのデフォルトをIMDSv2にする
  4. 既存インスタンスのIMDSv2移行を完了 — SDK、エージェント、自作スクリプトの対応を確認
  5. HttpTokensEnforced=enabled を有効化 — IMDSv1への切り替えを完全にブロック

Organizations宣言的ポリシーとの組み合わせ

組織全体で統一したい場合は、AWS Organizationsの宣言的ポリシーを使うこともできます。管理アカウントまたは委任管理者アカウントから、OU単位やアカウント単位でIMDSv2を強制できます。

この場合、get-instance-metadata-defaultsManagedBy フィールドが declarative-policy になります。宣言的ポリシーで管理されている場合、個々のアカウントからは設定を変更できなくなるため、ガバナンスがさらに強化されます。

Terraformは未対応(2026年3月時点)

Terraformユーザーにとって注意が必要な点があります。Terraform AWS Provider(v6.37.0時点)の aws_ec2_instance_metadata_defaults リソースには http_tokens_enforced 引数がまだ存在しませんTerraform Registry)。

現在サポートされている引数は http_tokenshttp_endpointhttp_put_response_hop_limitinstance_metadata_tags の4つのみです。

# これはできる
resource "aws_ec2_instance_metadata_defaults" "enforce-imdsv2" {
  http_tokens                 = "required"
  http_put_response_hop_limit = 1
}

# http_tokens_enforced = "enabled" ← これはまだ使えない

つまり、Terraformで http_tokens = "required" を設定しても、それはデフォルト値を設定するだけで、起動時に HttpTokens=optional を指定すれば迂回できてしまう状態です。httpTokensEnforced による完全なブロックを実現するには、現時点ではAWS CLI、API、またはマネジメントコンソールから別途設定する必要があります。

GitHub issueも2026年3月時点では出ていないようなので、Terraformで管理したい場合はissueを上げて対応を待つか、aws_cli のローカルExecプロビジョナー等で補完するしかなさそうです。

ECS on EC2への影響 — 見落としがちなポイント

ここで気になるのが、ECSへの影響です。ECSタスクにも「メタデータエンドポイント」がありますが、これはEC2のIMDSとは別物です。

EC2 IMDSECS タスクメタデータ
エンドポイント169.254.169.254169.254.170.2
用途EC2インスタンスのメタデータ・インスタンスロール認証情報ECSタスクのメタデータ・タスクロール認証情報
httpTokensEnforcedの影響ありなし

ECSタスクが 169.254.170.2 経由でタスクロールの認証情報を取得する分には、httpTokensEnforced の影響は受けません。Fargateの場合はそもそもEC2インスタンスが存在しないため、完全に無関係です。

ECS on EC2の場合は注意が必要

見落としがちですが、ECS on EC2構成では間接的な影響があります。

ECSエージェント自体がEC2のIMDSを使っています。ECSエージェントはEC2インスタンス上で動作し、IMDSからインスタンスのメタデータや認証情報を取得しています。現在のECSエージェントはIMDSv2に対応済みですが、古いバージョンを使っている場合は httpTokensEnforced を有効にするとエージェントが起動できなくなる可能性があります。

ホップリミットの問題もあります。IMDSv2のトークンは HttpPutResponseHopLimit でネットワークホップ数が制限されます。EC2インスタンス上で直接動くプロセスなら1ホップで届きますが、コンテナからだとネットワークの構成によってホップ数が増えます。bridgeネットワーキングモードの場合、ホップリミットが1だとコンテナからIMDSv2のトークンが取得できません。AWSはコンテナ環境ではホップリミットを3に設定することを推奨しています。

# コンテナ環境向けにホップリミットを3に設定
$ aws ec2 modify-instance-metadata-defaults \
    --http-tokens required \
    --http-tokens-enforced enabled \
    --http-put-response-hop-limit 3 \
    --region ap-northeast-1

コンテナからEC2 IMDSへのアクセスをブロックする

もう一つ、セキュリティ的に注意が必要な点があります。awsvpcモードやhostモードのECSタスクは、ホップリミットに関係なくEC2のIMDS(169.254.169.254)にアクセスできてしまいます。つまり、タスクロールではなくインスタンスロールの認証情報を取得できてしまうということです。

これはCapital One事件と同じ構図です。コンテナ内のアプリケーションにSSRF脆弱性があれば、EC2のIMDS経由でインスタンスロールの認証情報を窃取される可能性があります。

この対策として、ECSエージェントの設定で ECS_AWSVPC_BLOCK_IMDS=true を指定することで、awsvpcモードのタスクからEC2 IMDSへのアクセスをブロックできます(AWS ECS ドキュメント)。

httpTokensEnforced だけでなく、コンテナ環境では「そもそもコンテナからEC2 IMDSにアクセスさせない」という多層防御の考え方が重要です。

Capital One事件から6年 — 残された課題

Capital One事件から6年が経ち、AWSはIMDSv1を無効化するためのツールを着実に整備してきました。httpTokensEnforced はその集大成ともいえる機能です。

ただし、この機能は「新規起動と既存インスタンスの設定変更」をブロックするものであり、すでにIMDSv1が有効な状態で稼働中のインスタンスには影響しません。既存インスタンスのIMDS設定を変更するには modify-instance-metadata-options を個別に実行する必要があります。

「うちの環境はもう全部IMDSv2だから大丈夫」と思っていても、開発者が新しいインスタンスを立てるときに何かの拍子でIMDSv1を有効にしてしまう可能性はゼロではありません。httpTokensEnforced はそういった「うっかり」を防ぐ仕組みです。セキュリティは最後のひと押しが大事だと思います。