![[アップデート] リージョンごとにデフォルトIMDSを設定できるようになりました](https://devio2023-media.developers.io/wp-content/uploads/2023/09/amazon-ec2.png)
[アップデート] リージョンごとにデフォルトIMDSを設定できるようになりました
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
IMDSv2のみに明示するのが面倒
こんにちは、のんピ(@non____97)です。
皆さんはIMDSv2のみに明示するのが面倒だなと思ったことはありますか? 私はあります。
起動するEC2インスタンスのIMDSのどのバージョンを使用するかはAMIの設定次第です。もし、IMDSのデフォルト設定が定義されていないAMIを利用する場合、IMDSv2のみとする際にはEC2インスタンス起動時に明示的に指定する必要がありました。
今回、アップデートによりリージョンごとにデフォルトのIMDSを設定できるようになりました。
事前にデフォルトのIMDSの設定をしていれば、EC2インスタンスを起動する際に都度指定する必要がなくなります。
実際に試してみたので紹介します。
いきなりまとめ
- リージョン毎にIMDSに関連する以下についてのデフォルト設定を定義できるようになった
- IMDSの有効/無効
 - IMDSのバージョン
 - メタデータでインスタンスのタグ情報のアクセス可否
 - メタデータのレスポンスホップ数の上限
 
 - いずれもデフォルト値であり、定義した値に強制するものではない
- 起動時に明示的に値を設定すれば、そちらの値が使われる
 
 - CloudFormationで設定する場合はカスタムリソースを使用する必要がある
 
やってみた
アカウント設定をしていない場合
実際に試してみます。
まずはアカウント設定をしていない場合です。
Amazon Linux 2とAmazon Linux 2023のAMIを確認します。
$ aws ec2 describe-images --image-ids ami-033a1ebf088e56e81 ami-0c101f26f147fa7fd
{
    "Images": [
        {
            "Architecture": "x86_64",
            "CreationDate": "2024-03-21T02:25:43.000Z",
            "ImageId": "ami-0c101f26f147fa7fd",
            "ImageLocation": "amazon/al2023-ami-2023.4.20240319.1-kernel-6.1-x86_64",
            "ImageType": "machine",
            "Public": true,
            "OwnerId": "137112412989",
            "PlatformDetails": "Linux/UNIX",
            "UsageOperation": "RunInstances",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/xvda",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "Iops": 3000,
                        "SnapshotId": "snap-04819fa0d2620618b",
                        "VolumeSize": 8,
                        "VolumeType": "gp3",
                        "Throughput": 125,
                        "Encrypted": false
                    }
                }
            ],
            "Description": "Amazon Linux 2023 AMI 2023.4.20240319.1 x86_64 HVM kernel-6.1",
            "EnaSupport": true,
            "Hypervisor": "xen",
            "ImageOwnerAlias": "amazon",
            "Name": "al2023-ami-2023.4.20240319.1-kernel-6.1-x86_64",
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SriovNetSupport": "simple",
            "VirtualizationType": "hvm",
            "BootMode": "uefi-preferred",
            "DeprecationTime": "2024-06-19T02:26:00.000Z",
            "ImdsSupport": "v2.0"
        },
        {
            "Architecture": "x86_64",
            "CreationDate": "2024-03-20T02:57:50.000Z",
            "ImageId": "ami-033a1ebf088e56e81",
            "ImageLocation": "amazon/amzn2-ami-kernel-5.10-hvm-2.0.20240318.0-x86_64-gp2",
            "ImageType": "machine",
            "Public": true,
            "OwnerId": "137112412989",
            "PlatformDetails": "Linux/UNIX",
            "UsageOperation": "RunInstances",
            "State": "available",
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/xvda",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-09e76fd13c67fa768",
                        "VolumeSize": 8,
                        "VolumeType": "gp2",
                        "Encrypted": false
                    }
                }
            ],
            "Description": "Amazon Linux 2 Kernel 5.10 AMI 2.0.20240318.0 x86_64 HVM gp2",
            "EnaSupport": true,
            "Hypervisor": "xen",
            "ImageOwnerAlias": "amazon",
            "Name": "amzn2-ami-kernel-5.10-hvm-2.0.20240318.0-x86_64-gp2",
            "RootDeviceName": "/dev/xvda",
            "RootDeviceType": "ebs",
            "SriovNetSupport": "simple",
            "VirtualizationType": "hvm",
            "DeprecationTime": "2025-07-01T00:00:00.000Z"
        }
    ]
}
Amazon Linux 2023の方にはImdsSupportにv2.0という設定がありますが、Amazon Linux 2にはImdsSupportというプロパティはありません。
Amazon Linux 2のAMIを使ってEC2インスタンスを起動させます。その際にメタデータのバージョンは選択の状態にしておきます。

