Skip to content

Commit

Permalink
fix(codebuild): Project lacks permissions for SSM ParameterStore envi…
Browse files Browse the repository at this point in the history
…ronment variables (#11770)

Pipeline build fails when the environment variable is loaded from SSM Parameter Store.

Closes #11769

---------------

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
cvrajeesh authored Nov 30, 2020
1 parent 5bf5ecc commit 3c5c2f4
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 1 deletion.
25 changes: 25 additions & 0 deletions packages/@aws-cdk/aws-codebuild/lib/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,7 @@ export class Project extends ProjectBase {
this.projectName = this.getResourceNameAttribute(resource.ref);

this.addToRolePolicy(this.createLoggingPermission());
this.addParameterStorePermission(props);
// add permissions to create and use test report groups
// with names starting with the project's name,
// unless the customer explicitly opts out of it
Expand Down Expand Up @@ -923,6 +924,30 @@ export class Project extends ProjectBase {
});
}

private addParameterStorePermission(props: ProjectProps) {
if (!props.environmentVariables) {
return;
}

const resources = Object.values(props.environmentVariables)
.filter(envVariable => envVariable.type === BuildEnvironmentVariableType.PARAMETER_STORE)
.map(envVariable => Stack.of(this).formatArn({
service: 'ssm',
resource: 'parameter',
sep: ':',
resourceName: envVariable.value,
}));

if (resources.length === 0) {
return;
}

this.addToRolePolicy(new iam.PolicyStatement({
actions: ['ssm:GetParameters'],
resources,
}));
}

private renderEnvironment(
env: BuildEnvironment = {},
projectVars: { [name: string]: BuildEnvironmentVariable } = {}): CfnProject.EnvironmentProperty {
Expand Down
154 changes: 153 additions & 1 deletion packages/@aws-cdk/aws-codebuild/test/test.project.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { countResources, expect, haveResource, haveResourceLike, objectLike, not, ResourcePart } from '@aws-cdk/assert';
import { countResources, expect, haveResource, haveResourceLike, objectLike, not, ResourcePart, arrayWith } from '@aws-cdk/assert';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as logs from '@aws-cdk/aws-logs';
Expand Down Expand Up @@ -738,4 +738,156 @@ export = {
test.done();
},
},

'EnvironmentVariables': {
'can use environment variables from parameter store'(test: Test) {
// GIVEN
const stack = new cdk.Stack();

// WHEN
new codebuild.Project(stack, 'Project', {
source: codebuild.Source.s3({
bucket: new s3.Bucket(stack, 'Bucket'),
path: 'path',
}),
environment: {
buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'),
},
environmentVariables: {
'ENV_VAR1': {
type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE,
value: '/params/param1',
},
},
});

// THEN
expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', {
Environment: objectLike({
EnvironmentVariables: [{
Name: 'ENV_VAR1',
Type: 'PARAMETER_STORE',
Value: '/params/param1',
}],
}),
}));

test.done();
},


'grant read permission for parameter store variables'(test: Test) {
// GIVEN
const stack = new cdk.Stack();

// WHEN
new codebuild.Project(stack, 'Project', {
source: codebuild.Source.s3({
bucket: new s3.Bucket(stack, 'Bucket'),
path: 'path',
}),
environment: {
buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'),
},
environmentVariables: {
'ENV_VAR1': {
type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE,
value: '/params/param1',
},
'ENV_VAR2': {
type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE,
value: '/params/param2',
},
},
});

// THEN
expect(stack).to(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith(objectLike({
'Action': 'ssm:GetParameters',
'Effect': 'Allow',
'Resource': [{
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':ssm:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':parameter:/params/param1',

This comment has been minimized.

Copy link
@markusl

markusl Dec 7, 2020

Contributor
],
],
},
{
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':ssm:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':parameter:/params/param2',
],
],
}],
})),
},
}));


test.done();
},

'should not grant read permission when variables are not from parameter store'(test: Test) {

// GIVEN
const stack = new cdk.Stack();

// WHEN
new codebuild.Project(stack, 'Project', {
source: codebuild.Source.s3({
bucket: new s3.Bucket(stack, 'Bucket'),
path: 'path',
}),
environment: {
buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'),
},
environmentVariables: {
'ENV_VAR1': {
type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value: 'var1-value',
},
},
});

// THEN
expect(stack).notTo(haveResourceLike('AWS::IAM::Policy', {
'PolicyDocument': {
'Statement': arrayWith(objectLike({
'Action': 'ssm:GetParameters',
'Effect': 'Allow',
})),
},
}));

test.done();
},
},
};

0 comments on commit 3c5c2f4

Please sign in to comment.