[UPDATE] IMDSv2を強制するIAMポリシーを検証してみた #reinvent
こんにちは、臼田です。
みなさん、IAMポリシー絞ってますか?(挨拶
今回はre:Invent2019周辺で発表されたIMDSv2(インスタンスメタデータサービスv2)の機能について調査した内容を共有します。IMDSv2ってなんぞやという方は下記をご参照ください。
[待望のアプデ]EC2インスタンスメタデータサービスv2がリリースされてSSRF脆弱性等への攻撃に対するセキュリティが強化されました!
IMDSv2を強制するIAMポリシー
下記ユーザーガイドにて新規のEC2インスタンスを作成する際にIMDSv2を強制するIAMポリシーについて記載があります。
Configuring the Instance Metadata Service - Amazon Elastic Compute Cloud
このポリシーはユーザーやロール等に対して適用され、ポリシーが割り当てられたIAMに対してのみ強制することができます。現状ではアカウントに対して一律で強制する手法が無いことに注意してください。
動作の具体的な内容としてはec2:MetadataHttpTokens
というコンディションが新しく追加されたため、これをrequired
に設定していない場合の起動をDeny
している形となります。
やってみた
実際にやってみます。
ポリシー作成
作成するポリシーは下記のとおりです。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowAllRunInstances", "Effect": "Allow", "Action": "ec2:RunInstances", "Resource": "*" }, { "Sid": "DenyIfImdsV2IsNotUsed", "Effect": "Deny", "Action": "ec2:RunInstances", "Resource": "arn:aws:ec2:*:*:instance/*", "Condition": { "StringNotLike": { "ec2:MetadataHttpTokens": "required" } } } ] }
2019/12/23時点では上述したユーザーガイドとは内容が異なりますが、ユーザーガイドの内容ではうまく動作しなかったためサポートへ問い合わせて、正しく動くポリシーについて共有いただきました。このポリシーで動作を確認しています。
違いは14行目のResourceについてinstanceを指定しているところです。このコンディションはinstanceリソースタイプにのみ動作するため、このような指定が必要になるようです。
作成したポリシーと、ついでにAmazonEC2ReadOnlyAccess
をアタッチしたIAMユーザー or ロールを用意します。
通常の起動
まずは普通にRunInstanceしてみます。
$ aws ec2 run-instances --image-id ami-068a6cefc24c301d2 --count 1 --instance-type t2.micro --key-name mykey --security-group-ids sg-00000000 --subnet-id subnet-00000000 An error occurred (UnauthorizedOperation) when calling the RunInstances operation: You are not authorized to perform this operation. Encoded authorization failure message: b1JDKyXInk7QvhrOZy62x6kjxLDLWB0nd5ZIl41Mn6f5gw1LwSMWlvWqZMRpBYTIz1QpEGg2gf70te4JIPeV_Z2x_L4UGttjqKxhPVT59T7Rb69jLfJF7YApAcxnth9tyvONiTTXlZ7ii7-iyyBHIxHVvW-F-OfJi3Cc-yfn-DIaZl_YXSjpcvcuPCsLbOFBF4rWuGPEFkEPOeGwko4AL5cYwwQBLZipm5zQuokQ02Dj-xY7ID4TozJz4WFbTCniU3cX0IE5XNxMZYZsPAJnUQuQnDCAlP6MTkdIePJgzwZAGIGk5lX0x2so06z83_UF9AJAZZUaMZkZnhyrJv1H-w96G5tJYzyDXZ0jn6ErnrtJkcvLfRRxWM70JKtiYE-I981cdbNf0lWIywXhe0lkUFJageP5gub365Jo8A8v9qoAAQYUkE33Ftni6kmKOHgEp-kEpFyLK0rmHihoXJ7Ec9mIPfj3Frn61MKtYUch0QRdzRFI0WkgTA-g5jcsOm3TOfmiVcK5Me1brX3kUJlBhbEVb5edFw6FLlFe2kjFHYVeIYWohln7kAVIv09UT5OWdDOarKpE88b9WXY3CWLVJPKLDLXcDSLrqzsPIksrvv9K_DJtiAS4v_5t6Az7TATl8U7ScBq2E73kY8yytWKYXpmIu7pJ7hpjWD6yrIbMhKKnhOYrE0e7LSr1I4QvB7qIc3NGGweqG0tH4Zam4r9SepgpPLTHftJsuRErAPjthRvq0R6kUxqpRWE7wiQazT5ISMmb-4acBBpO4qSRd77g9U5snXx4Lwiruc6Lr7JND9AL5xFrnmg
失敗しました。想定どおりです。
ちなみに失敗したログを読むにはsts:DecodeAuthorizationMessage
権限が必要になります。詳細は下記を参照。
IMDSv2強制起動
それではIMDSv2を必須にして起動してみます。
$ aws ec2 run-instances --image-id ami-068a6cefc24c301d2 --count 1 --instance-type t2.micro --key-name mykey --security-group-ids sg-00000000 --subnet-id subnet-00000000 --metadata-options HttpTokens=required,HttpEndpoint=enabled { "Groups": [], "Instances": [ { "AmiLaunchIndex": 0, "ImageId": "ami-068a6cefc24c301d2", "InstanceId": "i-00xxxxxxxxxxxxxxx", "InstanceType": "t2.micro", "KeyName": "mykey", "LaunchTime": "2019-12-22T21:36:46.000Z", ...省略... "MetadataOptions": { "State": "pending", "HttpTokens": "required", "HttpPutResponseHopLimit": 1, "HttpEndpoint": "enabled" } } ], "OwnerId": "000000000000", "ReservationId": "r-0xxxxxxxxxxxxxxx" }
無事起動しました。
--metadata-options
では、modify-instance-metadata-options
と同じようにHttpTokens=required
だけでなくHttpEndpoint=enabled
も必要になる点が注意です。
起動したインスタンスにアクセスしてみる
無事起動できたので、インスタンスにアクセスしてみました。
$ ssh -i ~/.ssh/mykey.pem ec2-user@54.92.124.85 ec2-user@54.92.124.85: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
アクセスができませんでした。通常ならローカル側keyの設定による問題であることが多いですが、コンソールから起動した同じAMIの別インスタンスでは問題なくアクセスできました。
該当のインスタンスは最新のAmazon Linux 2を利用しています。
起動時のシステムログを確認してみます。
[ 134.892685] cloud-init[3076]: Dec 22 21:39:26 cloud-init[3076]: cc_write_metadata.py[WARNING]: there is no identity dataset [ 134.897935] cloud-init[3076]: Dec 22 21:39:26 cloud-init[3076]: util.py[WARNING]: Running module write-metadata (<module 'cloudinit.config.cc_write_metadata' from '/usr/lib/python2.7/site-packages/cloudinit/config/cc_write_metadata.pyc'>) failed Starting Hostname Service... [[32m OK [0m] Started Hostname Service. [[1;31mFAILED[0m] Failed to start Initial cloud-init job (metadata service crawler). See 'systemctl status cloud-init.service' for details.
なんとなく予想はついていましたが、起動する際にメタデータサービスへのアクセスが失敗していて、これが原因で鍵の設定が正しく行われていないようです。おそらく、まだAmazon Linux 2はIMDSv2を利用した初期起動に対応していないと考えられます。この内容もサポートへ問い合わせています。
まとめ
IMDSv2を強制したIAMポリシーについて動作検証を行いました。
強制すること自体は新しいコンディションを利用することにより実現できることを確認しました。
しかしながら、(おそらく)AMI側でも起動時のIMDSv2利用に対応していないと行けないため、この設定が利用できるタイミングはもう少し先かもしれません。別AMIでは試していないので、他のOSなどではうまく動作するかもしれません。あるいはゴールデンAMIに公開鍵を埋め込んでおけば行けるかもしれません。
現実的には起動時だけでなく稼働中にIMDSを利用するアプリケーションがIMDSv2に対応していないといけないため、すぐにこれを強制することはまだ現実的ではありません。公式ブログでもv1からv2への移行方法につて言及されており、新しくインスタンスに追加されたMetadataNoToken
というCloudWatchメトリクスをモニタリングしつつ、完全にこれがなくなってから移行することを推奨しています。
また、IMDSv2を利用することでセキュリティは向上しますが、確実にSSRF等の攻撃を防ぐことができるわけではないことも認識して利用する必要があります。詳細は徳丸先生のブログをご確認ください。
すぐにIMDSv2強制の恩恵を受けることは簡単ではありませんが、挑戦したい方は是非参考にしてください。