起動してきたEC2インスタンスのIMDSを確認すると、IMDSv2がOptionalとなっていました。つまりはIMDSv2のみではありません。IMDSv1も使用できる状態です。

ちなみに、AWS CLIから確認すると、以下のとおりです。
$ aws ec2 describe-instances \
	--instance-id i-02859717ec0cd97d9 \
	--query "Reservations[*].Instances[*].MetadataOptions"
[
    [
        {
            "State": "applied",
            "HttpTokens": "optional",
            "HttpPutResponseHopLimit": 2,
            "HttpEndpoint": "enabled",
            "HttpProtocolIpv6": "disabled",
            "InstanceMetadataTags": "disabled"
        }
    ]
]
マネジメントコンソールからアカウントのデフォルトIMDSを設定
それではマネジメントコンソールからアカウントのデフォルトIMDSを設定します。
EC2のコンソールからデータ保護とセキュリティをクリックします。

デフォルトIMDSの設定を確認できました。デフォルトだと全てNo preferenceになっていますね。IMDSのバージョンだけでなく、そもそもIMDSを有効にするか、メタデータでタグ情報にアクセスさせるか、メタデータレスポンスのホップ数も指定できるようです。

管理をクリックしてMetadata versionをV2 only (token required)に変更します。

設定が変更されたことを確認します。

この状態で、先ほどと全く同じAMIと設定でAmazon Linux 2を起動します。
起動後にIMDSを確認するとIMDSv2がRequiredになっていました。やったぜ。

AWS CLIでは以下のとおりです。
$ aws ec2 describe-instances \
	--instance-id i-02399237a7d5ac8ad \
	--query "Reservations[*].Instances[*].MetadataOptions"
