Skip to content

Commit

Permalink
fix(codepipeline): CloudFormation deployment role always gets pipelin…
Browse files Browse the repository at this point in the history
…e bucket and key permissions (#5190)

Previously, we only explicitly granted the CloudFormation CodePipeline action deployment role access to the pipeline bucket
(and, by extension, its KMS key)
when the action was deploying into a different account.
However, that meant in the single account case,
if the pipeline had a key defined,
the role would never be added to the key's policy,
and any deployment requiring access to the artifacts bucket
(like a Lambda function) would fail.
This fixes the bug by always granting the deployment role permissions to the pipeline bucket (and thus the key as well).

Fixes #5183
  • Loading branch information
skinny85 authored and mergify[bot] committed Nov 26, 2019
1 parent 209f909 commit d5c0f3e
Show file tree
Hide file tree
Showing 9 changed files with 426 additions and 9 deletions.
46 changes: 46 additions & 0 deletions packages/@aws-cdk/app-delivery/test/integ.cicd.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ['*'],
Expand Down
Original file line number Diff line number Diff line change
@@ -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');
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@
},
"Resource": "*"
},
{
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::GetAtt": [
"PipelineDeployPrepareChangesRoleD28C853C",
"Arn"
]
}
},
"Resource": "*"
},
{
"Action": [
"kms:Decrypt",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,22 @@
},
"Resource": "*"
},
{
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::GetAtt": [
"PipelineDeployLambdaCFNDeployRole89CA1043",
"Arn"
]
}
},
"Resource": "*"
},
{
"Action": [
"kms:Decrypt",
Expand Down Expand Up @@ -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",
Expand Down
Loading

0 comments on commit d5c0f3e

Please sign in to comment.