-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into deploy-role-external-id
- Loading branch information
Showing
20 changed files
with
3,586 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -495,4 +495,60 @@ const validationAction = new ShellScriptAction({ | |
// 'test.js' was produced from 'test/test.ts' during the synth step | ||
commands: ['node ./test.js'], | ||
}); | ||
``` | ||
``` | ||
|
||
### Confirm permissions broadening | ||
|
||
To keep tabs on the security impact of changes going out through your pipeline, | ||
you can insert a security check before any stage deployment. This security check | ||
will check if the upcoming deployment would add any new IAM permissions or | ||
security group rules, and if so pause the pipeline and require you to confirm | ||
the changes. | ||
|
||
The security check will appear as two distinct actions in your pipeline: first | ||
a CodeBuild project that runs `cdk diff` on the stage that's about to be deployed, | ||
followed by a Manual Approval action that pauses the pipeline. If it so happens | ||
that there no new IAM permissions or security group rules will be added by the deployment, | ||
the manual approval step is automatically satisfied. The pipeline will look like this: | ||
|
||
```txt | ||
Pipeline | ||
├── ... | ||
├── MyApplicationStage | ||
│ ├── MyApplicationSecurityCheck // Security Diff Action | ||
│ ├── MyApplicationManualApproval // Manual Approval Action | ||
│ ├── Stack.Prepare | ||
│ └── Stack.Deploy | ||
└── ... | ||
``` | ||
|
||
You can enable the security check by passing `confirmBroadeningPermissions` to | ||
`addApplicationStage`: | ||
|
||
```ts | ||
const stage = pipeline.addApplicationStage(new MyApplication(this, 'PreProd'), { | ||
confirmBroadeningPermissions: true, | ||
}); | ||
``` | ||
|
||
To get notified when there is a change that needs your manual approval, | ||
create an SNS Topic, subscribe your own email address, and pass it in via | ||
`securityNotificationTopic`: | ||
|
||
```ts | ||
import * as sns from '@aws-cdk/aws-sns'; | ||
import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; | ||
import * as pipelines from '@aws-cdk/pipelines'; | ||
|
||
const topic = new sns.Topic(this, 'SecurityChangesTopic'); | ||
topic.addSubscription(new subscriptions.EmailSubscription('[email protected]')); | ||
|
||
const pipeline = new CdkPipeline(app, 'Pipeline', { /* ... */ }); | ||
const stage = pipeline.addApplicationStage(new MyApplication(this, 'PreProd'), { | ||
confirmBroadeningPermissions: true, | ||
securityNotificationTopic: topic, | ||
}); | ||
``` | ||
|
||
**Note**: Manual Approvals notifications only apply when an application has security | ||
check enabled. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -840,7 +840,7 @@ and orphan the old bucket. You should manually delete the orphaned bucket | |
after you are sure you have redeployed all CDK applications and there are no | ||
more references to the old asset bucket. | ||
|
||
## Security Tips | ||
## Security Considerations | ||
|
||
It's important to stay safe while employing Continuous Delivery. The CDK Pipelines | ||
library comes with secure defaults to the best of our ability, but by its | ||
|
@@ -862,6 +862,68 @@ We therefore expect you to mind the following: | |
changes can be deployed through git. Avoid the chances of credentials leaking | ||
by not having them in the first place! | ||
|
||
### Confirm permissions broadening | ||
|
||
To keep tabs on the security impact of changes going out through your pipeline, | ||
you can insert a security check before any stage deployment. This security check | ||
will check if the upcoming deployment would add any new IAM permissions or | ||
security group rules, and if so pause the pipeline and require you to confirm | ||
the changes. | ||
|
||
The security check will appear as two distinct actions in your pipeline: first | ||
a CodeBuild project that runs `cdk diff` on the stage that's about to be deployed, | ||
followed by a Manual Approval action that pauses the pipeline. If it so happens | ||
that there no new IAM permissions or security group rules will be added by the deployment, | ||
the manual approval step is automatically satisfied. The pipeline will look like this: | ||
|
||
```txt | ||
Pipeline | ||
├── ... | ||
├── MyApplicationStage | ||
│ ├── MyApplicationSecurityCheck // Security Diff Action | ||
│ ├── MyApplicationManualApproval // Manual Approval Action | ||
│ ├── Stack.Prepare | ||
│ └── Stack.Deploy | ||
└── ... | ||
``` | ||
|
||
You can insert the security check by using a `ConfirmPermissionsBroadening` step: | ||
|
||
```ts | ||
const stage = new MyApplicationStage(this, 'MyApplication'); | ||
pipeline.addStage(stage, { | ||
pre: [ | ||
new ConfirmPermissionsBroadening('Check', { stage }), | ||
], | ||
}); | ||
``` | ||
|
||
To get notified when there is a change that needs your manual approval, | ||
create an SNS Topic, subscribe your own email address, and pass it in as | ||
as the `notificationTopic` property: | ||
|
||
```ts | ||
import * as sns from '@aws-cdk/aws-sns'; | ||
import * as subscriptions from '@aws-cdk/aws-sns-subscriptions'; | ||
import * as pipelines from '@aws-cdk/pipelines'; | ||
|
||
const topic = new sns.Topic(this, 'SecurityChangesTopic'); | ||
topic.addSubscription(new subscriptions.EmailSubscription('[email protected]')); | ||
|
||
const stage = new MyApplicationStage(this, 'MyApplication'); | ||
pipeline.addStage(stage, { | ||
pre: [ | ||
new ConfirmPermissionsBroadening('Check', { | ||
stage, | ||
notificationTopic: topic, | ||
}), | ||
], | ||
}); | ||
``` | ||
|
||
**Note**: Manual Approvals notifications only apply when an application has security | ||
check enabled. | ||
|
||
## Troubleshooting | ||
|
||
Here are some common errors you may encounter while using this library. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { IStage } from '@aws-cdk/aws-codepipeline'; | ||
import * as cpa from '@aws-cdk/aws-codepipeline-actions'; | ||
import * as sns from '@aws-cdk/aws-sns'; | ||
import { Stage } from '@aws-cdk/core'; | ||
import { Node } from 'constructs'; | ||
import { Step } from '../blueprint'; | ||
import { ApplicationSecurityCheck } from '../private/application-security-check'; | ||
import { CodePipeline } from './codepipeline'; | ||
import { CodePipelineActionFactoryResult, ICodePipelineActionFactory, ProduceActionOptions } from './codepipeline-action-factory'; | ||
|
||
/** | ||
* Properties for a `PermissionsBroadeningCheck` | ||
*/ | ||
export interface PermissionsBroadeningCheckProps { | ||
/** | ||
* The CDK Stage object to check the stacks of | ||
* | ||
* This should be the same Stage object you are passing to `addStage()`. | ||
*/ | ||
readonly stage: Stage; | ||
|
||
/** | ||
* Topic to send notifications when a human needs to give manual confirmation | ||
* | ||
* @default - no notification | ||
*/ | ||
readonly notificationTopic?: sns.ITopic | ||
} | ||
|
||
/** | ||
* Pause the pipeline if a deployment would add IAM permissions or Security Group rules | ||
* | ||
* This step is only supported in CodePipeline pipelines. | ||
*/ | ||
export class ConfirmPermissionsBroadening extends Step implements ICodePipelineActionFactory { | ||
constructor(id: string, private readonly props: PermissionsBroadeningCheckProps) { | ||
super(id); | ||
} | ||
|
||
public produceAction(stage: IStage, options: ProduceActionOptions): CodePipelineActionFactoryResult { | ||
const sec = this.getOrCreateSecCheck(options.pipeline); | ||
this.props.notificationTopic?.grantPublish(sec.cdkDiffProject); | ||
|
||
const variablesNamespace = Node.of(this.props.stage).addr; | ||
|
||
const approveActionName = `${options.actionName}.Confirm`; | ||
stage.addAction(new cpa.CodeBuildAction({ | ||
runOrder: options.runOrder, | ||
actionName: `${options.actionName}.Check`, | ||
input: options.artifacts.toCodePipeline(options.pipeline.cloudAssemblyFileSet), | ||
project: sec.cdkDiffProject, | ||
variablesNamespace, | ||
environmentVariables: { | ||
STAGE_PATH: { value: Node.of(this.props.stage).path }, | ||
STAGE_NAME: { value: stage.stageName }, | ||
ACTION_NAME: { value: approveActionName }, | ||
...this.props.notificationTopic ? { | ||
NOTIFICATION_ARN: { value: this.props.notificationTopic.topicArn }, | ||
NOTIFICATION_SUBJECT: { value: `Confirm permission broadening in ${this.props.stage.stageName}` }, | ||
} : {}, | ||
}, | ||
})); | ||
|
||
stage.addAction(new cpa.ManualApprovalAction({ | ||
actionName: approveActionName, | ||
runOrder: options.runOrder + 1, | ||
additionalInformation: `#{${variablesNamespace}.MESSAGE}`, | ||
externalEntityLink: `#{${variablesNamespace}.LINK}`, | ||
})); | ||
|
||
return { runOrdersConsumed: 2 }; | ||
} | ||
|
||
private getOrCreateSecCheck(pipeline: CodePipeline): ApplicationSecurityCheck { | ||
const id = 'PipelinesSecurityCheck'; | ||
const existing = Node.of(pipeline).tryFindChild(id); | ||
if (existing) { | ||
if (!(existing instanceof ApplicationSecurityCheck)) { | ||
throw new Error(`Expected '${Node.of(existing).path}' to be 'ApplicationSecurityCheck' but was '${existing}'`); | ||
} | ||
return existing; | ||
} | ||
|
||
return new ApplicationSecurityCheck(pipeline, id, { | ||
codePipeline: pipeline.pipeline, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
export * from './artifact-map'; | ||
export * from './codebuild-step'; | ||
export * from './confirm-permissions-broadening'; | ||
export * from './codepipeline'; | ||
export * from './codepipeline-action-factory'; | ||
export * from './codepipeline-source'; |
Oops, something went wrong.