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.
Last updated: September 2026

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:

  1. 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.
  2. Build Stage: Compiles code, runs unit tests, analyzes code quality, and packages deployment artifacts using AWS CodeBuild or third-party build systems.
  3. Test Stage: Executes automated integration tests, load tests, compliance checks, and synthetic canaries in an isolated pre-production environment.
  4. 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 TypeLatencyAPI OverheadEvent Filtering Capability
EventBridge (Recommended)Near-real-time (best effort; no sub-second SLA)No scheduled polling callsGranular filtering by branch, tag, repository, and event type
Polling (Legacy)1–5 minutesPeriodic GetCommit or ListObjects API callsNone; 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:

  1. 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"
    }
  ]
}
  1. 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 an ExternalEntityLink (e.g., linking directly to Datadog/CloudWatch staging metrics dashboards).
  • Authorization: The approver must have the codepipeline:PutApprovalResult IAM permission to approve or reject the transition, passing an ApprovalResult containing Status (Approved or Rejected) 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

  1. Producing Variables: In an action (such as CodeBuild or Source), declare a namespace. For example, setting namespace: BuildVariables in a CodeBuild action makes all exported environment variables available under that namespace.
  2. Default System Variables: Source actions automatically produce variables such as #{SourceVariables.CommitId}, #{SourceVariables.BranchName}, and #{SourceVariables.AuthorDate}.
  3. 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

SymptomRoot CauseRemediation
AccessDenied on S3 GetObject in Deploy stageS3 bucket uses default aws/s3 KMS key, or S3 bucket policy omits the target account roleSwitch S3 bucket encryption to a Customer Managed Key (CMK) and add target role to S3 bucket policy
KMS.AccessDeniedException during artifact downloadKMS CMK key policy does not delegate permissions to the target account IDUpdate 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:AssumeRoleTarget account deployment role trust policy does not list Tools account CodePipeline service roleUpdate target role trust policy Principal block to include arn:aws:iam::<ToolsAccountID>:role/CodePipelineServiceRole
Pipeline fails immediately on commitEventBridge rule pattern does not match the repository or branch referenceVerify EventBridge event pattern detail.referenceName matches the exact branch name (e.g., main or master)
Loading diagram...
Cross-Account CodePipeline Architecture
Test Your Knowledge

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
B
C
D
Test Your Knowledge

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
B
C
D
Test Your Knowledge

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?

A
B
C
D