Skip to content

Commit

Permalink
feat(aws-codepipeline): support for pipeline action’s service role
Browse files Browse the repository at this point in the history
In realation to aws#49

The action’s service roles is a role which will be assumed
by pipeline during execution of this action.

The pipeline action’s service role can be used to perform more
advanced configuration, when i.e. elevation of permissions
is required, or when fine grained access control may be required.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codepipeline-pipeline-stages-actions.html

This commit is motivated by enabling cross-account deployments,
for which service role will be used as jump role to assume
one used by Cloud Formation in target account.
  • Loading branch information
Rado Smogura committed Jan 18, 2019
1 parent 4af7c0d commit 58a297b
Show file tree
Hide file tree
Showing 14 changed files with 527 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,4 +1,6 @@
.vscode
# VSCode extension
/.favorites.json
.DS_Store
node_modules
lerna-debug.log
Expand Down
3 changes: 1 addition & 2 deletions packages/@aws-cdk/aws-cloudformation/lib/pipeline-actions.ts
Expand Up @@ -59,8 +59,7 @@ export abstract class PipelineCloudFormationAction extends codepipeline.Action {

constructor(scope: cdk.Construct, id: string, props: PipelineCloudFormationActionProps, configuration?: any) {
super(scope, id, {
stage: props.stage,
runOrder: props.runOrder,
...props,
region: props.region,
artifactBounds: {
minInputs: 0,
Expand Down
3 changes: 1 addition & 2 deletions packages/@aws-cdk/aws-codecommit/lib/pipeline-action.ts
Expand Up @@ -48,8 +48,7 @@ export interface PipelineSourceActionProps extends CommonPipelineSourceActionPro
export class PipelineSourceAction extends codepipeline.SourceAction {
constructor(scope: cdk.Construct, id: string, props: PipelineSourceActionProps) {
super(scope, id, {
stage: props.stage,
runOrder: props.runOrder,
...props,
provider: 'CodeCommit',
configuration: {
RepositoryName: props.repository.repositoryName,
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts
@@ -1,6 +1,6 @@
import { App, Stack } from '@aws-cdk/cdk';
import { Test } from 'nodeunit';
import { Repository, RepositoryProps } from '../lib';
import { Repository, RepositoryProps } from '../lib';

export = {
'default properties': {
Expand Down Expand Up @@ -49,7 +49,7 @@ export = {
test.throws(() => myRepository.notify('myTrigger'));

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

Expand Down
3 changes: 1 addition & 2 deletions packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts
Expand Up @@ -31,8 +31,7 @@ export interface PipelineDeployActionProps extends CommonPipelineDeployActionPro
export class PipelineDeployAction extends codepipeline.DeployAction {
constructor(scope: cdk.Construct, id: string, props: PipelineDeployActionProps) {
super(scope, id, {
stage: props.stage,
runOrder: props.runOrder,
...props,
artifactBounds: { minInputs: 1, maxInputs: 1, minOutputs: 0, maxOutputs: 0 },
provider: 'CodeDeploy',
inputArtifact: props.inputArtifact,
Expand Down
66 changes: 66 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/test/test.pipeline-action.ts
@@ -0,0 +1,66 @@
import { IPipeline } from '@aws-cdk/aws-codepipeline-api';
import * as iam from '@aws-cdk/aws-iam';
import { App, Stack } from '@aws-cdk/cdk';
import { Test } from 'nodeunit';
import { Bucket, PipelineSourceAction } from '../../aws-s3/lib';
import { PipelineDeployAction, ServerDeploymentGroup } from '../lib';

export = {
'test passing properties to action'(test: Test) {
const app = new TestApp();

const source = new PipelineSourceAction(app.stack, 'Src', {
bucket: Bucket.import(app.stack, 'Bucket', {bucketName: 'someName'}),
bucketKey: 'bkkey',
stage: {
node: app.stack.node,
name: 'Source',
pipeline: {
role: iam.Role.import(app.stack, 'r1', { roleArn: 'arn:aws:iam::123456789012:role/superUser1'} )
} as IPipeline,
_internal: {
_attachAction: () => null,
_findInputArtifact: () => { throw new Error('X'); },
_generateOutputArtifactName: () => 'SourceOut'
}
}
});

const action = new PipelineDeployAction(app.stack, 'Id', {
runOrder: 456,
stage: {
node: app.stack.node,
name: 'Source',
pipeline: {
role: iam.Role.import(app.stack, 'r2', { roleArn: 'arn:aws:iam::123456789012:role/superUser2'} )
} as IPipeline,
_internal: {
_attachAction: () => null,
_findInputArtifact: () => { throw new Error('X'); },
_generateOutputArtifactName: () => 'DeployOut'
}
},
actionRole: iam.Role.import(app.stack, 'Role', {
roleArn: 'arn:aws:iam::123456789012:role/superUser'
}),
deploymentGroup: new ServerDeploymentGroup(app.stack, 'DeployGroup', {
deploymentGroupName: 'DGName'
}),
inputArtifact: source.outputArtifact
});

test.equals(action.runOrder, 456);
test.equals(action.actionRole!.roleArn, 'arn:aws:iam::123456789012:role/superUser');
test.done();
}
};

class TestApp {
private readonly app = new App();
// tslint:disable-next-line:member-ordering
public readonly stack: Stack = new Stack(this.app, 'MyStack');

public synthesizeTemplate() {
return this.app.synthesizeStack(this.stack.name).template;
}
}
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-codepipeline-api/lib/action.ts
Expand Up @@ -136,6 +136,15 @@ export interface CommonActionProps {
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html
*/
runOrder?: number;

/**
* The service role that is assumed during execution of action.
* This role is not mandatory, however more advanced configuration
* may require specifying it.
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codepipeline-pipeline-stages-actions.html
*/
actionRole?: iam.IRole;
}

/**
Expand Down Expand Up @@ -205,6 +214,15 @@ export abstract class Action extends cdk.Construct {
*/
public readonly configuration?: any;

/**
* The service role that is assumed during execution of action.
* This role is not mandatory, however more advanced configuration
* may require specifying it.
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codepipeline-pipeline-stages-actions.html
*/
public readonly actionRole?: iam.IRole;

/**
* The order in which AWS CodePipeline runs this action.
* For more information, see the AWS CodePipeline User Guide.
Expand All @@ -218,6 +236,7 @@ export abstract class Action extends cdk.Construct {

private readonly _actionInputArtifacts = new Array<Artifact>();
private readonly _actionOutputArtifacts = new Array<Artifact>();

private readonly artifactBounds: ActionArtifactBounds;
private readonly stage: IStage;

Expand All @@ -235,6 +254,7 @@ export abstract class Action extends cdk.Construct {
this.artifactBounds = props.artifactBounds;
this.runOrder = props.runOrder === undefined ? 1 : props.runOrder;
this.stage = props.stage;
this.actionRole = props.actionRole;

this.stage._internal._attachAction(this);
}
Expand Down
Expand Up @@ -58,8 +58,7 @@ export interface GitHubSourceActionProps extends actions.CommonActionProps,
export class GitHubSourceAction extends actions.SourceAction {
constructor(scope: cdk.Construct, id: string, props: GitHubSourceActionProps) {
super(scope, id, {
stage: props.stage,
runOrder: props.runOrder,
...props,
owner: 'ThirdParty',
provider: 'GitHub',
configuration: {
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-codepipeline/lib/stage.ts
Expand Up @@ -162,6 +162,7 @@ export class Stage extends cdk.Construct implements cpapi.IStage, cpapi.IInterna
configuration: action.configuration,
outputArtifacts: action._outputArtifacts.map(a => ({ name: a.name })),
runOrder: action.runOrder,
roleArn: action.actionRole ? action.actionRole.roleArn : undefined
};
}

Expand Down

0 comments on commit 58a297b

Please sign in to comment.