Created
May 9, 2022 20:53
-
-
Save cagingulsen/e180ed4b10cc5baf3b636d6c42c1cb34 to your computer and use it in GitHub Desktop.
AWS CDK Bootstrap Template for Custom Bootstrapping - Version 12 - with a Permissions Boundary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
# "cdk-(qualifier)-image-publishing-role-(account)-(region)" needs to be <= 64 chars | |
# account = 12, region <= 14, 10 chars for qualifier and 28 for rest of role name | |
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'] | |
PermissionsBoundaryArn: | |
Description: ARN of the Permissions Boundary | |
Type: 'String' | |
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: | |
# Not actually everyone -- see below for Conditions | |
AWS: "*" | |
Resource: "*" | |
Condition: | |
StringEquals: | |
# See https://docs.aws.amazon.com/kms/latest/developerguide/policy-conditions.html#conditions-kms-caller-account | |
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} | |
RepositoryPolicyText: | |
Version: "2012-10-17" | |
Statement: | |
# Necessary for Lambda container images | |
# https://docs.aws.amazon.com/lambda/latest/dg/configuration-images.html#configuration-images-permissions | |
- Sid: LambdaECRImageRetrievalPolicy | |
Effect: Allow | |
Principal: { Service: "lambda.amazonaws.com" } | |
Action: | |
- ecr:BatchGetImage | |
- ecr:GetDownloadUrlForLayer | |
Condition: | |
StringLike: | |
"aws:sourceArn": { "Fn::Sub": "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:*" } | |
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} | |
PermissionsBoundary: !Ref PermissionsBoundaryArn | |
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} | |
PermissionsBoundary: !Ref PermissionsBoundaryArn | |
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} | |
PermissionsBoundary: !Ref PermissionsBoundaryArn | |
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* | |
- s3:GetEncryptionConfiguration | |
- 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 | |
# Read/write buckets in different accounts. Permissions to buckets in | |
# same account are granted by bucket policies. | |
# | |
# Write permissions necessary to write outputs to the cross-region artifact replication bucket | |
# https://aws.amazon.com/premiumsupport/knowledge-center/codepipeline-deploy-cloudformation/. | |
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 | |
# Use keys only for the purposes of reading encrypted files from S3. | |
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: | |
# Permissions needed by the CLI when doing `cdk deploy`. | |
# Our CI/CD does not need DeleteStack, | |
# but we also want to use this role from the CLI, | |
# and there you can call `cdk destroy` | |
- cloudformation:DescribeStackEvents | |
- cloudformation:GetTemplate | |
- cloudformation:DeleteStack | |
- cloudformation:UpdateTerminationProtection | |
- sts:GetCallerIdentity | |
# `cdk import` | |
- cloudformation:GetTemplateSummary | |
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} | |
PermissionsBoundary: !Ref PermissionsBoundaryArn | |
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 | |
# The CLI will prevent this case from occurring | |
- Ref: AWS::NoValue | |
# The CLI will advertise that we picked this implicitly | |
- - Fn::Sub: "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" | |
RoleName: | |
Fn::Sub: cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region} | |
PermissionsBoundary: !Ref PermissionsBoundaryArn | |
# The SSM parameter is used in pipeline-deployed templates to verify the version | |
# of the bootstrap resources. | |
CdkBootstrapVersion: | |
Type: AWS::SSM::Parameter | |
Properties: | |
Type: String | |
Name: | |
Fn::Sub: '/cdk-bootstrap/${Qualifier}/version' | |
Value: '12' | |
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}" | |
# @deprecated - This Export can be removed at some future point in time. | |
# We can't do it today because if there are stacks that use it, the bootstrap | |
# stack cannot be updated. Not used anymore by apps >= 1.60.0 | |
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}" | |
# The Output is used by the CLI to verify the version of the bootstrap resources. | |
BootstrapVersion: | |
Description: The version of the bootstrap resources that are currently mastered | |
in this stack | |
Value: | |
Fn::GetAtt: [CdkBootstrapVersion, Value] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment