IMDSv1を無効化したEC2でDatadog Agentを使うときは必ずec2_prefer_imdsv2オプションをtrueにしよう

Daichi Harada
7 min readSep 9, 2021

--

長時間ハマってしまったので、備忘録として残しておきます。

TLDR

  • IMDSv1を無効化したEC2インスタンスでDatadog Agentを動かすときにはec2_prefer_imdsv2を明示的にtrueにしないとhostの識別がうまくいかないことがあるよ

環境

  • Datadog Agent 6.30.1
  • Amazon Linux 2

そもそもIMDSv1をなぜDisableするのか

IMDS (Instance Metadata Service)はEC2インスタンス内部から叩くと自身のinstance idやらinstance profileの認証情報を取得できるエンドポイント。

[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/

通常外部からは叩けないエンドポイントだが、SSRF攻撃が可能な脆弱性があった場合、このエンドポイントを突かれるとInstance Profileの認証情報を抜かれてしまう危険性がある。( Capital Oneの事例 が有名。)

この弱点を補強したのがIMDSv2で、リクエスト前にPUTリクエストでセッショントークンを取得してから、そのトークンをヘッダにつけてリクエストしないと叩けないようになっている。

[ec2-user ~]$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \ && curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/ 

TerraformでIMDSv2のみの利用に制限し、IMDSv1を無効化したい場合は以下のように書く。(SSM AgentなどもIMDSを利用するので、IMDSv2まで完全に閉じてしまう、というユースケースは稀なのではないかと思う。)

resource "aws_instance" "imds_v2_only_enabled" {
ami = "ami-xxxxxxxxxx"
# 中略 ...
metadata_options {
http_endpoint = "enabled" # IMDS自体はenable
http_tokens = "required" # ただしToken必須=IMDSv2のみ受け付ける
}
}

※ IMDSv2を使うことの効果については、以下記事が詳しいです。

Datadog Agentはどのようにhostを一意に特定するか

こちらのドキュメントにある通り、以下のようなロジックでdatadog agentのhostnameを決定している。

  • datadog agentのconfigに明示的に指定したagent-hostname
  • hostname -f の結果 (ただしEC2のデフォルト ip-192–0–0–1 のような形式の場合、次の評価を走らせる)
  • instance-id ( IMDS のエンドポイントから取得した instance-id)
  • hostname (IMDSが利用不可の場合フォールバック)

そして、instance-idを取得する際にはデフォルトでIMDSv1を使ってホスト名を決定する挙動になっており、IMDSv2を利用するには ec2_prefer_imdsv2 オプションを明示的に true にする必要がある。

何が困るのか

IMDSv1が無効化されている && ec2_prefer_imdsv2がfalse の場合、一意性の担保できるinstance-idが読みに行けず、hostnameがインスタンスの特定に使われる。Private IPは再利用されるので、EC2のデフォルト hostname (ip-192–0–0–1 形式) は「かつて存在したがもう退役したインスタンス」と被る可能性がある。(一意性は担保されない。)

具体的な困りとしては、AWS Integration (CloudWatchのメトリクスなので正しいinstance id ) で認識されたhostと、Datadog Agentで認識されたhost (hostnameから識別し、退役したインスタンスのinstance idと関連付けられてしまう) を別物と認識してしまい、更に後者は退役したインスタンスのTag情報などを引き継いでしまう。

その結果、instance-idでdatadog側をfilterするとcloudwatchのメトリクスしか取れてなくてagentが動いてないように見えたり、

上がAWS Integrationで認識したhost, 下がDatadog Agentが認識したhost

退役したインスタンスのものとしてdatadog agent経由のメトリクスが見えてしまうのでDashboard上で古いインスタンスが生き返ったかのように見えたりする。( タグ情報は古いインスタンスの情報を誤って引き継ぎ、Datadog Agent経由のメトリクスはReportし続け、CloudWatch経由のメトリクスは取れてない、という状況になる)

生き返った風に見える (実際は全然別のインスタンス)

(正直めっちゃ困るw)

解決策

タイトル通り、IMDSv1を無効化したEC2でDatadog Agentを使うときは必ずec2_prefer_imdsv2オプションをtrueにしましょう。

--

--