ec2のインスタンスメタデータを取得するのに使用する仕組みですが
2年くらい前にv2が出ていて、セキュリティが強化されたらしいです(以下IMDSv2)
このへんの具体的な話は記事もたくさんあるので今回は特に触れませんが、これが引き起こすちょっとした問題について書きます
問題が起きる環境
ec2に起動したコンテナで起きます
現代社会においてはかなり当てはまるかと思います
起きる問題
metadata取得に失敗します
上記のドキュメントにある通り、IMDSv2はまずtokenを取得して、そのtokenを使用してmetadataを取得します
ec2の設定がデフォルトの場合、そのtoken取得に失敗します
どういうことなのか
IMDSv2のPUTリクエストにはホップ制限がかけられており、デフォルトでこの値は1になっています
そこでこちらのドキュメントに注意事項として書いてありますが
コンテナ環境では、ホップ制限が 1 の場合、コンテナへの到達は余分なネットワークホップと見なされるため、IMDSv2 応答は返されません。
ということです
回避方法
これまた書いてある通り、ec2インスタンスのホップ制限を2にします
方法としては
awsコマンドで modify-instande-metaata-options
を使用して変更する
https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-instance-metadata-options.html
起動テンプレートのAdvanced detailsで指定する
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-launch-templates.html
などがあります
一応確認してみる
kubernetes環境で試しました
適当にcurlができるpodを作成します(今回はnetshoot https://github.com/nicolaka/netshoot を使用)
podが作られたnodeのインスタンスidを取得して、metadata-optionsを確認
$ aws ec2 modify-instance-metadata-options --instance-id i-xxxxxxxxxxxxxxxxx
{
"InstanceId": "i-xxxxxxxxxxxxxxxxx",
"InstanceMetadataOptions": {
"State": "pending",
"HttpTokens": "optional",
"HttpPutResponseHopLimit": 1,
"HttpEndpoint": "enabled",
"HttpProtocolIpv6": "disabled"
}
}
"HttpPutResponseHopLimit": 1
が確認できましたので、netshootのコンテナにログインし、curlでtokenを取得してみます
bash-5.1# curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
curl: (56) Recv failure: Connection reset by peer
エラーになりました(エラーになるまで2分くらい待ちました)
HttpPutResponseHopLimitを2にします
$ aws ec2 modify-instance-metadata-options --instance-id i-xxxxxxxxxxxxxxxxx --http-put-response-hop-limit 2
{
"InstanceId": "i-xxxxxxxxxxxxxxxxx",
"InstanceMetadataOptions": {
"State": "pending",
"HttpTokens": "optional",
"HttpPutResponseHopLimit": 2,
"HttpEndpoint": "enabled",
"HttpProtocolIpv6": "disabled"
}
}
再びnetshootのコンテナからtoken取得を試みます
bash-5.1# curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
AQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX==
tokenが取得できました
確かにec2デフォルトのコンテナ環境ではIMDSv2でのtoken取得で問題があり、ホップ制限を変更することで回避できました
隠れた影響
aws-sdkはデフォルトでIMDSv2を使用していますので、IMDSv2は使ってないよ、という場合も影響を受けている場合があります
aws-sdkの場合は、最初IMDSv2で試して、失敗するとIMDSv1で取得するという流れになっているということなので、遅延が起きます
https://github.com/aws/aws-sdk-go/issues/2972
例えばaws-sdk-goの場合は大々的に遅れるようなのでこの問題には気付きやすいでしょう
https://github.com/aws/aws-sdk-php/issues/1908
aws-sdk-phpの場合は1秒とのことで、気付かないうちにパフォーマンスが悪化している、なんてことがあるかもしれません