From c570d9cbd0ec618c84f5ac5c2e3256f3d3671a20 Mon Sep 17 00:00:00 2001 From: Luis Arias Date: Tue, 18 Aug 2020 02:39:12 -0700 Subject: [PATCH] feat(pipelines): add PolicyStatements to CodeBuild project role (#9527) Fixes aws/aws-cdk#9163 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/pipelines/README.md | 35 ++++++++++++ .../lib/synths/simple-synth-action.ts | 16 ++++++ .../test/build-role-policy-statements.test.ts | 54 +++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 431016a0d39c3..53686cad73e2e 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -421,6 +421,41 @@ const validationAction = new ShellScriptAction({ }); ``` +#### Add Additional permissions to the CodeBuild Project Role for building and synthing + +You can customize the role permissions used by the CodeBuild project so it has access to +the needed resources. eg: Adding CodeArtifact repo permissions so we pull npm packages +from the CA repo instead of NPM. + +```ts +class MyPipelineStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + ... + const pipeline = new CdkPipeline(this, 'Pipeline', { + ... + synthAction: SimpleSynthAction.standardNpmSynth({ + sourceArtifact, + cloudAssemblyArtifact, + + // Use this to customize and a permissions required for the build + // and synth + rolePolicyStatements: [ + new PolicyStatement({ + actions: ['codeartifact:*', 'sts:GetServiceBearerToken'], + resources: ['arn:codeartifact:repo:arn'], + }), + ], + + // Then you can login to codeartifact repository + // and npm will now pull packages from your repository + // Note the codeartifact login command requires more params to work. + buildCommand: 'aws codeartifact login --tool npm && npm run build', + }), + }); + } +} +``` + ## CDK Environment Bootstrapping An *environment* is an *(account, region)* pair where you want to deploy a diff --git a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts index fc088c46e00a2..564ab304d16c6 100644 --- a/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts +++ b/packages/@aws-cdk/pipelines/lib/synths/simple-synth-action.ts @@ -3,6 +3,7 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions'; import * as events from '@aws-cdk/aws-events'; +import { PolicyStatement } from '@aws-cdk/aws-iam'; import { Construct } from '@aws-cdk/core'; import { cloudAssemblyBuildSpecDir } from '../private/construct-internals'; import { copyEnvironmentVariables, filterEmpty } from './_util'; @@ -77,6 +78,15 @@ export interface SimpleSynthOptions { * @default - No additional artifacts generated */ readonly additionalArtifacts?: AdditionalArtifact[]; + + /** + * Policy statements to add to role used during the synth + * + * Can be used to add acces to a CodeArtifact repository etc. + * + * @default - No policy statements added to CodeBuild Project Role + */ + readonly rolePolicyStatements?: PolicyStatement[]; } /** @@ -235,6 +245,12 @@ export class SimpleSynthAction implements codepipeline.IAction { }, }); + if (this.props.rolePolicyStatements !== undefined) { + this.props.rolePolicyStatements.forEach(policyStatement => { + project.addToRolePolicy(policyStatement); + }); + } + this._action = new codepipeline_actions.CodeBuildAction({ actionName: this.actionProperties.actionName, input: this.props.sourceArtifact, diff --git a/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts b/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts new file mode 100644 index 0000000000000..298e8ccbb4e79 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/build-role-policy-statements.test.ts @@ -0,0 +1,54 @@ +import { arrayWith, deepObjectLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import { PolicyStatement } from '@aws-cdk/aws-iam'; +import { Stack } from '@aws-cdk/core'; +import * as cdkp from '../lib'; +import { PIPELINE_ENV, TestApp, TestGitHubNpmPipeline } from './testutil'; + +let app: TestApp; +let pipelineStack: Stack; +let sourceArtifact: codepipeline.Artifact; +let cloudAssemblyArtifact: codepipeline.Artifact; + +beforeEach(() => { + app = new TestApp(); + pipelineStack = new Stack(app, 'PipelineStackPolicy', { env: PIPELINE_ENV }); + sourceArtifact = new codepipeline.Artifact(); + cloudAssemblyArtifact = new codepipeline.Artifact('CloudAsm'); +}); + +afterEach(() => { + app.cleanup(); +}); + +test('Build project includes codeartifact policy statements for role', () => { + // WHEN + new TestGitHubNpmPipeline(pipelineStack, 'Cdk', { + sourceArtifact, + cloudAssemblyArtifact, + synthAction: cdkp.SimpleSynthAction.standardNpmSynth({ + sourceArtifact, + cloudAssemblyArtifact, + rolePolicyStatements: [ + new PolicyStatement({ + actions: ['codeartifact:*', 'sts:GetServiceBearerToken'], + resources: ['arn:my:arn'], + }), + ], + }), + }); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith(deepObjectLike({ + Action: [ + 'codeartifact:*', + 'sts:GetServiceBearerToken', + ], + Resource: 'arn:my:arn', + })), + }, + }); +});