[
    [
        {
            "State": "applied",
            "HttpTokens": "required",
            "HttpPutResponseHopLimit": 2,
            "HttpEndpoint": "enabled",
            "HttpProtocolIpv6": "disabled",
            "InstanceMetadataTags": "disabled"
        }
    ]
]
なお、デフォルトIMDS設定はあくまでデフォルト値です。「起動時に指定したIMDSの設定とマッチしていなければ拒否する」という代物ではありません。
AMI、デフォルトIMDS設定、起動パラメーターでどのような設定をした場合に、最終的にどの値になるかは以下のとおりです。
| Launch parameter | Account level default | AMI default | Resulting instance configuration | 
|---|---|---|---|
| V2 only (token required) | No preference | V2 only | V2 only | 
| V2 only (token required) | V2 only | V2 only | V2 only | 
| V2 only (token required) | V1 or V2 | V2 only | V2 only | 
| V1 or V2 (token optional) | No preference | V2 only | V1 or V2 | 
| V1 or V2 (token optional) | V2 only | V2 only | V1 or V2 | 
| V1 or V2 (token optional) | V1 or V2 | V2 only | V1 or V2 | 
| Not set | No preference | V2 only | V2 only | 
| Not set | V2 only | V2 only | V2 only | 
| Not set | V1 or V2 | V2 only | V1 or V2 | 
| V2 only (token required) | No preference | null | V2 only | 
| V2 only (token required) | V2 only | null | V2 only | 
| V2 only (token required) | V1 or V2 | null | V2 only | 
| V1 or V2 (token optional) | No preference | null | V1 or V2 | 
| V1 or V2 (token optional) | V2 only | null | V1 or V2 | 
| V1 or V2 (token optional) | V1 or V2 | null | V1 or V2 | 
| Not set | No preference | null | V1 or V2 | 
| Not set | V2 only | null | V2 only | 
| Not set | V1 or V2 | null | V1 or V2 | 
抜粋 : Configure the instance metadata options - Amazon Elastic Compute Cloud
AWS CLIでアカウントのデフォルトIMDSを設定
もちろん、AWS CLIで設定変更することも可能です。
デフォルトIMDSの設定を確認する際にはget-instance-metadata-defaultsを叩きます。
$ aws ec2 get-instance-metadata-defaults
{
    "AccountLevel": {
        "HttpTokens": "required"
    }
}
HttpTokensがrequiredなので、IMDSv2のみがデフォルトになっていそうです。また、No preferenceの設定は出力されないようです。
デフォルトIMDSの設定を変更する際にはmodify-instance-metadata-defaultsを叩きます。
試しにIMDSの有効化と、IMDSのバージョンの指定を解除します。
$ aws ec2 modify-instance-metadata-defaults \
    --http-tokens no-preference \
    --http-endpoint enabled
{
    "Return": true
}
$ aws ec2 get-instance-metadata-defaults
{
    "AccountLevel": {
        "HttpEndpoint": "enabled"
    }
}
問題なく設定できましたね。
CloudFormation Custom ResourceでアカウントのデフォルトIMDSを設定
このデフォルトIMDSはリージョン単位の設定です。また、大量のAWSアカウントがある場合はそれを一つづつ設定するのはかなり骨が折れます。
そんな時にはCloudFormation StackSetsを使いたいとことです。
しかし、2024/3/26時点でデフォルトIMDSはCloudFormationでサポートされていません。そのため、カスタムリソースで作成をする必要があります。
AWS CDKを使ってデフォルトIMDSでIMDSv2のみを明示的に指定する場合は、以下のように定義できます。
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
export class Imdsv2Stack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    new cdk.custom_resources.AwsCustomResource(
      this,
      "ModifyInstanceMetadataDefaults",
      {
        onCreate: {
          service: "EC2",
          action: "modifyInstanceMetadataDefaults",
          parameters: {
            HttpTokens: "required",
          },
          physicalResourceId: cdk.custom_resources.PhysicalResourceId.of(
            "ModifyInstanceMetadataDefaults"
          ),
        },
        onDelete: {
          service: "EC2",
          action: "modifyInstanceMetadataDefaults",
          parameters: {
            HttpTokens: "no-preference",
          },
        },
        policy: cdk.custom_resources.AwsCustomResourcePolicy.fromStatements([
          new cdk.aws_iam.PolicyStatement({
            actions: ["ec2:ModifyInstanceMetadataDefaults"],
            resources: ["*"],
          }),
        ]),
        installLatestAwsSdk: true,
        logRetention: cdk.aws_logs.RetentionDays.ONE_WEEK,
      }
    );
  }
}
今回はinstallLatestAwsSdkをtrueと指定して、最新のAWS SDKをインストールさせています。これは裏側で作成できるLambda関数にプリインストールされているAWS SDK for JavaScript v3にはModifyInstanceMetadataDefaultsCommandがまだ存在していなかったためです。
installLatestAwsSdkをtrueにしない状態でnpx cdk deployでデプロイすると、以下のように怒られました。
18:18:13 | CREATE_FAILED        | Custom::AWS           | ModifyInstanceMetadataDefaults0E27DBD7
Received response status [FAILED] from custom resource. Message returned: Unable to find command named: ModifyInstanceMetadataDefaultsCommand for action:
ModifyInstanceMetadataDefaults in service package @aws-sdk/client-ec2 (RequestId: ca445099-6fb1-4ab0-b3b1-825ae4a38a49)
正常にデプロイが完了した場合は、以下のように"HttpTokens": "required"となっていました。"HttpEndpoint": "enabled"となっているのは先の検証の影響です。
$ aws ec2 get-instance-metadata-defaults
{
    "AccountLevel": {
        "HttpTokens": "required",
        "HttpEndpoint": "enabled"
    }
}
Lambda関数のログは以下のとおりです。AWS SDK v3をインストールした後、ModifyInstanceMetadataDefaultsCommandを叩いていそうです。
2024-03-26T19:05:16.683+09:00	INIT_START Runtime Version: nodejs:18.v24 Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:c09960ad0af4321e1a7cf013174f7c0d7169bf09af823ca2ad2f93c72ade708a
2024-03-26T19:05:16.863+09:00	START RequestId: 71f83dee-ecf7-4e2b-bd5a-da30bccca558 Version: $LATEST
2024-03-26T19:05:16.937+09:00	2024-03-26T10:05:16.937Z 71f83dee-ecf7-4e2b-bd5a-da30bccca558 INFO Installing latest AWS SDK v3: @aws-sdk/client-ec2
2024-03-26T19:07:10.695+09:00	2024-03-26T10:07:10.695Z 71f83dee-ecf7-4e2b-bd5a-da30bccca558 INFO {"RequestType":"Create","ServiceToken":"arn:aws:lambda:us-east-1:<AWSID>:function:Imdsv2Stack-AWS679f53fac002430cb0da5b7982bd22872D1-3j5lfQgw5O8A","ResponseURL":"...","StackId":"arn:aws:cloudformation:us-east-1:<AWSID>:stack/Imdsv2Stack/3ca48b50-eb58-11ee-9d41-0e3fea76f2d9","RequestId":"208d4943-a498-40a2-a6e9-2dd8ab92848f","LogicalResourceId":"ModifyInstanceMetadataDefaults0E27DBD7","ResourceType":"Custom::AWS","ResourceProperties":{"ServiceToken":"arn:aws:lambda:us-east-1:<AWSID>:function:Imdsv2Stack-AWS679f53fac002430cb0da5b7982bd22872D1-3j5lfQgw5O8A","Delete":{"service":"EC2","action":"modifyInstanceMetadataDefaults","parameters":{"HttpTokens":"no-preference"}},"InstallLatestAwsSdk":"true","Create":{"service":"EC2","action":"modifyInstanceMetadataDefaults","parameters":{"HttpTokens":"required"},"physicalResourceId":{"id":"ModifyInstanceMetadataDefaults"}}}}
2024-03-26T19:07:12.216+09:00	2024-03-26T10:07:12.216Z 71f83dee-ecf7-4e2b-bd5a-da30bccca558 INFO API response { Return: true }
2024-03-26T19:07:12.254+09:00	2024-03-26T10:07:12.254Z 71f83dee-ecf7-4e2b-bd5a-da30bccca558 INFO Responding {"Status":"SUCCESS","Reason":"OK","PhysicalResourceId":"ModifyInstanceMetadataDefaults","StackId":"arn:aws:cloudformation:us-east-1:<AWSID>:stack/Imdsv2Stack/3ca48b50-eb58-11ee-9d41-0e3fea76f2d9","RequestId":"208d4943-a498-40a2-a6e9-2dd8ab92848f","LogicalResourceId":"ModifyInstanceMetadataDefaults0E27DBD7","NoEcho":false,"Data":{"region":"us-east-1","Return":true}}
2024-03-26T19:07:12.437+09:00	END RequestId: 71f83dee-ecf7-4e2b-bd5a-da30bccca558
2024-03-26T19:07:12.437+09:00	REPORT RequestId: 71f83dee-ecf7-4e2b-bd5a-da30bccca558 Duration: 115573.00 ms Billed Duration: 115574 ms Memory Size: 128 MB Max Memory Used: 128 MB Init Duration: 178.67 ms
ちなみにStack内のリソース一覧は以下のとおりです。

