diff --git a/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json b/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json index a7889b12487fd..3e5104f23e141 100644 --- a/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json +++ b/packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json @@ -419,6 +419,52 @@ "Version": "2012-10-17" } } + }, + "CodePipelineDeployChangeSetRoleDefaultPolicy289820BE": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ArtifactBucket7410C9EF", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CodePipelineDeployChangeSetRoleDefaultPolicy289820BE", + "Roles": [ + { + "Ref": "CodePipelineDeployChangeSetRoleF9F2B343" + } + ] + } } } } diff --git a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts index 98eaceb07669d..2915bd3ef270f 100644 --- a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts @@ -198,6 +198,49 @@ export = nodeunit.testCase({ PolicyDocument: { Version: '2012-10-17', Statement: [ + { + Action: [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + ], + Effect: "Allow", + Resource: [ + { + "Fn::GetAtt": [ + "CodePipelineArtifactsBucketF1E925CF", + "Arn", + ], + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "CodePipelineArtifactsBucketF1E925CF", + "Arn", + ], + }, + "/*", + ], + ], + }, + ], + }, + { + Action: [ + "kms:Decrypt", + "kms:DescribeKey", + ], + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "CodePipelineArtifactsBucketEncryptionKey85407CB4", + "Arn", + ], + }, + }, { Action: '*', Effect: 'Allow', @@ -272,6 +315,49 @@ export = nodeunit.testCase({ PolicyDocument: { Version: '2012-10-17', Statement: [ + { + Action: [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + ], + Effect: "Allow", + Resource: [ + { + "Fn::GetAtt": [ + "CodePipelineArtifactsBucketF1E925CF", + "Arn", + ], + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "CodePipelineArtifactsBucketF1E925CF", + "Arn", + ], + }, + "/*" + ], + ], + }, + ], + }, + { + Action: [ + "kms:Decrypt", + "kms:DescribeKey", + ], + Effect: "Allow", + Resource: { + "Fn::GetAtt": [ + "CodePipelineArtifactsBucketEncryptionKey85407CB4", + "Arn", + ], + }, + }, { Action: [ 'ec2:AuthorizeSecurityGroupEgress', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts index 96906bf76644d..ecbf97a6b5c5c 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts @@ -278,18 +278,19 @@ abstract class CloudFormationDeployAction extends CloudFormationAction { assumedBy: new iam.ServicePrincipal('cloudformation.amazonaws.com'), roleName: cdk.PhysicalName.GENERATE_IF_NEEDED, }); - - // the deployment role might need read access to the pipeline's bucket - // (for example, if it's deploying a Lambda function), - // and since this is cross-account, even admin permissions won't be enough - - // the pipeline's bucket must trust this role - options.bucket.grantRead(this._deploymentRole); } else { this._deploymentRole = new iam.Role(scope, 'Role', { assumedBy: new iam.ServicePrincipal('cloudformation.amazonaws.com') }); } + // the deployment role might need read access to the pipeline's bucket + // (for example, if it's deploying a Lambda function), + // and even if it has admin permissions, it won't be enough, + // as it needs to be added to the key's resource policy + // (and the bucket's, if the access is cross-account) + options.bucket.grantRead(this._deploymentRole); + if (this.props2.adminPermissions) { this._deploymentRole.addToPolicy(new iam.PolicyStatement({ actions: ['*'], diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts index d7503448feaec..4a06f494d222f 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/cloudformation/test.cloudformation-pipeline-actions.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert'; import { CloudFormationCapabilities } from '@aws-cdk/aws-cloudformation'; import codebuild = require('@aws-cdk/aws-codebuild'); import codecommit = require('@aws-cdk/aws-codecommit'); @@ -200,7 +200,7 @@ export = { }, - 'fullPermissions leads to admin role and full IAM capabilities'(test: Test) { + 'fullPermissions leads to admin role and full IAM capabilities with pipeline bucket+key read permissions'(test: Test) { // GIVEN const stack = new TestFixture(); @@ -238,10 +238,25 @@ export = { })); // THEN: Role is created with full permissions - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).to(haveResourceLike('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + ], + "Effect": "Allow", + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey", + ], + "Effect": "Allow", + }, { Action: "*", Effect: 'Allow', diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json index dfc2bbf3c6fa5..a0111db9bb324 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json @@ -86,6 +86,22 @@ }, "Resource": "*" }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PipelineDeployPrepareChangesRoleD28C853C", + "Arn" + ] + } + }, + "Resource": "*" + }, { "Action": [ "kms:Decrypt", @@ -681,6 +697,49 @@ "Properties": { "PolicyDocument": { "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + }, { "Action": "*", "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json index 314d9b597afa4..ff745332948c0 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json @@ -173,6 +173,22 @@ }, "Resource": "*" }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PipelineDeployLambdaCFNDeployRole89CA1043", + "Arn" + ] + } + }, + "Resource": "*" + }, { "Action": [ "kms:Decrypt", @@ -1137,6 +1153,49 @@ "Properties": { "PolicyDocument": { "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + }, { "Action": "*", "Effect": "Allow", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json index 50b41008fb977..ae5f539860dc7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-cross-region.expected.json @@ -434,6 +434,52 @@ "Version": "2012-10-17" } } + }, + "MyPipelineCFNCFNDeployRoleDefaultPolicy65876BA0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyPipelineCFNCFNDeployRoleDefaultPolicy65876BA0", + "Roles": [ + { + "Ref": "MyPipelineCFNCFNDeployRole9CC99B3F" + } + ] + } } } } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json index 064a00b70c062..8903e0393415b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn-with-action-role.expected.json @@ -437,6 +437,52 @@ "Version": "2012-10-17" } } + }, + "MyPipelineCFNCFNDeployRoleDefaultPolicy65876BA0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyPipelineCFNCFNDeployRoleDefaultPolicy65876BA0", + "Roles": [ + { + "Ref": "MyPipelineCFNCFNDeployRole9CC99B3F" + } + ] + } } } } diff --git a/packages/decdk/test/__snapshots__/synth.test.js.snap b/packages/decdk/test/__snapshots__/synth.test.js.snap index eb08f19ae2fcc..26915a4c52cc7 100644 --- a/packages/decdk/test/__snapshots__/synth.test.js.snap +++ b/packages/decdk/test/__snapshots__/synth.test.js.snap @@ -1989,6 +1989,22 @@ Object { }, "Resource": "*", }, + Object { + "Action": Array [ + "kms:Decrypt", + "kms:DescribeKey", + ], + "Effect": "Allow", + "Principal": Object { + "AWS": Object { + "Fn::GetAtt": Array [ + "PipelineDeployRole97597E3E", + "Arn", + ], + }, + }, + "Resource": "*", + }, Object { "Action": Array [ "kms:Decrypt", @@ -2384,6 +2400,49 @@ Object { "Properties": Object { "PolicyDocument": Object { "Statement": Array [ + Object { + "Action": Array [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + ], + "Effect": "Allow", + "Resource": Array [ + Object { + "Fn::GetAtt": Array [ + "PipelineArtifactsBucket22248F97", + "Arn", + ], + }, + Object { + "Fn::Join": Array [ + "", + Array [ + Object { + "Fn::GetAtt": Array [ + "PipelineArtifactsBucket22248F97", + "Arn", + ], + }, + "/*", + ], + ], + }, + ], + }, + Object { + "Action": Array [ + "kms:Decrypt", + "kms:DescribeKey", + ], + "Effect": "Allow", + "Resource": Object { + "Fn::GetAtt": Array [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn", + ], + }, + }, Object { "Action": "*", "Effect": "Allow",