1.1 Multi-Stage & Multi-Account CodePipeline Design
Key Takeaways
- AWS CodePipeline organizes software releases into sequential or parallel stages (Source, Build, Test, Deploy) triggered reactively by Amazon EventBridge rules rather than legacy polling.
- Cross-account deployments require hosting CodePipeline, an S3 artifact bucket, and an AWS KMS Customer Managed Key (CMK) in a central Tools/Shared-Services account; AWS-managed S3 keys (aws/s3) cannot be used across accounts.
- Target account deployment actions assume dedicated IAM cross-account execution roles via roleArn, requiring mutual trust between the Tools account CodePipeline service role and target account role policies.
- The centralized S3 artifact bucket policy must grant s3:GetObject*, s3:PutObject*, and s3:ListBucket permissions to target account roles, while the KMS key policy must delegate decrypt capabilities to target account principals.
- Dynamic pipeline variables (#{Namespace.Variable}) extract runtime values like Git commit IDs or container image tags from upstream actions and inject them directly into downstream CloudFormation parameter overrides.
Core Anatomy of AWS CodePipeline
AWS CodePipeline is a fully managed continuous delivery service that automates release pipelines for fast, reliable application and infrastructure updates. CodePipeline orchestrates the workflow of code changes through distinct stages, each containing one or more actions that execute sequentially or in parallel.
Stage Progression and Action Categories
A production-grade pipeline is divided into logical stages that enforce quality gates before software reaches end users:
- Source Stage: Fetches code from source control repositories (such as GitHub, Bitbucket, or AWS CodeCommit) or artifact repositories (such as Amazon S3 or Amazon ECR). Every execution begins with a source revision.
- Build Stage: Compiles code, runs unit tests, analyzes code quality, and packages deployment artifacts using AWS CodeBuild or third-party build systems.
- Test Stage: Executes automated integration tests, load tests, compliance checks, and synthetic canaries in an isolated pre-production environment.
- Deploy Stage: Deploys artifacts to target hosting platforms, including AWS Elastic Beanstalk, Amazon ECS, AWS Fargate, AWS Lambda, Amazon EC2/on-premises via AWS CodeDeploy, or provisions infrastructure using AWS CloudFormation.
Actions inside a stage can be configured with execution order integers (runOrder). Actions sharing the same runOrder execute in parallel, reducing cycle time. Actions with higher runOrder values execute sequentially only after earlier actions succeed.
Execution Triggers: EventBridge vs. Polling
Historically, CodePipeline periodically polled source repositories every few minutes to detect changes. Modern AWS architectures require event-driven triggers powered by Amazon EventBridge:
| Trigger Type | Latency | API Overhead | Event Filtering Capability |
|---|---|---|---|
| EventBridge (Recommended) | Near-real-time (best effort; no sub-second SLA) | No scheduled polling calls | Granular filtering by branch, tag, repository, and event type |
| Polling (Legacy) | 1–5 minutes | Periodic GetCommit or ListObjects API calls | None; checks all branch heads periodically |
When a developer pushes a commit or updates a reference, the source provider emits an event that matches an EventBridge rule. EventBridge routes the matching event to the CodePipeline API (codepipeline:StartPipelineExecution) without scheduled source polling. Delivery is best effort, so architecture decisions must not assume a guaranteed sub-second end-to-end latency.
Enterprise Cross-Account Pipeline Architecture
In enterprise AWS Organizations, security and governance best practices require strict boundary isolation between environments. A common topology establishes dedicated AWS accounts:
- Tools / Shared Services Account (Account A -
111111111111): Hosts the CodePipeline pipeline, the primary Amazon S3 artifact bucket, and the AWS KMS Customer Managed Key (CMK). - Development Account (Account B -
222222222222): Hosts development application workloads and development CloudFormation stacks. - Staging / QA Account (Account C -
333333333333): Hosts pre-production validation environments. - Production Account (Account D -
444444444444): Hosts business-critical live production workloads.
Deploying across accounts requires a coordinated triad of permissions: IAM AssumeRole, S3 Bucket Policies, and KMS Customer Managed Key (CMK) Policies.
[ Tools Account (111111111111) ]
CodePipeline Service Role
│
├─ 1. Assumes Role ──> [ Target Account (444444444444) ]
│ CrossAccountDeployRole
│ │
├─ 2. Encrypts Artifact ├─ 3. Reads & Decrypts Artifact
▼ ▼
[ S3 Artifact Bucket ] <─────────── [ KMS CMK (Tools Account) ]
(Bucket Policy Allows (Key Policy Allows
Target Account Access) Target Account Access)
The KMS Customer Managed Key (CMK) Requirement
[!IMPORTANT] DOP-C02 Exam Trap: You cannot use the default AWS-managed S3 key (
aws/s3) for cross-account CodePipeline deployments! The key policy of an AWS-managed key cannot be modified to add cross-account permissions. You must create an AWS KMS Customer Managed Key (CMK) in the Tools account and configure its key policy to explicitly grant cryptographic operations to the target accounts.
The KMS key policy in the Tools account must grant access to the target account root principal or specific deployment roles:
{
"Version": "2012-10-17",
"Id": "CrossAccountKmsPolicy",
"Statement": [
{
"Sid": "EnableTargetAccountUsage",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::222222222222:root",
"arn:aws:iam::444444444444:root"
]
},
"Action": [
"kms:DescribeKey",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:ReEncrypt*",
"kms:Decrypt"
],
"Resource": "*"
}
]
}
Cross-Account S3 Artifact Bucket Policy
The central S3 artifact bucket located in the Tools account must permit target account IAM roles to retrieve and upload pipeline artifacts:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountArtifactAccess",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::222222222222:role/CrossAccountDeployRole",
"arn:aws:iam::444444444444:role/CrossAccountDeployRole"
]
},
"Action": [
"s3:GetObject*",
"s3:PutObject*",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::central-pipeline-artifacts-111111111111",
"arn:aws:s3:::central-pipeline-artifacts-111111111111/*"
]
}
]
}
Target Account IAM Deployment Role
In each target account (e.g., Production 444444444444), an IAM role named CrossAccountDeployRole must be created. This role has two components:
- Trust Policy: Allows the Tools account CodePipeline service role to assume it via AWS Security Token Service (STS):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:role/CodePipelineServiceRole"
},
"Action": "sts:AssumeRole"
}
]
}
- Permissions Policy: Grants permissions to deploy target resources (e.g., CloudFormation, ECS, Lambda) and access the Tools account S3 bucket and KMS CMK:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ToolsAccountKmsAndS3Access",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:DescribeKey",
"s3:GetObject*",
"s3:ListBucket"
],
"Resource": [
"arn:aws:kms:us-east-1:111111111111:key/12345678-1234-1234-1234-123456789012",
"arn:aws:s3:::central-pipeline-artifacts-111111111111/*",
"arn:aws:s3:::central-pipeline-artifacts-111111111111"
]
},
{
"Sid": "LocalDeploymentPermissions",
"Effect": "Allow",
"Action": [
"cloudformation:*",
"ecs:*",
"iam:PassRole"
],
"Resource": "*"
}
]
}
In CodePipeline, the deployment action specifies roleArn: arn:aws:iam::444444444444:role/CrossAccountDeployRole. When the action executes, CodePipeline calls sts:AssumeRole, obtains temporary credentials for Account D, fetches and decrypts the artifact from Account A's S3 bucket, and executes the deployment locally in Account D.
Governance, Approvals, and Execution Controls
Enterprise release pipelines require strict operational governance before promoting code into higher environments.
Manual Approval Actions with Amazon SNS
To prevent unvalidated code from reaching production, insert a Manual Approval Action between Staging and Production stages. The action configuration connects to an Amazon SNS Topic:
- Notification: CodePipeline publishes an approval request to the SNS topic, triggering email notifications, SMS alerts, or invoking a webhook (such as an AWS Lambda function posting to Slack or Microsoft Teams).
- Context: The action includes
CustomData(e.g., "Verify Staging smoke test results before approving release 2.4.0") and anExternalEntityLink(e.g., linking directly to Datadog/CloudWatch staging metrics dashboards). - Authorization: The approver must have the
codepipeline:PutApprovalResultIAM permission to approve or reject the transition, passing anApprovalResultcontainingStatus(ApprovedorRejected) and summary notes.
Disabling and Enabling Stage Transitions
Stage transitions can be enabled or disabled dynamically without modifying the pipeline definition:
- Freezing Deployments: During operational freeze windows (e.g., peak retail events or infrastructure migrations), engineers disable the transition into the Production stage and supply a human-readable reason string.
- Execution Behavior: Disabling a transition does not stop currently executing actions inside a stage; it simply prevents new pipeline executions from crossing the stage boundary.
- Resuming Flow: When the transition is re-enabled, the most recent execution waiting at the boundary advances automatically.
Pipeline Variables and Dynamic Parameter Overrides
CodePipeline supports Pipeline Variables that dynamically pass runtime metadata between stages without requiring intermediate S3 storage.
Declaring and Consuming Variables
- Producing Variables: In an action (such as CodeBuild or Source), declare a
namespace. For example, settingnamespace: BuildVariablesin a CodeBuild action makes all exported environment variables available under that namespace. - Default System Variables: Source actions automatically produce variables such as
#{SourceVariables.CommitId},#{SourceVariables.BranchName}, and#{SourceVariables.AuthorDate}. - Downstream Consumption: Subsequent actions reference variables using the
#{Namespace.VariableName}syntax.
CloudFormation Parameter Overrides
When deploying a containerized application, CodeBuild compiles the code, tags the Docker image with the Git commit hash, and exports IMAGE_TAG. The downstream CloudFormation deployment action dynamically overrides template parameters:
{
"ActionTypeId": {
"Category": "Deploy",
"Owner": "AWS",
"Provider": "CloudFormation",
"Version": "1"
},
"Name": "DeployToProd",
"Configuration": {
"ActionMode": "CREATE_UPDATE",
"StackName": "ProductionMicroserviceStack",
"TemplatePath": "BuildOutput::template.yml",
"ParameterOverrides": "{\"ContainerImageTag\": \"#{BuildVariables.IMAGE_TAG}\", \"GitCommit\": \"#{SourceVariables.CommitId}\"}",
"RoleArn": "arn:aws:iam::444444444444:role/CrossAccountDeployRole"
},
"InputArtifacts": [
{
"Name": "BuildOutput"
}
],
"RunOrder": 1
}
Cross-Account Troubleshooting & Watchouts
| Symptom | Root Cause | Remediation |
|---|---|---|
AccessDenied on S3 GetObject in Deploy stage | S3 bucket uses default aws/s3 KMS key, or S3 bucket policy omits the target account role | Switch S3 bucket encryption to a Customer Managed Key (CMK) and add target role to S3 bucket policy |
KMS.AccessDeniedException during artifact download | KMS CMK key policy does not delegate permissions to the target account ID | Update KMS key policy in the Tools account to include target account root ARN (arn:aws:iam::<AccountID>:root) |
AssumeRole failed: Not authorized to perform sts:AssumeRole | Target account deployment role trust policy does not list Tools account CodePipeline service role | Update target role trust policy Principal block to include arn:aws:iam::<ToolsAccountID>:role/CodePipelineServiceRole |
| Pipeline fails immediately on commit | EventBridge rule pattern does not match the repository or branch reference | Verify EventBridge event pattern detail.referenceName matches the exact branch name (e.g., main or master) |
A DevOps engineer is designing a cross-account deployment pipeline in AWS CodePipeline. The pipeline is hosted in a central Tools account (Account A) and deploys AWS CloudFormation stacks to a Production account (Account B). During pipeline execution, the CloudFormation deployment action in Account B fails with an AccessDeniedException when attempting to read the deployment template from the S3 artifact bucket located in Account A. The S3 bucket policy in Account A already grants s3:GetObject permissions to the cross-account deployment role in Account B, and the deployment role in Account B has full CloudFormation administrative permissions. What is the root cause of this failure and how should it be resolved?
A company manages multiple AWS accounts within an AWS Organization. A central Shared Services account hosts a CodePipeline pipeline that builds application artifacts and deploys them to a Staging account. The DevOps team needs to configure the pipeline action to deploy an updated ECS task definition in the Staging account using least-privilege permissions. Which combination of IAM configuration steps is required to enable CodePipeline to execute the deployment in the Staging account?
A DevOps engineer is configuring a CodePipeline pipeline that compiles a microservice in CodeBuild, produces a uniquely tagged container image, and deploys an updated CloudFormation stack. The CloudFormation template accepts a parameter named ContainerTag. The engineer needs to dynamically pass the short Git commit hash generated in the CodeBuild build phase to the CloudFormation deployment action without rebuilding or hardcoding the template. Which approach accomplishes this requirement?