CDK BootstrapのModern templateで何が変わるのか
cdk bootstrapとは
cdk appを新しい環境(AWSアカウント x リージョン)でデプロイする際に、最初の一回だけ実行が必要なコマンドです。もう少し厳密に言うと、各環境(AWSアカウント x リージョン)にて以下いずれかに当てはまるappを初めてデプロイする際に必要になります。
- アセットを必要とするスタックがある場合
- 50キロバイトを超えるCFnテンプレートが生成される場合
- DefaultSynthesizerを使用するスタックがある場合
cdk bootstrapコマンドを実行すると、CFn(CloudFormation)スタックが作成され、cdk appのデプロイに必要な周辺リソースが作成されます。
modern (vs legacy)
cdk bootstrapで作成されるCFnスタックで使われるCFnテンプレートには大別して2種類存在します。modern templateとlegacy templateです。もともとはlegacyのみ存在していて後にmodernが登場しました。2022年2月現在はどちらも利用可能です。
この2種類のtemplateにどういう違いがあるのか、特にlegacyからmodernに変わって何が改良されたのか興味が湧いたので調べてみました。
とりあえず modern/legacy両方やってみた
cdk bootstrap --show-template
でbootstrapコマンドで作成されるCFn(CloudFormation) スタックのテンプレートが出力できます。modern/legacy版両方で出力して差分を調べてみました。cdkのバージョンは 1.142.0です。
modern版への切り替え方
CDK v1では v1.25.0以降からmodern版が利用可能ですが、legacy版がデフォルトです。(v2ではmodern版しか利用できません)
v1でmodern版を利用したい場合、以下いずれかの方法を使います。
環境変数を使う
環境変数 CDK_NEW_BOOTSTRAP
に1をセットした状態でbootstrapコマンドを実行します。
% export CDK_NEW_BOOTSTRAP=1 % cdk bootstrap --show-template > modern-bootstrap.yaml CDK_NEW_BOOTSTRAP set, using new-style bootstrapping
cdk.json
内のフィーチャーフラグをセットする
bootstrapコマンドをcdkのappのディレクトリ上で実行する場合は、そのappのcdk.json
内のフィーチャーフラグを@aws-cdk/core:newStyleStackSynthesis
をtrue
にセットする方法でもいけます。
{ "app": "npx ts-node --prefer-ts-exts bin/modern.ts", "context": { "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, "@aws-cdk/core:enableStackNameDuplicates": "true", "@aws-cdk/core:newStyleStackSynthesis": true, "aws-cdk:enableDiffNoFail": "true", "@aws-cdk/core:stackRelativeExports": "true", "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, "@aws-cdk/aws-kms:defaultKeyPolicies": true, "@aws-cdk/aws-s3:grantWriteWithoutAcl": true, "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true, "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, "@aws-cdk/aws-efs:defaultEncryptionAtRest": true, "@aws-cdk/aws-lambda:recognizeVersionProps": true, "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true } }
% npx cdk bootstrap --show-template > modern-bootstrap.yaml '@aws-cdk/core:newStyleStackSynthesis' context set, using new-style bootstrapping
というわけで両方のテンプレートを出力してみました。
legacyのテンプレート
Description: The CDK Toolkit Stack. It was created by `cdk bootstrap` and manages resources necessary for managing your Cloud Applications with AWS CDK. Conditions: UsePublicAccessBlockConfiguration: Fn::Equals: - "true" - "true" Resources: StagingBucket: Type: AWS::S3::Bucket Properties: BucketName: null AccessControl: Private BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: aws:kms KMSMasterKeyID: null PublicAccessBlockConfiguration: Fn::If: - UsePublicAccessBlockConfiguration - BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true - Ref: AWS::NoValue StagingBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: StagingBucket PolicyDocument: Id: AccessControl Version: "2012-10-17" Statement: - Sid: AllowSSLRequestsOnly Action: s3:* Effect: Deny Resource: - Fn::Sub: ${StagingBucket.Arn} - Fn::Sub: ${StagingBucket.Arn}/* Condition: Bool: aws:SecureTransport: "false" Principal: "*" Outputs: BucketName: Description: The name of the S3 bucket owned by the CDK toolkit stack Value: Ref: StagingBucket BucketDomainName: Description: The domain name of the S3 bucket owned by the CDK toolkit stack Value: Fn::GetAtt: - StagingBucket - RegionalDomainName
modernのテンプレート
Description: This stack includes resources needed to deploy AWS CDK apps into this environment Parameters: TrustedAccounts: Description: List of AWS accounts that are trusted to publish assets and deploy stacks to this environment Default: "" Type: CommaDelimitedList TrustedAccountsForLookup: Description: List of AWS accounts that are trusted to look up values in this environment Default: "" Type: CommaDelimitedList CloudFormationExecutionPolicies: Description: List of the ManagedPolicy ARN(s) to attach to the CloudFormation deployment role Default: "" Type: CommaDelimitedList FileAssetsBucketName: Description: The name of the S3 bucket used for file assets Default: "" Type: String FileAssetsBucketKmsKeyId: Description: Empty to create a new key (default), 'AWS_MANAGED_KEY' to use a managed S3 key, or the ID/ARN of an existing key. Default: "" Type: String ContainerAssetsRepositoryName: Description: A user-provided custom name to use for the container assets ECR repository Default: "" Type: String Qualifier: Description: An identifier to distinguish multiple bootstrap stacks in the same environment Default: hnb659fds Type: String AllowedPattern: "[A-Za-z0-9_-]{1,10}" ConstraintDescription: Qualifier must be an alphanumeric identifier of at most 10 characters PublicAccessBlockConfiguration: Description: Whether or not to enable S3 Staging Bucket Public Access Block Configuration Default: "true" Type: String AllowedValues: - "true" - "false" Conditions: HasTrustedAccounts: Fn::Not: - Fn::Equals: - "" - Fn::Join: - "" - Ref: TrustedAccounts HasTrustedAccountsForLookup: Fn::Not: - Fn::Equals: - "" - Fn::Join: - "" - Ref: TrustedAccountsForLookup HasCloudFormationExecutionPolicies: Fn::Not: - Fn::Equals: - "" - Fn::Join: - "" - Ref: CloudFormationExecutionPolicies HasCustomFileAssetsBucketName: Fn::Not: - Fn::Equals: - "" - Ref: FileAssetsBucketName CreateNewKey: Fn::Equals: - "" - Ref: FileAssetsBucketKmsKeyId UseAwsManagedKey: Fn::Equals: - AWS_MANAGED_KEY - Ref: FileAssetsBucketKmsKeyId HasCustomContainerAssetsRepositoryName: Fn::Not: - Fn::Equals: - "" - Ref: ContainerAssetsRepositoryName UsePublicAccessBlockConfiguration: Fn::Equals: - "true" - Ref: PublicAccessBlockConfiguration Resources: FileAssetsBucketEncryptionKey: Type: AWS::KMS::Key Properties: KeyPolicy: Statement: - Action: - kms:Create* - kms:Describe* - kms:Enable* - kms:List* - kms:Put* - kms:Update* - kms:Revoke* - kms:Disable* - kms:Get* - kms:Delete* - kms:ScheduleKeyDeletion - kms:CancelKeyDeletion - kms:GenerateDataKey Effect: Allow Principal: AWS: Ref: AWS::AccountId Resource: "*" - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: "*" Resource: "*" Condition: StringEquals: kms:CallerAccount: Ref: AWS::AccountId kms:ViaService: - Fn::Sub: s3.${AWS::Region}.amazonaws.com - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Principal: AWS: Fn::Sub: ${FilePublishingRole.Arn} Resource: "*" Condition: CreateNewKey FileAssetsBucketEncryptionKeyAlias: Condition: CreateNewKey Type: AWS::KMS::Alias Properties: AliasName: Fn::Sub: alias/cdk-${Qualifier}-assets-key TargetKeyId: Ref: FileAssetsBucketEncryptionKey StagingBucket: Type: AWS::S3::Bucket Properties: BucketName: Fn::If: - HasCustomFileAssetsBucketName - Fn::Sub: ${FileAssetsBucketName} - Fn::Sub: cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region} AccessControl: Private BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: aws:kms KMSMasterKeyID: Fn::If: - CreateNewKey - Fn::Sub: ${FileAssetsBucketEncryptionKey.Arn} - Fn::If: - UseAwsManagedKey - Ref: AWS::NoValue - Fn::Sub: ${FileAssetsBucketKmsKeyId} PublicAccessBlockConfiguration: Fn::If: - UsePublicAccessBlockConfiguration - BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true - Ref: AWS::NoValue VersioningConfiguration: Status: Enabled UpdateReplacePolicy: Retain DeletionPolicy: Retain StagingBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: StagingBucket PolicyDocument: Id: AccessControl Version: "2012-10-17" Statement: - Sid: AllowSSLRequestsOnly Action: s3:* Effect: Deny Resource: - Fn::Sub: ${StagingBucket.Arn} - Fn::Sub: ${StagingBucket.Arn}/* Condition: Bool: aws:SecureTransport: "false" Principal: "*" ContainerAssetsRepository: Type: AWS::ECR::Repository Properties: ImageScanningConfiguration: ScanOnPush: true RepositoryName: Fn::If: - HasCustomContainerAssetsRepositoryName - Fn::Sub: ${ContainerAssetsRepositoryName} - Fn::Sub: cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region} FilePublishingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: AWS::AccountId - Fn::If: - HasTrustedAccounts - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: TrustedAccounts - Ref: AWS::NoValue RoleName: Fn::Sub: cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region} Tags: - Key: aws-cdk:bootstrap-role Value: file-publishing ImagePublishingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: AWS::AccountId - Fn::If: - HasTrustedAccounts - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: TrustedAccounts - Ref: AWS::NoValue RoleName: Fn::Sub: cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region} Tags: - Key: aws-cdk:bootstrap-role Value: image-publishing LookupRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: AWS::AccountId - Fn::If: - HasTrustedAccountsForLookup - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: TrustedAccountsForLookup - Ref: AWS::NoValue - Fn::If: - HasTrustedAccounts - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: TrustedAccounts - Ref: AWS::NoValue RoleName: Fn::Sub: cdk-${Qualifier}-lookup-role-${AWS::AccountId}-${AWS::Region} ManagedPolicyArns: - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess Policies: - PolicyDocument: Statement: - Sid: DontReadSecrets Effect: Deny Action: - kms:Decrypt Resource: "*" Version: "2012-10-17" PolicyName: LookupRolePolicy Tags: - Key: aws-cdk:bootstrap-role Value: lookup FilePublishingRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - s3:GetObject* - s3:GetBucket* - FilePublishingRoleDefaultPolicy - s3:List* - s3:DeleteObject* - s3:PutObject* - s3:Abort* Resource: - Fn::Sub: ${StagingBucket.Arn} - Fn::Sub: ${StagingBucket.Arn}/* Effect: Allow - Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Effect: Allow Resource: Fn::If: - CreateNewKey - Fn::Sub: ${FileAssetsBucketEncryptionKey.Arn} - Fn::Sub: arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${FileAssetsBucketKmsKeyId} Version: "2012-10-17" Roles: - Ref: FilePublishingRole PolicyName: Fn::Sub: cdk-${Qualifier}-file-publishing-role-default-policy-${AWS::AccountId}-${AWS::Region} ImagePublishingRoleDefaultPolicy: Type: AWS::IAM::Policy Properties: PolicyDocument: Statement: - Action: - ecr:PutImage - ecr:InitiateLayerUpload - ecr:UploadLayerPart - ecr:CompleteLayerUpload - ecr:BatchCheckLayerAvailability - ecr:DescribeRepositories - ecr:DescribeImages - ecr:BatchGetImage - ecr:GetDownloadUrlForLayer Resource: Fn::Sub: ${ContainerAssetsRepository.Arn} Effect: Allow - Action: - ecr:GetAuthorizationToken Resource: "*" Effect: Allow Version: "2012-10-17" Roles: - Ref: ImagePublishingRole PolicyName: Fn::Sub: cdk-${Qualifier}-image-publishing-role-default-policy-${AWS::AccountId}-${AWS::Region} DeploymentActionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: AWS::AccountId - Fn::If: - HasTrustedAccounts - Action: sts:AssumeRole Effect: Allow Principal: AWS: Ref: TrustedAccounts - Ref: AWS::NoValue Policies: - PolicyDocument: Statement: - Sid: CloudFormationPermissions Effect: Allow Action: - cloudformation:CreateChangeSet - cloudformation:DeleteChangeSet - cloudformation:DescribeChangeSet - cloudformation:DescribeStacks - cloudformation:ExecuteChangeSet - cloudformation:CreateStack - cloudformation:UpdateStack Resource: "*" - Sid: PipelineCrossAccountArtifactsBucket Effect: Allow Action: - s3:GetObject* - s3:GetBucket* - s3:List* - s3:Abort* - s3:DeleteObject* - s3:PutObject* Resource: "*" Condition: StringNotEquals: s3:ResourceAccount: Ref: AWS::AccountId - Sid: PipelineCrossAccountArtifactsKey Effect: Allow Action: - kms:Decrypt - kms:DescribeKey - kms:Encrypt - kms:ReEncrypt* - kms:GenerateDataKey* Resource: "*" Condition: StringEquals: kms:ViaService: Fn::Sub: s3.${AWS::Region}.amazonaws.com - Action: iam:PassRole Resource: Fn::Sub: ${CloudFormationExecutionRole.Arn} Effect: Allow - Sid: CliPermissions Action: - cloudformation:DescribeStackEvents - cloudformation:GetTemplate - cloudformation:DeleteStack - cloudformation:UpdateTerminationProtection - sts:GetCallerIdentity Resource: "*" Effect: Allow - Sid: CliStagingBucket Effect: Allow Action: - s3:GetObject* - s3:GetBucket* - s3:List* Resource: - Fn::Sub: ${StagingBucket.Arn} - Fn::Sub: ${StagingBucket.Arn}/* - Sid: ReadVersion Effect: Allow Action: - ssm:GetParameter Resource: - Fn::Sub: arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter${CdkBootstrapVersion} Version: "2012-10-17" PolicyName: default RoleName: Fn::Sub: cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region} Tags: - Key: aws-cdk:bootstrap-role Value: deploy CloudFormationExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: cloudformation.amazonaws.com Version: "2012-10-17" ManagedPolicyArns: Fn::If: - HasCloudFormationExecutionPolicies - Ref: CloudFormationExecutionPolicies - Fn::If: - HasTrustedAccounts - Ref: AWS::NoValue - - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess RoleName: Fn::Sub: cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region} CdkBootstrapVersion: Type: AWS::SSM::Parameter Properties: Type: String Name: Fn::Sub: /cdk-bootstrap/${Qualifier}/version Value: "10" Outputs: BucketName: Description: The name of the S3 bucket owned by the CDK toolkit stack Value: Fn::Sub: ${StagingBucket} BucketDomainName: Description: The domain name of the S3 bucket owned by the CDK toolkit stack Value: Fn::Sub: ${StagingBucket.RegionalDomainName} FileAssetKeyArn: Description: The ARN of the KMS key used to encrypt the asset bucket (deprecated) Value: Fn::If: - CreateNewKey - Fn::Sub: ${FileAssetsBucketEncryptionKey.Arn} - Fn::Sub: ${FileAssetsBucketKmsKeyId} Export: Name: Fn::Sub: CdkBootstrap-${Qualifier}-FileAssetKeyArn ImageRepositoryName: Description: The name of the ECR repository which hosts docker image assets Value: Fn::Sub: ${ContainerAssetsRepository} BootstrapVersion: Description: The version of the bootstrap resources that are currently mastered in this stack Value: Fn::GetAtt: - CdkBootstrapVersion - Value
diff
diffも取ってみました。
--- bootstrap-template-legacy.yaml 2022-01-28 15:54:29.000000000 +0900 +++ bootstrap-template-modern.yaml 2022-01-28 18:41:30.000000000 +0900 @@ -1,20 +1,168 @@ -Description: The CDK Toolkit Stack. It was created by `cdk bootstrap` and manages resources necessary for managing your Cloud Applications with AWS CDK. +Description: This stack includes resources needed to deploy AWS CDK apps into this environment +Parameters: + TrustedAccounts: + Description: List of AWS accounts that are trusted to publish assets and deploy stacks to this environment + Default: "" + Type: CommaDelimitedList + TrustedAccountsForLookup: + Description: List of AWS accounts that are trusted to look up values in this environment + Default: "" + Type: CommaDelimitedList + CloudFormationExecutionPolicies: + Description: List of the ManagedPolicy ARN(s) to attach to the CloudFormation deployment role + Default: "" + Type: CommaDelimitedList + FileAssetsBucketName: + Description: The name of the S3 bucket used for file assets + Default: "" + Type: String + FileAssetsBucketKmsKeyId: + Description: Empty to create a new key (default), 'AWS_MANAGED_KEY' to use a managed S3 key, or the ID/ARN of an existing key. + Default: "" + Type: String + ContainerAssetsRepositoryName: + Description: A user-provided custom name to use for the container assets ECR repository + Default: "" + Type: String + Qualifier: + Description: An identifier to distinguish multiple bootstrap stacks in the same environment + Default: hnb659fds + Type: String + AllowedPattern: "[A-Za-z0-9_-]{1,10}" + ConstraintDescription: Qualifier must be an alphanumeric identifier of at most 10 characters + PublicAccessBlockConfiguration: + Description: Whether or not to enable S3 Staging Bucket Public Access Block Configuration + Default: "true" + Type: String + AllowedValues: + - "true" + - "false" Conditions: + HasTrustedAccounts: + Fn::Not: + - Fn::Equals: + - "" + - Fn::Join: + - "" + - Ref: TrustedAccounts + HasTrustedAccountsForLookup: + Fn::Not: + - Fn::Equals: + - "" + - Fn::Join: + - "" + - Ref: TrustedAccountsForLookup + HasCloudFormationExecutionPolicies: + Fn::Not: + - Fn::Equals: + - "" + - Fn::Join: + - "" + - Ref: CloudFormationExecutionPolicies + HasCustomFileAssetsBucketName: + Fn::Not: + - Fn::Equals: + - "" + - Ref: FileAssetsBucketName + CreateNewKey: + Fn::Equals: + - "" + - Ref: FileAssetsBucketKmsKeyId + UseAwsManagedKey: + Fn::Equals: + - AWS_MANAGED_KEY + - Ref: FileAssetsBucketKmsKeyId + HasCustomContainerAssetsRepositoryName: + Fn::Not: + - Fn::Equals: + - "" + - Ref: ContainerAssetsRepositoryName UsePublicAccessBlockConfiguration: Fn::Equals: - "true" - - "true" + - Ref: PublicAccessBlockConfiguration Resources: + FileAssetsBucketEncryptionKey: + Type: AWS::KMS::Key + Properties: + KeyPolicy: + Statement: + - Action: + - kms:Create* + - kms:Describe* + - kms:Enable* + - kms:List* + - kms:Put* + - kms:Update* + - kms:Revoke* + - kms:Disable* + - kms:Get* + - kms:Delete* + - kms:ScheduleKeyDeletion + - kms:CancelKeyDeletion + - kms:GenerateDataKey + Effect: Allow + Principal: + AWS: + Ref: AWS::AccountId + Resource: "*" + - Action: + - kms:Decrypt + - kms:DescribeKey + - kms:Encrypt + - kms:ReEncrypt* + - kms:GenerateDataKey* + Effect: Allow + Principal: + AWS: "*" + Resource: "*" + Condition: + StringEquals: + kms:CallerAccount: + Ref: AWS::AccountId + kms:ViaService: + - Fn::Sub: s3.${AWS::Region}.amazonaws.com + - Action: + - kms:Decrypt + - kms:DescribeKey + - kms:Encrypt + - kms:ReEncrypt* + - kms:GenerateDataKey* + Effect: Allow + Principal: + AWS: + Fn::Sub: ${FilePublishingRole.Arn} + Resource: "*" + Condition: CreateNewKey + FileAssetsBucketEncryptionKeyAlias: + Condition: CreateNewKey + Type: AWS::KMS::Alias + Properties: + AliasName: + Fn::Sub: alias/cdk-${Qualifier}-assets-key + TargetKeyId: + Ref: FileAssetsBucketEncryptionKey StagingBucket: Type: AWS::S3::Bucket Properties: - BucketName: null + BucketName: + Fn::If: + - HasCustomFileAssetsBucketName + - Fn::Sub: ${FileAssetsBucketName} + - Fn::Sub: cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region} AccessControl: Private BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: aws:kms - KMSMasterKeyID: null + KMSMasterKeyID: + Fn::If: + - CreateNewKey + - Fn::Sub: ${FileAssetsBucketEncryptionKey.Arn} + - Fn::If: + - UseAwsManagedKey + - Ref: AWS::NoValue + - Fn::Sub: ${FileAssetsBucketKmsKeyId} PublicAccessBlockConfiguration: Fn::If: - UsePublicAccessBlockConfiguration @@ -23,6 +171,10 @@ IgnorePublicAcls: true RestrictPublicBuckets: true - Ref: AWS::NoValue + VersioningConfiguration: + Status: Enabled + UpdateReplacePolicy: Retain + DeletionPolicy: Retain StagingBucketPolicy: Type: AWS::S3::BucketPolicy Properties: @@ -42,15 +194,311 @@ Bool: aws:SecureTransport: "false" Principal: "*" + ContainerAssetsRepository: + Type: AWS::ECR::Repository + Properties: + ImageScanningConfiguration: + ScanOnPush: true + RepositoryName: + Fn::If: + - HasCustomContainerAssetsRepositoryName + - Fn::Sub: ${ContainerAssetsRepositoryName} + - Fn::Sub: cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region} + FilePublishingRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: AWS::AccountId + - Fn::If: + - HasTrustedAccounts + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: TrustedAccounts + - Ref: AWS::NoValue + RoleName: + Fn::Sub: cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: aws-cdk:bootstrap-role + Value: file-publishing + ImagePublishingRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: AWS::AccountId + - Fn::If: + - HasTrustedAccounts + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: TrustedAccounts + - Ref: AWS::NoValue + RoleName: + Fn::Sub: cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: aws-cdk:bootstrap-role + Value: image-publishing + LookupRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: AWS::AccountId + - Fn::If: + - HasTrustedAccountsForLookup + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: TrustedAccountsForLookup + - Ref: AWS::NoValue + - Fn::If: + - HasTrustedAccounts + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: TrustedAccounts + - Ref: AWS::NoValue + RoleName: + Fn::Sub: cdk-${Qualifier}-lookup-role-${AWS::AccountId}-${AWS::Region} + ManagedPolicyArns: + - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess + Policies: + - PolicyDocument: + Statement: + - Sid: DontReadSecrets + Effect: Deny + Action: + - kms:Decrypt + Resource: "*" + Version: "2012-10-17" + PolicyName: LookupRolePolicy + Tags: + - Key: aws-cdk:bootstrap-role + Value: lookup + FilePublishingRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - s3:GetObject* + - s3:GetBucket* + - FilePublishingRoleDefaultPolicy + - s3:List* + - s3:DeleteObject* + - s3:PutObject* + - s3:Abort* + Resource: + - Fn::Sub: ${StagingBucket.Arn} + - Fn::Sub: ${StagingBucket.Arn}/* + Effect: Allow + - Action: + - kms:Decrypt + - kms:DescribeKey + - kms:Encrypt + - kms:ReEncrypt* + - kms:GenerateDataKey* + Effect: Allow + Resource: + Fn::If: + - CreateNewKey + - Fn::Sub: ${FileAssetsBucketEncryptionKey.Arn} + - Fn::Sub: arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${FileAssetsBucketKmsKeyId} + Version: "2012-10-17" + Roles: + - Ref: FilePublishingRole + PolicyName: + Fn::Sub: cdk-${Qualifier}-file-publishing-role-default-policy-${AWS::AccountId}-${AWS::Region} + ImagePublishingRoleDefaultPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - ecr:PutImage + - ecr:InitiateLayerUpload + - ecr:UploadLayerPart + - ecr:CompleteLayerUpload + - ecr:BatchCheckLayerAvailability + - ecr:DescribeRepositories + - ecr:DescribeImages + - ecr:BatchGetImage + - ecr:GetDownloadUrlForLayer + Resource: + Fn::Sub: ${ContainerAssetsRepository.Arn} + Effect: Allow + - Action: + - ecr:GetAuthorizationToken + Resource: "*" + Effect: Allow + Version: "2012-10-17" + Roles: + - Ref: ImagePublishingRole + PolicyName: + Fn::Sub: cdk-${Qualifier}-image-publishing-role-default-policy-${AWS::AccountId}-${AWS::Region} + DeploymentActionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: AWS::AccountId + - Fn::If: + - HasTrustedAccounts + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + Ref: TrustedAccounts + - Ref: AWS::NoValue + Policies: + - PolicyDocument: + Statement: + - Sid: CloudFormationPermissions + Effect: Allow + Action: + - cloudformation:CreateChangeSet + - cloudformation:DeleteChangeSet + - cloudformation:DescribeChangeSet + - cloudformation:DescribeStacks + - cloudformation:ExecuteChangeSet + - cloudformation:CreateStack + - cloudformation:UpdateStack + Resource: "*" + - Sid: PipelineCrossAccountArtifactsBucket + Effect: Allow + Action: + - s3:GetObject* + - s3:GetBucket* + - s3:List* + - s3:Abort* + - s3:DeleteObject* + - s3:PutObject* + Resource: "*" + Condition: + StringNotEquals: + s3:ResourceAccount: + Ref: AWS::AccountId + - Sid: PipelineCrossAccountArtifactsKey + Effect: Allow + Action: + - kms:Decrypt + - kms:DescribeKey + - kms:Encrypt + - kms:ReEncrypt* + - kms:GenerateDataKey* + Resource: "*" + Condition: + StringEquals: + kms:ViaService: + Fn::Sub: s3.${AWS::Region}.amazonaws.com + - Action: iam:PassRole + Resource: + Fn::Sub: ${CloudFormationExecutionRole.Arn} + Effect: Allow + - Sid: CliPermissions + Action: + - cloudformation:DescribeStackEvents + - cloudformation:GetTemplate + - cloudformation:DeleteStack + - cloudformation:UpdateTerminationProtection + - sts:GetCallerIdentity + Resource: "*" + Effect: Allow + - Sid: CliStagingBucket + Effect: Allow + Action: + - s3:GetObject* + - s3:GetBucket* + - s3:List* + Resource: + - Fn::Sub: ${StagingBucket.Arn} + - Fn::Sub: ${StagingBucket.Arn}/* + - Sid: ReadVersion + Effect: Allow + Action: + - ssm:GetParameter + Resource: + - Fn::Sub: arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter${CdkBootstrapVersion} + Version: "2012-10-17" + PolicyName: default + RoleName: + Fn::Sub: cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region} + Tags: + - Key: aws-cdk:bootstrap-role + Value: deploy + CloudFormationExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: cloudformation.amazonaws.com + Version: "2012-10-17" + ManagedPolicyArns: + Fn::If: + - HasCloudFormationExecutionPolicies + - Ref: CloudFormationExecutionPolicies + - Fn::If: + - HasTrustedAccounts + - Ref: AWS::NoValue + - - Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess + RoleName: + Fn::Sub: cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region} + CdkBootstrapVersion: + Type: AWS::SSM::Parameter + Properties: + Type: String + Name: + Fn::Sub: /cdk-bootstrap/${Qualifier}/version + Value: "10" Outputs: BucketName: Description: The name of the S3 bucket owned by the CDK toolkit stack Value: - Ref: StagingBucket + Fn::Sub: ${StagingBucket} BucketDomainName: Description: The domain name of the S3 bucket owned by the CDK toolkit stack Value: + Fn::Sub: ${StagingBucket.RegionalDomainName} + FileAssetKeyArn: + Description: The ARN of the KMS key used to encrypt the asset bucket (deprecated) + Value: + Fn::If: + - CreateNewKey + - Fn::Sub: ${FileAssetsBucketEncryptionKey.Arn} + - Fn::Sub: ${FileAssetsBucketKmsKeyId} + Export: + Name: + Fn::Sub: CdkBootstrap-${Qualifier}-FileAssetKeyArn + ImageRepositoryName: + Description: The name of the ECR repository which hosts docker image assets + Value: + Fn::Sub: ${ContainerAssetsRepository} + BootstrapVersion: + Description: The version of the bootstrap resources that are currently mastered in this stack + Value: Fn::GetAtt: - - StagingBucket - - RegionalDomainName + - CdkBootstrapVersion + - Value
ざっくりわかることは…Modern版の方がかなりテンプレートが大きく、作るリソースの種類が多いですね。
Resources
legacyで作成されるリソースは以下2つだけです。
- AWS::S3::Bucket
- AWS::S3::BucketPolicy
対してmodernには上記に加えて以下リソースが作成されます。
- AWS::SSM::Parameter
- AWS::IAM::Role 5つ
- AWS::ECR::Repository
- AWS::IAM::Policy 2つ
また条件次第で以下も作成されます。
- AWS::KMS::Key
- AWS::KMS::Alias
Outputs
新たに作られたKMSキーやECRリポジトリの情報が追加されています。またBootstrapVersion
なる項目もあります。
Parameters
legacyにはParametersはゼロですが、modernには8個あります。
結局 modern templateになって何が良くなるの?
ここまで書いておいてなんですが、正直テンプレートの差分自体はどうでも良いですよね。重要なのはこういった差分によって得られるメリットです。
デプロイ実行時の権限が分離される
legacyの場合、cdk appをcdk deploy
コマンドにて(CFnを介して)デプロイする際に使われる権限は、コマンドを実行したエンティティの権限です。aws sts get-caller-identity
コマンドで確認できるやつですね。
対してmodernではbootstrapスタックがプロビジョニングされたときに指定されたアクセス許可を使用してデプロイします。modern templateの中にIAM Roleが5つあると先程ご紹介しました。これが使われます。各ロールの詳細を説明します。
DeploymentActionRole
cdk deploy
などのcdkコマンドを打つと基本的にこのロールにassume roleしてからAWS上の操作を行なうようです。「基本的に」というのは、他のロールの責務外の箇所全部、という意味です。
CloudFormationExecutionRole
CDKはCFnテンプレートを生成してそのテンプレートをCFnに食わせて各リソースを作成するツールですが、CFnがリソースを作成する際に使われるロールです。以下で紹介されているIAM Roleを介してCFnを実行するやつです。
なお、これを実現するために、先のDeploymentActionRoleにCloudFormationExecutionRoleに対してのiam:PassRole
が許可されています。
また、このCloudFormationExecutionRoleは各リソースを作成する際に使われるロールですので、デフォルトではAdministratorAccessポリシーがアタッチされます。が、cdk bootstrap
コマンドの--cloudformation-execution-policies
で別のポリシーのARNを指定すれば上書きすることが可能です。
LookupRole
以下エントリで使われているVPC ConstructのfromLookup
static methodのようなfromLookup
メソッドを使う場合に使われるロールです。
各種fromLookup
メソッドは既存リソースを参照する際に使われるメソッドなので、このロールにはReadOnlyAccessマネージドポリシーがアタッチされます。
ImagePublishingRole
modern templateで作成されるECRリポジトリにアクセスするのに使われます。このECRリポジトリが使われるのは、cdk appの中でコンテナイメージをbuild、pushするような処理が必要な場合です。例えば以下のコードのような、特定のディレクトリ以下にあるDockerfileとソースコードを基にコンテナイメージを作り、それをLambda関数にするような場合です。
const getMovieFunction = new lambda.DockerImageFunction(this, 'getMovieFunction',{ functionName: 'getMovieFunction', code: lambda.DockerImageCode.fromImageAsset(path.join(__dirname, '../../src/movie-service'), { cmd: [ "get.get" ], entrypoint: ["/lambda-entrypoint.sh"], }), environment: { DYNAMODB_TABLE: this.table.tableName }, });
以下は、上記とほぼ同じコードを使って cdk deploy -v
した際の出力の一部です。最初の行でImagePublishingRole(にて作成されたロール)にassume roleしてから、docker login
でECRレジストリにログインし、コンテナイメージをビルドし、タグ付けしプッシュ、ということが行われていることがわかるかと思います。
Assuming role 'arn:aws:iam::123456789012:role/cdk-hnb659fds-image-publishing-role-123456789012-us-east-1'. [75%] check: Check 123456789012.dkr.ecr.us-east-1.amazonaws.com/cdk-hnb659fds-container-assets-123456789012-us-east-1:82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 Call failed: describeImages({"repositoryName":"cdk-hnb659fds-container-assets-123456789012-us-east-1","imageIds":[{"imageTag":"82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072"}]}) => The image with imageId {imageDigest:'null', imageTag:'82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072'} does not exist within the repository with name 'cdk-hnb659fds-container-assets-123456789012-us-east-1' in the registry with id '123456789012' (code=ImageNotFoundException) [75%] debug: docker login --username AWS --password-stdin https://123456789012.dkr.ecr.us-east-1.amazonaws.com [75%] debug: docker inspect cdkasset-82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 [75%] build: Building Docker image at /Users/kazue.masaki/hoge/cdk.out/asset.82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 [75%] debug: docker build --tag cdkasset-82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 . #1 [internal] load build definition from Dockerfile #1 sha256:f5f55ee88cf1c382b262f8e025d176d52d1b777c3d1930e1c8d3d5e203b90630 #1 transferring dockerfile: 331B done #1 DONE 0.0s #2 [internal] load .dockerignore #2 sha256:5c5f981b13a8392382ffe9c1ddd1e354f5922dc3974bab6702b3192231cade5d #2 transferring context: 2B done #2 DONE 0.0s #3 [internal] load metadata for public.ecr.aws/lambda/nodejs:12 #3 sha256:dffa778413db7fcfd0635689e67ed302cfc55e499bb3ec3f18f4be6f2c6d3375 #3 DONE 4.0s #5 [internal] load build context #5 sha256:f9b9c5c3c155c2d102874b2358df3cc2c54577508df465af93efbe31b9290404 #5 transferring context: 3.10kB 0.0s done #5 DONE 0.0s #4 [1/3] FROM public.ecr.aws/lambda/nodejs:12@sha256:0eb5179d02a6d6e095c048f752dd33a75263cf4136ced8787a83737228dc2354 #4 sha256:2d07cc1648b3d1bb43e4ec6303cc94d300c65d66aa31f384dcca620041a2bfd8 #4 resolve public.ecr.aws/lambda/nodejs:12@sha256:0eb5179d02a6d6e095c048f752dd33a75263cf4136ced8787a83737228dc2354 done #4 sha256:0eb5179d02a6d6e095c048f752dd33a75263cf4136ced8787a83737228dc2354 772B / 772B done #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 0B / 102.54MB 0.1s #4 sha256:0de26daf261e48dbc00f77c5fca094fefb2688e51d9dfc254e62da61caabf73a 0B / 81.51kB 0.1s #4 sha256:c8880dcd4d4b595529cb48f73e39f9bda467a3fde8314e175bbc20db3e70d5e8 1.58kB / 1.58kB done #4 sha256:42e1ffbbf5228b97e5bcbae3ac164b665f015c0ad1a6beb618abb37a0d827172 3.12kB / 3.12kB done #4 sha256:0bd3404121966a38ff947eb711f2c1bd8ce9f3313ec50467acce079b545c8fd8 0B / 417B 0.1s #4 sha256:0de26daf261e48dbc00f77c5fca094fefb2688e51d9dfc254e62da61caabf73a 81.51kB / 81.51kB 0.9s done #4 sha256:ba3917f372fcb5f0400ef2e67fa308141dea840c07dd7cc3e3e4ef691d1b2a0b 0B / 2.11MB 1.0s #4 sha256:0bd3404121966a38ff947eb711f2c1bd8ce9f3313ec50467acce079b545c8fd8 417B / 417B 1.1s done #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 0B / 36.29MB 1.3s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 5.24MB / 102.54MB 2.3s #4 sha256:ba3917f372fcb5f0400ef2e67fa308141dea840c07dd7cc3e3e4ef691d1b2a0b 1.05MB / 2.11MB 2.4s #4 sha256:ba3917f372fcb5f0400ef2e67fa308141dea840c07dd7cc3e3e4ef691d1b2a0b 2.11MB / 2.11MB 2.4s done #4 sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 0B / 9.26MB 2.5s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 11.53MB / 102.54MB 2.6s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 3.15MB / 36.29MB 2.9s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 17.83MB / 102.54MB 3.1s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 9.44MB / 36.29MB 3.1s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 13.63MB / 36.29MB 3.3s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 23.07MB / 102.54MB 3.5s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 15.73MB / 36.29MB 3.6s #4 sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 1.05MB / 9.26MB 3.6s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 28.31MB / 102.54MB 3.7s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 17.83MB / 36.29MB 3.7s #4 sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 2.10MB / 9.26MB 3.7s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 22.02MB / 36.29MB 3.9s #4 sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 5.24MB / 9.26MB 3.9s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 27.26MB / 36.29MB 4.2s #4 sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 9.26MB / 9.26MB 4.2s done #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 33.55MB / 102.54MB 4.3s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 34.60MB / 36.29MB 4.5s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 41.94MB / 102.54MB 4.7s #4 sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 36.29MB / 36.29MB 4.7s done #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 47.19MB / 102.54MB 5.2s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 53.48MB / 102.54MB 5.6s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 61.87MB / 102.54MB 5.9s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 69.21MB / 102.54MB 6.2s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 74.45MB / 102.54MB 6.5s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 80.74MB / 102.54MB 6.8s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 85.98MB / 102.54MB 7.1s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 92.27MB / 102.54MB 7.4s #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 100.66MB / 102.54MB 7.9s #4 extracting sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 #4 sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 102.54MB / 102.54MB 8.0s done #4 extracting sha256:d4bbef92ccd41b6a71f82c32c66da512dff174187c784d4322aabe5d47244bb9 2.9s done #4 extracting sha256:0de26daf261e48dbc00f77c5fca094fefb2688e51d9dfc254e62da61caabf73a 0.0s done #4 extracting sha256:0bd3404121966a38ff947eb711f2c1bd8ce9f3313ec50467acce079b545c8fd8 done #4 extracting sha256:ba3917f372fcb5f0400ef2e67fa308141dea840c07dd7cc3e3e4ef691d1b2a0b #4 extracting sha256:ba3917f372fcb5f0400ef2e67fa308141dea840c07dd7cc3e3e4ef691d1b2a0b 0.1s done #4 extracting sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 0.1s #4 extracting sha256:14389da6c37f56d27f8498a2d48b3a27748bd1ffac7eb35cb7402a2da8f4a0b9 1.0s done #4 extracting sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 #4 extracting sha256:446fafb864797ce9732c47ebba7d5a15244e49a309ef70767e91b29c80d46214 0.4s done #4 DONE 13.1s #6 [2/3] COPY list.js get.js package.json package-lock.json /var/task/ #6 sha256:0b050ecc3fb54d27aa842df1719d37d753529c6ab8fcf1c4d5d56eebea0e37c7 #6 DONE 0.1s #7 [3/3] RUN npm install #7 sha256:da30c0a7d837c2c108cd1e37c1d48f998e575ce9a60c364a331ec9e66fb3536e #7 1.253 npm WARN movie-service@1.0.0 No repository field. #7 1.253 #7 1.254 added 2 packages from 9 contributors and audited 2 packages in 0.906s #7 1.255 found 0 vulnerabilities #7 1.255 #7 DONE 1.3s #8 exporting to image #8 sha256:e8c613e07b0b7ff33893b694f7759a10d42e180f2b4dc349fb57dc6b71dcab00 #8 exporting layers 0.0s done #8 writing image sha256:4bae9f552ad2d3320f5dc03cf009f229dea2565311c447b0bd4e3e100edc64a4 done #8 naming to docker.io/library/cdkasset-82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 done #8 DONE 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them [75%] upload: Push 123456789012.dkr.ecr.us-east-1.amazonaws.com/cdk-hnb659fds-container-assets-123456789012-us-east-1:82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 [75%] debug: docker tag cdkasset-82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 123456789012.dkr.ecr.us-east-1.amazonaws.com/cdk-hnb659fds-container-assets-123456789012-us-east-1:82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 [75%] debug: docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/cdk-hnb659fds-container-assets-123456789012-us-east-1:82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072 The push refers to repository [123456789012.dkr.ecr.us-east-1.amazonaws.com/cdk-hnb659fds-container-assets-123456789012-us-east-1] 7a14e98d7d59: Preparing 4c85dd7eb7a5: Preparing 72a490fbf8cd: Preparing 083dc41d458c: Preparing 1a913cc9bc55: Preparing 050f1cc9348a: Preparing 20455b74816f: Preparing 6339f48a17fc: Preparing 050f1cc9348a: Waiting 20455b74816f: Waiting 6339f48a17fc: Waiting 4c85dd7eb7a5: Pushed 7a14e98d7d59: Pushed 1a913cc9bc55: Pushed 72a490fbf8cd: Pushed 050f1cc9348a: Pushed 20455b74816f: Pushed 083dc41d458c: Pushed 6339f48a17fc: Pushed 82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072: digest: sha256:9c0ffd5e70d8d67e865f645322d44d24e24daed35d681b6e5478c5e544f22910 size: 1997 [100%] success: Published 82f1f2c7b5ab440f870dedc0ba5775be95a3d13321b872e92656245d32791072:current_account-us-east-1
FilePublishingRole
前述のImagePublishingRoleと似ていますが、こちらはS3バケットにアセットをアップロードするときに使われるロールです。コンテナイメージからではなくソースコードからLambda関数を作成する際などに使われます。(対象のS3バケットもcdk bootstrap
によって作成されます。)
割愛しますが、cdk deploy -v
コマンドを打つとImagePublishingRoleと同様このロールにassume roleしてからオブジェクトをS3にアップロードしているのがわかります。
5つのロールまとめ
クロスアカウントデプロイメントができる
cdk bootstrap
コマンドに--trust
オプションを追加して値にAWSアカウントIDを指定します。するとそのアカウントからのデプロイが可能になります。具体的には、前項で説明した各種ロールの信頼関係ポリシーに指定したアカウントIDが追加されるので、そのアカウントからassume roleできるようになってデプロイできるようになります。CDK PipelineでクロスアカウントのCI/CDパイプラインを作る際に活用できます。
また--trust-for-lookup
というオプションもあります。こちらは前項のLookupRoleの信頼関係ポリシーのみ変更するオプションです。つまりこのオプションに指定されたアカウントからは、当アカウントの既存リソースについての参照はできるけれども、デプロイはできないという状態を作れます。
改良が続けられている
modern templateは改良が続けられていて、作成されるリソースが変わったりそのプロパティが変わったりしています。更新がかかる度にそれは新しいversionとなります。modern templateの中にAWS::SSM::Parameter
つまりパラメーターストアがありましたが、このパラメーターストアには紐づくbootstrap templateのバージョン番号が格納されています。cdk appのdeploy時にこのパラメーターストアの値をチェックして、bootstrapのバージョンがそのappの要件を満たしているかチェックします。
リソース命名方法をコントロールできる
bootstrap templateを介して作成される各AWSリソースには名前にランダムな文字列が付きます。legacyではこの文字列をコントロールすることはできません。が、modernではできます。--qualifier
オプションをつけてcdk bootstrap
コマンドを実行します。先程ご紹介した modern templateにQualifier
というパラメーターがあり、ここに--qualifier
オプション値が渡されてスタックが作成されます。そしてこのQualifier
パラメーターは各bootstrapリソースの名前を決定する際に使われています。例えば以下はS3バケットを作成する部分です。
StagingBucket: Type: AWS::S3::Bucket Properties: BucketName: Fn::If: - HasCustomFileAssetsBucketName - Fn::Sub: ${FileAssetsBucketName} - Fn::Sub: cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}
なおQualifier
デフォルト値はhnb659fds
なので、これが名前に含まれるリソースが作成されます。
この機能によって、同一環境(アカウントxリージョン)に複数個のbootstrapリソースを置きたい場合に、リソース名重複エラーを避けることができます。まあそもそも同一環境に複数個のbootstrapリソースを置きたい場合はあまりなさそうな気もしますが… コンプライアンス要件的にcdk app毎に使うbootstrapリソースも完全に分けたいとか、bootstrapリソースも色々カスタマイズできるので個々のapp要件に併せてカスタマイズしたものを使いたいとかですかね。
なおcdk app側で--qualifier
オプションで名前を変えたbootstrapリソース群を使うには、Stack Constructのsynthesizer propでqualifier
を指定します。
new MyStack(this, 'MyStack', { synthesizer: new DefaultStackSynthesizer({ qualifier: 'MYQUALIFIER', }), });
もしくはcdk.json
内で@aws-cdk/core:bootstrapQualifier
を使います。
{ "app": "...", "context": { "@aws-cdk/core:bootstrapQualifier": "MYQUALIFIER" } }
バケット暗号化のキーが選べる
bootstrapで作成されるS3バケットですが、legacyだとAWS管理のKMSキーによってオブジェクトがサーバーサイド暗号化されます。modernだと以下3つの方法を選ぶことができます。
- AWS管理のKMSキー(legacyと同じ)
- 作成済みKMSキーを使う
- bootstrap内でKMSキーを作ってそれを使う
なおデフォルトはAWS管理のKMSキーです。
ガッツリカスタマイズもできる
cdk bootstrap --template my-bootstrap-template.yaml
のように--template
オプションで任意のCFnテンプレートを指定すれば、ガッツリbootstrapリソース達のカスタマイズを行なうこともできます。ただしこちらに書かれていることは守る必要があります。