We use machine learning technology to do auto-translation. Click "English" on top navigation bar to check Chinese version.
Implementing automatic drift detection in CDK Pipelines using Amazon EventBridge
The
With CloudFormation stacks, there is the possibility that someone can manually change the configuration of stack resources outside the purview of CloudFormation and the pipeline that deploys the stack. This causes the deployed resources to be inconsistent with the intent in the application, which is referred to as “drift”, a situation that can make the application’s behavior unpredictable. For example, when troubleshooting an application, if the application has drifted in production, it is difficult to reproduce the same behavior in a development environment. In other cases, it may introduce security vulnerabilities in the application. For example, an
CloudFormation offers a
In this blog post you will see how CloudFormation drift detection can be integrated as a pre-deployment validation step in CDK Pipelines using an event driven approach.
Services and frameworks used in the post include CloudFormation, CodeBuild,
Solution overview

Architecture diagram
The user starts the pipeline by checking code into an
Demo Stack
and then saves the drift_detection_id
along with pipeline_job_id
in a DynamoDB table. In the meantime, the pipeline waits for a response on the status of drift detection.
The EventBridge rules are set up to capture the drift detection state change events for Demo Stack
that are received by the default event bus. The callback lambda is registered as the intended target for the rules. When drift detection completes, it triggers the EventBridge rule which in turn invokes the callback lambda function with stack status as either DRIFTED
or IN SYNC
. The callback lambda function pulls the pipeline_job_id
from DynamoDB and sends the appropriate status back to the pipeline, thus propelling the pipeline out of the wait state. If the stack is in the IN SYNC
status, the callback lambda sends a success status and the pipeline continues with the deployment. If the stack is in the DRIFTED
status, callback lambda sends failure status back to the pipeline and the pipeline run ends up in failure.
Solution Deep Dive
The solution deploys two stacks as shown in the above architecture diagram
- CDK Pipelines stack
- Pre-requisite stack
The CDK Pipelines stack defines a pipeline with a CodeCommit source and drift detection step integrated into it. The pre-requisite stack deploys following resources that are required by the CDK Pipelines stack.
- A Lambda function that implements drift detection step
- A DynamoDB table that holds
drift_detection_id
andpipeline_job_id
- An Event bridge rule to capture “CloudFormation Drift Detection Status Change” event
- A callback lambda function that evaluates status of drift detection and sends status back to the pipeline by looking up the data captured in DynamoDB.
The pre-requisites stack is deployed first, followed by the CDK Pipelines stack.
Defining drift detection step
CDK Pipelines offers a
You start by defining a class called DriftDetectionStep
that extends Step and implements ICodePipelineActionFactory
as shown in the following code snippet. The constructor accepts 3 parameters stackName
, account
, region
as inputs. When the pipeline runs the step, it invokes the drift detection lambda function with these parameters wrapped inside userParameters
variable. The function produceAction()
adds the action to invoke drift detection lambda function to the pipeline stage.
Please note that the solution uses an
export class DriftDetectionStep
extends Step
implements pipelines.ICodePipelineActionFactory
{
constructor(
private readonly stackName: string,
private readonly account: string,
private readonly region: string
) {
super(`DriftDetectionStep-${stackName}`);
}
public produceAction(
stage: codepipeline.IStage,
options: ProduceActionOptions
): CodePipelineActionFactoryResult {
// Define the configuraton for the action that is added to the pipeline.
stage.addAction(
new cpactions.LambdaInvokeAction({
actionName: options.actionName,
runOrder: options.runOrder,
lambda: lambda.Function.fromFunctionArn(
options.scope,
`InitiateDriftDetectLambda-${this.stackName}`,
ssm.StringParameter.valueForStringParameter(
options.scope,
SSM_PARAM_DRIFT_DETECT_LAMBDA_ARN
)
),
// These are the parameters passed to the drift detection step implementaton provider lambda
userParameters: {
stackName: this.stackName,
account: this.account,
region: this.region,
},
})
);
return {
runOrdersConsumed: 1,
};
}
}
Configuring drift detection step in CDK Pipelines
Here you will see how to integrate the previously defined drift detection step into CDK Pipelines. The pipeline has a stage called DemoStage
as shown in the following code snippet. During the construction of DemoStage
, we declare drift detection as the pre-deployment step. This makes sure that the pipeline always does the drift detection check prior to deployment.
Please note that for every stack defined in the stage; we add a dedicated step to perform drift detection by instantiating the class DriftDetectionStep
detailed in the prior section. Thus, this solution scales with the number of stacks defined per stage.
export class PipelineStack extends BaseStack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const repo = new codecommit.Repository(this, 'DemoRepo', {
repositoryName: `${this.node.tryGetContext('appName')}-repo`,
});
const pipeline = new CodePipeline(this, 'DemoPipeline', {
synth: new ShellStep('synth', {
input: CodePipelineSource.codeCommit(repo, 'main'),
commands: ['./script-synth.sh'],
}),
crossAccountKeys: true,
enableKeyRotation: true,
});
const demoStage = new DemoStage(this, 'DemoStage', {
env: {
account: this.account,
region: this.region,
},
});
const driftDetectionSteps: Step[] = [];
for (const stackName of demoStage.stackNameList) {
const step = new DriftDetectionStep(stackName, this.account, this.region);
driftDetectionSteps.push(step);
}
pipeline.addStage(demoStage, {
pre: driftDetectionSteps,
});
Demo
Here you will go through the deployment steps for the solution and see drift detection in action.
Deploy the pre-requisites stack
Clone the repo from the GitHub location
Deploy the CDK Pipelines stack
Clone the repo from the GitHub location
script-deploy.sh
. This deploys a pipeline with an empty CodeCommit repo as the source. The pipeline run ends up in failure, as shown below, because of the empty CodeCommit repo.
Next, check in the code from the cloned repo into the CodeCommit source repo. You can find detailed instructions on that in
The pipeline deploys two stacks DemoStackA
and DemoStackB
. Each of these stacks creates an S3 bucket.
Demonstrate drift detection
Locate the S3 bucket created by DemoStackA
under resources, navigate to the S3 bucket and modify the tag aws-cdk:auto-delete-objects
from true
to false
as shown below
Now, go to the pipeline and trigger a new execution by clicking on Release Change
The pipeline run will now end in failure at the pre-deployment drift detection step.
Cleanup
Please follow the steps below to clean up all the stacks.
- Navigate to S3 console and empty the buckets created by stacks
DemoStackA
andDemoStackB
. - Navigate to the CloudFormation console and delete stacks
DemoStackA
andDemoStackB
, since deleting CDK Pipelines stack does not delete the application stacks that the pipeline deploys. - Delete the CDK Pipelines stack
cdk-drift-detect-demo-pipeline
- Delete the pre-requisites stack
cdk-drift-detect-demo-drift-detection-prereq
Conclusion
In this post, I showed how to add a custom implementation step in CDK Pipelines. I also used that mechanism to integrate a drift detection check as a pre-deployment step. This allows us to validate the integrity of a CloudFormation Stack before its deployment. Since the validation is integrated into the pipeline, it is easier to manage the solution in one place as part of the overarching pipeline. Give the solution a try, and then see if you can incorporate it into your organization’s delivery pipelines.
About the author:
Damodar Shenvi Wagle is a Senior Cloud Application Architect at Amazon Web Services Professional Services. His areas of expertise include architecting serverless solutions, CI/CD, and automation.
The mentioned AWS GenAI Services service names relating to generative AI are only available or previewed in the Global Regions. Amazon Web Services China promotes AWS GenAI Services relating to generative AI solely for China-to-global business purposes and/or advanced technology introduction.