diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.assets.json index 501840aa00d98..75b327e1f1d67 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.assets.json @@ -1,7 +1,7 @@ { "version": "34.0.0", "files": { - "afcd88ec191e5005dcb0a7186d4d6529b8b2b1b467fb4ac395664efda42a794e": { + "7a8efad29e5cb8979aac968ca3709d9f3c874be848a2097779d79b8be52e4fd9": { "source": { "path": "aws-cdk-asg-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "afcd88ec191e5005dcb0a7186d4d6529b8b2b1b467fb4ac395664efda42a794e.json", + "objectKey": "7a8efad29e5cb8979aac968ca3709d9f3c874be848a2097779d79b8be52e4fd9.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.template.json index 2504e9f5600ee..c717d216f0346 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/aws-cdk-asg-integ.template.json @@ -888,6 +888,169 @@ "IgnoreUnmodifiedGroupSizeProperties": true } } + }, + "AsgWithIMDSv2InstanceSecurityGroupDE233317": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceSecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/AsgWithIMDSv2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "AsgWithIMDSv2InstanceRole7C239C97": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/AsgWithIMDSv2" + } + ] + } + }, + "AsgWithIMDSv2InstanceProfile0D43F696": { + "Type": "AWS::IAM::InstanceProfile", + "Properties": { + "Roles": [ + { + "Ref": "AsgWithIMDSv2InstanceRole7C239C97" + } + ] + } + }, + "AsgWithIMDSv2LaunchTemplateC4EE1BC2": { + "Type": "AWS::EC2::LaunchTemplate", + "Properties": { + "LaunchTemplateData": { + "IamInstanceProfile": { + "Arn": { + "Fn::GetAtt": [ + "AsgWithIMDSv2InstanceProfile0D43F696", + "Arn" + ] + } + }, + "ImageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amikernel510hvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "InstanceType": "t2.micro", + "MetadataOptions": { + "HttpTokens": "required" + }, + "Monitoring": { + "Enabled": false + }, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "AsgWithIMDSv2InstanceSecurityGroupDE233317", + "GroupId" + ] + } + ], + "TagSpecifications": [ + { + "ResourceType": "instance", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate" + } + ] + }, + { + "ResourceType": "volume", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate" + } + ] + } + ], + "UserData": { + "Fn::Base64": "#!/bin/bash" + } + }, + "TagSpecifications": [ + { + "ResourceType": "launch-template", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate" + } + ] + } + ] + }, + "DependsOn": [ + "AsgWithIMDSv2InstanceRole7C239C97" + ] + }, + "AsgWithIMDSv2ASGFD283CC8": { + "Type": "AWS::AutoScaling::AutoScalingGroup", + "Properties": { + "LaunchTemplate": { + "LaunchTemplateId": { + "Ref": "AsgWithIMDSv2LaunchTemplateC4EE1BC2" + }, + "Version": { + "Fn::GetAtt": [ + "AsgWithIMDSv2LaunchTemplateC4EE1BC2", + "LatestVersionNumber" + ] + } + }, + "MaxSize": "1", + "MinSize": "1", + "Tags": [ + { + "Key": "Name", + "PropagateAtLaunch": true, + "Value": "aws-cdk-asg-integ/AsgWithIMDSv2" + } + ], + "VPCZoneIdentifier": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + }, + "UpdatePolicy": { + "AutoScalingScheduledAction": { + "IgnoreUnmodifiedGroupSizeProperties": true + } + } } }, "Parameters": { @@ -903,6 +1066,10 @@ "Type": "AWS::SSM::Parameter::Value", "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2" }, + "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amikernel510hvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2" + }, "BootstrapVersion": { "Type": "AWS::SSM::Parameter::Value", "Default": "/cdk-bootstrap/hnb659fds/version", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/manifest.json index 851eee1ce9a3d..64d7772a46cc1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/afcd88ec191e5005dcb0a7186d4d6529b8b2b1b467fb4ac395664efda42a794e.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/7a8efad29e5cb8979aac968ca3709d9f3c874be848a2097779d79b8be52e4fd9.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -292,6 +292,42 @@ "data": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" } ], + "/aws-cdk-asg-integ/AsgWithIMDSv2/InstanceSecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AsgWithIMDSv2InstanceSecurityGroupDE233317" + } + ], + "/aws-cdk-asg-integ/AsgWithIMDSv2/InstanceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AsgWithIMDSv2InstanceRole7C239C97" + } + ], + "/aws-cdk-asg-integ/AsgWithIMDSv2/InstanceProfile": [ + { + "type": "aws:cdk:logicalId", + "data": "AsgWithIMDSv2InstanceProfile0D43F696" + } + ], + "/aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AsgWithIMDSv2LaunchTemplateC4EE1BC2" + } + ], + "/aws-cdk-asg-integ/AsgWithIMDSv2/ASG": [ + { + "type": "aws:cdk:logicalId", + "data": "AsgWithIMDSv2ASGFD283CC8" + } + ], + "/aws-cdk-asg-integ/SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": [ + { + "type": "aws:cdk:logicalId", + "data": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amikernel510hvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + } + ], "/aws-cdk-asg-integ/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/tree.json index 7439fd0c00c96..3c4a2f70265cc 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.js.snapshot/tree.json @@ -1404,6 +1404,273 @@ "version": "10.2.70" } }, + "AsgWithIMDSv2": { + "id": "AsgWithIMDSv2", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2", + "children": { + "InstanceSecurityGroup": { + "id": "InstanceSecurityGroup", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceSecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceSecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceSecurityGroup", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "tags": [ + { + "key": "Name", + "value": "aws-cdk-asg-integ/AsgWithIMDSv2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "InstanceRole": { + "id": "InstanceRole", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceRole", + "children": { + "ImportInstanceRole": { + "id": "ImportInstanceRole", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceRole/ImportInstanceRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-asg-integ/AsgWithIMDSv2" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "InstanceProfile": { + "id": "InstanceProfile", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/InstanceProfile", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::InstanceProfile", + "aws:cdk:cloudformation:props": { + "roles": [ + { + "Ref": "AsgWithIMDSv2InstanceRole7C239C97" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "ImportedInstanceProfile": { + "id": "ImportedInstanceProfile", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/ImportedInstanceProfile", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "LaunchTemplate": { + "id": "LaunchTemplate", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::LaunchTemplate", + "aws:cdk:cloudformation:props": { + "launchTemplateData": { + "iamInstanceProfile": { + "arn": { + "Fn::GetAtt": [ + "AsgWithIMDSv2InstanceProfile0D43F696", + "Arn" + ] + } + }, + "imageId": { + "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amikernel510hvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" + }, + "instanceType": "t2.micro", + "monitoring": { + "enabled": false + }, + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "AsgWithIMDSv2InstanceSecurityGroupDE233317", + "GroupId" + ] + } + ], + "tagSpecifications": [ + { + "resourceType": "instance", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate" + } + ] + }, + { + "resourceType": "volume", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate" + } + ] + } + ], + "userData": { + "Fn::Base64": "#!/bin/bash" + }, + "metadataOptions": { + "httpTokens": "required" + } + }, + "tagSpecifications": [ + { + "resourceType": "launch-template", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-asg-integ/AsgWithIMDSv2/LaunchTemplate" + } + ] + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "ASG": { + "id": "ASG", + "path": "aws-cdk-asg-integ/AsgWithIMDSv2/ASG", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::AutoScaling::AutoScalingGroup", + "aws:cdk:cloudformation:props": { + "launchTemplate": { + "launchTemplateId": { + "Ref": "AsgWithIMDSv2LaunchTemplateC4EE1BC2" + }, + "version": { + "Fn::GetAtt": [ + "AsgWithIMDSv2LaunchTemplateC4EE1BC2", + "LatestVersionNumber" + ] + } + }, + "maxSize": "1", + "minSize": "1", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-asg-integ/AsgWithIMDSv2", + "propagateAtLaunch": true + } + ], + "vpcZoneIdentifier": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ] + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": { + "id": "SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter", + "path": "aws-cdk-asg-integ/SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, + "SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118": { + "id": "SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118", + "path": "aws-cdk-asg-integ/SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-kernel-5.10-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.70" + } + }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "aws-cdk-asg-integ/BootstrapVersion", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.ts index ef74155fafb38..6582f6c2b5b71 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-autoscaling/test/integ.asg-lt.ts @@ -3,9 +3,11 @@ import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as cdk from 'aws-cdk-lib'; import * as autoscaling from 'aws-cdk-lib/aws-autoscaling'; +import { AUTOSCALING_GENERATE_LAUNCH_TEMPLATE } from 'aws-cdk-lib/cx-api'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-asg-integ'); +stack.node.setContext(AUTOSCALING_GENERATE_LAUNCH_TEMPLATE, true); const role = new iam.Role(stack, 'role', { assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'), @@ -101,4 +103,11 @@ new autoscaling.AutoScalingGroup(stack, 'AsgWithGp3Blockdevice', { vpc, }); +new autoscaling.AutoScalingGroup(stack, 'AsgWithIMDSv2', { + instanceType: new ec2.InstanceType('t2.micro'), + machineImage: ec2.MachineImage.latestAmazonLinux2(), + requireImdsv2: true, + vpc, +}); + app.synth(); diff --git a/packages/aws-cdk-lib/aws-autoscaling/lib/aspects/require-imdsv2-aspect.ts b/packages/aws-cdk-lib/aws-autoscaling/lib/aspects/require-imdsv2-aspect.ts index 17389e2f34d20..73e6952ecf509 100644 --- a/packages/aws-cdk-lib/aws-autoscaling/lib/aspects/require-imdsv2-aspect.ts +++ b/packages/aws-cdk-lib/aws-autoscaling/lib/aspects/require-imdsv2-aspect.ts @@ -1,5 +1,7 @@ import { IConstruct } from 'constructs'; +import { CfnLaunchTemplate, LaunchTemplate } from '../../../aws-ec2'; import * as cdk from '../../../core'; +import { AUTOSCALING_GENERATE_LAUNCH_TEMPLATE } from '../../../cx-api'; import { AutoScalingGroup } from '../auto-scaling-group'; import { CfnLaunchConfiguration } from '../autoscaling.generated'; @@ -15,16 +17,41 @@ export class AutoScalingGroupRequireImdsv2Aspect implements cdk.IAspect { return; } - const launchConfig = node.node.tryFindChild('LaunchConfig') as CfnLaunchConfiguration; - if (cdk.isResolvableObject(launchConfig.metadataOptions)) { - this.warn(node, 'CfnLaunchConfiguration.MetadataOptions field is a CDK token.'); - return; - } + if (!cdk.FeatureFlags.of(node).isEnabled(AUTOSCALING_GENERATE_LAUNCH_TEMPLATE)) { + const launchConfig = node.node.tryFindChild('LaunchConfig') as CfnLaunchConfiguration; + if (cdk.isResolvableObject(launchConfig.metadataOptions)) { + this.warn(node, 'CfnLaunchConfiguration.MetadataOptions field is a CDK token.'); + return; + } + + launchConfig.metadataOptions = { + ...launchConfig.metadataOptions, + httpTokens: 'required', + }; + } else { + const launchTemplate = node.node.tryFindChild('LaunchTemplate') as LaunchTemplate; + const cfnLaunchTemplate = launchTemplate.node.tryFindChild('Resource') as CfnLaunchTemplate; + const data = cfnLaunchTemplate.launchTemplateData; + if (cdk.isResolvableObject(data)) { + this.warn(node, 'CfnLaunchTemplate.LaunchTemplateData field is a CDK token.'); + return; + } - launchConfig.metadataOptions = { - ...launchConfig.metadataOptions, - httpTokens: 'required', - }; + const metadataOptions = (data as CfnLaunchTemplate.LaunchTemplateDataProperty).metadataOptions; + if (cdk.isResolvableObject(metadataOptions)) { + this.warn(node, 'CfnLaunchTemplate.LaunchTemplateData.MetadataOptions field is a CDK token.'); + return; + } + + const newData: CfnLaunchTemplate.LaunchTemplateDataProperty = { + ...data, + metadataOptions: { + ...metadataOptions, + httpTokens: 'required', + }, + }; + cfnLaunchTemplate.launchTemplateData = newData; + } } /** diff --git a/packages/aws-cdk-lib/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts b/packages/aws-cdk-lib/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts index 8a8835f217865..c08b5b8553d58 100644 --- a/packages/aws-cdk-lib/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts +++ b/packages/aws-cdk-lib/aws-autoscaling/test/aspects/require-imdsv2-aspect.test.ts @@ -1,6 +1,7 @@ import { Annotations, Match, Template } from '../../../assertions'; import * as ec2 from '../../../aws-ec2'; import * as cdk from '../../../core'; +import { AUTOSCALING_GENERATE_LAUNCH_TEMPLATE } from '../../../cx-api'; import { AutoScalingGroup, AutoScalingGroupRequireImdsv2Aspect, @@ -63,4 +64,101 @@ describe('AutoScalingGroupRequireImdsv2Aspect', () => { }, }); }); +}); + +describe('AutoScalingGroupRequireImdsv2Aspect with AUTOSCALING_GENERATE_LAUNCH_TEMPLATE feature flag', () => { + let app: cdk.App; + let stack: cdk.Stack; + let vpc: ec2.Vpc; + + beforeEach(() => { + app = new cdk.App(); + stack = new cdk.Stack(app, 'Stack'); + stack.node.setContext(AUTOSCALING_GENERATE_LAUNCH_TEMPLATE, true); + vpc = new ec2.Vpc(stack, 'Vpc'); + }); + + test('warns when launchTemplateData for LaunchTemplate is a token', () => { + // GIVEN + const asg = new AutoScalingGroup(stack, 'AutoScalingGroup', { + vpc, + instanceType: new ec2.InstanceType('t2.micro'), + machineImage: ec2.MachineImage.latestAmazonLinux2(), + }); + const launchTemplate = asg.node.tryFindChild('LaunchTemplate') as ec2.LaunchTemplate; + const cfnLaunchTemplate = launchTemplate.node.tryFindChild('Resource') as ec2.CfnLaunchTemplate; + cfnLaunchTemplate.launchTemplateData = cdk.Token.asAny({ + kernelId: 'asfd', + } as ec2.CfnLaunchTemplate.LaunchTemplateDataProperty); + const aspect = new AutoScalingGroupRequireImdsv2Aspect(); + + // WHEN + cdk.Aspects.of(stack).add(aspect); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', Match.not({ + LaunchTemplateData: { + KernelId: 'asfd', + MetadataOptions: { + HttpTokens: 'required', + }, + }, + })); + + Annotations.fromStack(stack).hasWarning('/Stack/AutoScalingGroup', Match.stringLikeRegexp('.*CfnLaunchTemplate.LaunchTemplateData field is a CDK token.')); + }); + + test('warns when metadataOptions for LaunchTemplate is a token', () => { + // GIVEN + const asg = new AutoScalingGroup(stack, 'AutoScalingGroup', { + vpc, + instanceType: new ec2.InstanceType('t2.micro'), + machineImage: ec2.MachineImage.latestAmazonLinux2(), + }); + const launchTemplate = asg.node.tryFindChild('LaunchTemplate') as ec2.LaunchTemplate; + const cfnLaunchTemplate = launchTemplate.node.tryFindChild('Resource') as ec2.CfnLaunchTemplate; + cfnLaunchTemplate.launchTemplateData = { + metadataOptions: cdk.Token.asAny({ + httpEndpoint: 'https://bla.com', + } as ec2.CfnLaunchTemplate.MetadataOptionsProperty), + } as ec2.CfnLaunchTemplate.LaunchTemplateDataProperty; + + const aspect = new AutoScalingGroupRequireImdsv2Aspect(); + + // WHEN + cdk.Aspects.of(stack).add(aspect); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', Match.not({ + LaunchTemplateData: { + MetadataOptions: { + HttpTokens: 'required', + }, + }, + })); + + Annotations.fromStack(stack).hasWarning('/Stack/AutoScalingGroup', Match.stringLikeRegexp('.*CfnLaunchTemplate.LaunchTemplateData.MetadataOptions field is a CDK token.')); + }); + + test('requires IMDSv2 for LaunchTemplate', () => { + // GIVEN + new AutoScalingGroup(stack, 'AutoScalingGroup', { + vpc, + instanceType: new ec2.InstanceType('t2.micro'), + machineImage: ec2.MachineImage.latestAmazonLinux2(), + }); + const aspect = new AutoScalingGroupRequireImdsv2Aspect(); + + // WHEN + cdk.Aspects.of(stack).add(aspect); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { + LaunchTemplateData: { + MetadataOptions: { + HttpTokens: 'required', + }, + }, + }); + }); }); \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/aws-cdk-lib/aws-autoscaling/test/auto-scaling-group.test.ts index e658973fc5c57..e6de1020369da 100644 --- a/packages/aws-cdk-lib/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/aws-cdk-lib/aws-autoscaling/test/auto-scaling-group.test.ts @@ -2379,6 +2379,30 @@ test('ssm permissions adds right managed policy with mixed instance policy', () }); }); +test('requires imdsv2 when @aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(AUTOSCALING_GENERATE_LAUNCH_TEMPLATE, true); + const vpc = mockVpc(stack); + + // WHEN + new autoscaling.AutoScalingGroup(stack, 'MyFleet', { + vpc, + instanceType: new ec2.InstanceType('t2.micro'), + machineImage: ec2.MachineImage.latestAmazonLinux2(), + requireImdsv2: true, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::LaunchTemplate', { + LaunchTemplateData: { + MetadataOptions: { + HttpTokens: 'required', + }, + }, + }); +}); + function mockSecurityGroup(stack: cdk.Stack) { return ec2.SecurityGroup.fromSecurityGroupId(stack, 'MySG', 'most-secure'); }