npx cdk destroyでスタックを削除します。削除後にデフォルトIMDS設定を確認すると、"HttpTokens": "required"の指定が消えていました。意図したとおりです。
$ aws ec2 get-instance-metadata-defaults
{
    "AccountLevel": {
        "HttpEndpoint": "enabled"
    }
}
Lambda関数のログは以下のとおりです。
2024-03-26T19:12:24.853+09:00	START RequestId: 1355c1e9-4eba-4045-b806-44b40257dce6 Version: $LATEST
2024-03-26T19:12:25.117+09:00	2024-03-26T10:12:25.117Z 1355c1e9-4eba-4045-b806-44b40257dce6 INFO {"RequestType":"Delete","ServiceToken":"arn:aws:lambda:us-east-1:<AWSID>:function:Imdsv2Stack-AWS679f53fac002430cb0da5b7982bd22872D1-3j5lfQgw5O8A","ResponseURL":"...","StackId":"arn:aws:cloudformation:us-east-1:<AWSID>:stack/Imdsv2Stack/3ca48b50-eb58-11ee-9d41-0e3fea76f2d9","RequestId":"459c6847-e9f1-4e18-ba56-8d2355d29e7b","LogicalResourceId":"ModifyInstanceMetadataDefaults0E27DBD7","PhysicalResourceId":"ModifyInstanceMetadataDefaults","ResourceType":"Custom::AWS","ResourceProperties":{"ServiceToken":"arn:aws:lambda:us-east-1:<AWSID>:function:Imdsv2Stack-AWS679f53fac002430cb0da5b7982bd22872D1-3j5lfQgw5O8A","Delete":{"service":"EC2","action":"modifyInstanceMetadataDefaults","parameters":{"HttpTokens":"no-preference"}},"InstallLatestAwsSdk":"true","Create":{"service":"EC2","action":"modifyInstanceMetadataDefaults","parameters":{"HttpTokens":"required"},"physicalResourceId":{"id":"ModifyInstanceMetadataDefaults"}}}}
2024-03-26T19:12:25.742+09:00	2024-03-26T10:12:25.742Z 1355c1e9-4eba-4045-b806-44b40257dce6 INFO API response { Return: true }
2024-03-26T19:12:25.742+09:00	2024-03-26T10:12:25.742Z 1355c1e9-4eba-4045-b806-44b40257dce6 INFO Responding {"Status":"SUCCESS","Reason":"OK","PhysicalResourceId":"ModifyInstanceMetadataDefaults","StackId":"arn:aws:cloudformation:us-east-1:<AWSID>:stack/Imdsv2Stack/3ca48b50-eb58-11ee-9d41-0e3fea76f2d9","RequestId":"459c6847-e9f1-4e18-ba56-8d2355d29e7b","LogicalResourceId":"ModifyInstanceMetadataDefaults0E27DBD7","NoEcho":false,"Data":{"region":"us-east-1","Return":true}}
2024-03-26T19:12:25.953+09:00	END RequestId: 1355c1e9-4eba-4045-b806-44b40257dce6
2024-03-26T19:12:25.953+09:00	REPORT RequestId: 1355c1e9-4eba-4045-b806-44b40257dce6 Duration: 1099.35 ms Billed Duration: 1100 ms Memory Size: 128 MB Max Memory Used: 128 MB
IMDSv2利用促進に繋がりそう
リージョンごとにデフォルトIMDSを設定できるようになったアップデートを紹介しました。
現在ではIMDSv2のみとすることが推奨されています。こちらの設定を使うことによってデフォルトでIMDSv2のみで起動させることが可能になるため、意図せずIMDSv1を使用しているインスタンスが少なくなるのではと考えます。
IMDSv2への移行手順は以下記事が参考になります。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!






