Skip to content

Commit

Permalink
feat(CodeBuild): add kms:Decrypt action for secrets from other accounts
Browse files Browse the repository at this point in the history
When providing a secretArn from a another account for the EnvironmentVariables
allow kms:Decrypt action for any key. This enables CodeBuild to get the secret
without any further policy changes by the user.

fixes #14043
  • Loading branch information
Kruspe committed Apr 18, 2021
1 parent 8a949dc commit 3854465
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 3 deletions.
23 changes: 22 additions & 1 deletion packages/@aws-cdk/aws-codebuild/lib/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ export class Project extends ProjectBase {
const ret = new Array<CfnProject.EnvironmentVariableProperty>();
const ssmIamResources = new Array<string>();
const secretsManagerIamResources = new Array<string>();
const kmsIamResources = new Array<string>();

for (const [name, envVariable] of Object.entries(environmentVariables)) {
const envVariableValue = envVariable.value?.toString();
Expand Down Expand Up @@ -790,7 +791,7 @@ export class Project extends ProjectBase {
// If we were given just a name, it must be partial, as CodeBuild doesn't support providing full names.
// In this case, we need to accommodate for the generated suffix in the IAM resource name
: `${secretName}-??????`;
secretsManagerIamResources.push(Stack.of(principal).formatArn({
secretsManagerIamResources.push(stack.formatArn({
service: 'secretsmanager',
resource: 'secret',
resourceName: secretIamResourceName,
Expand All @@ -800,6 +801,20 @@ export class Project extends ProjectBase {
account: parsedArn?.account,
region: parsedArn?.region,
}));
// if secret comes from another account, SecretsManager will need to access
// KMS on the other account as well to be able to get the secret
if (parsedArn?.account !== stack.account) {
kmsIamResources.push(stack.formatArn({
service: 'kms',
resource: 'key',
resourceName: '*',
sep: '/',
// if we were given an ARN, we need to use the provided partition/account/region
partition: parsedArn?.partition,
account: parsedArn?.account,
region: parsedArn?.region,
}));
}
}
}
}
Expand All @@ -817,6 +832,12 @@ export class Project extends ProjectBase {
resources: secretsManagerIamResources,
}));
}
if (kmsIamResources.length !== 0) {
principal?.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({
actions: ['kms:Decrypt'],
resources: kmsIamResources,
}));
}

return ret;
}
Expand Down
87 changes: 85 additions & 2 deletions packages/@aws-cdk/aws-codebuild/test/test.project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,10 @@ export = {

'can be provided as a verbatim full secret ARN followed by a JSON key'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const app = new cdk.App();
const stack = new cdk.Stack(app, 'ProjectStack', {
env: { account: '123456789012' },
});

// WHEN
new codebuild.PipelineProject(stack, 'Project', {
Expand Down Expand Up @@ -1057,12 +1060,26 @@ export = {
},
}));

// THEN
expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith({
'Action': 'kms:Decrypt',
'Effect': 'Allow',
'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*',
}),
},
})));

test.done();
},

'can be provided as a verbatim partial secret ARN'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const app = new cdk.App();
const stack = new cdk.Stack(app, 'ProjectStack', {
env: { account: '123456789012' },
});

// WHEN
new codebuild.PipelineProject(stack, 'Project', {
Expand Down Expand Up @@ -1098,6 +1115,72 @@ export = {
},
}));

// THEN
expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith({
'Action': 'kms:Decrypt',
'Effect': 'Allow',
'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*',
}),
},
})));

test.done();
},

'can be provided as a verbatim partial secret ARN from another account'(test: Test) {
// GIVEN
const app = new cdk.App();
const stack = new cdk.Stack(app, 'ProjectStack', {
env: { account: '123456789012' },
});

// WHEN
new codebuild.PipelineProject(stack, 'Project', {
environmentVariables: {
'ENV_VAR1': {
type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER,
value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret',
},
},
});

// THEN
expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', {
'Environment': {
'EnvironmentVariables': [
{
'Name': 'ENV_VAR1',
'Type': 'SECRETS_MANAGER',
'Value': 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret',
},
],
},
}));

// THEN
expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith({
'Action': 'secretsmanager:GetSecretValue',
'Effect': 'Allow',
'Resource': 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret*',
}),
},
}));

// THEN
expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith({
'Action': 'kms:Decrypt',
'Effect': 'Allow',
'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*',
}),
},
}));

test.done();
},

Expand Down

0 comments on commit 3854465

Please sign in to comment.