RAPID INCIDENT TRIAGE & ACTION PLAN•Security
01. Error Signature
CodeBuild AssumeRole TagSession Permission Fix
02. Root Cause Vector

CodeBuild fails with AccessDeniedException because the calling principal's IAM policy is missing sts:TagSession, blocking role assumption...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Security

CodeBuild AssumeRole TagSession Permission Fix

CodeBuild fails with AccessDeniedException because the calling principal's IAM policy is missing sts:TagSession, blocking role assumption entirely.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(98L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# TODO: This was a quick fix for PCI compliance, but we need to refactor the IAM roles.
# WARNING: This config is used by the legacy 'pci-secure-zone' deployment pipeline.
# Old role arn (commented out): arn:aws:iam::123456789012:role/legacy-codebuild-role

AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template for CodeBuild project in legacy VPC.

Parameters:
  EnvironmentName:
    Type: String
    Default: prod-pci
    Description: Environment name (e.g., prod-pci, staging)

Resources:
  # CodeBuild project for the internal legacy API image builds.
  LegacyAPICodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${EnvironmentName}-legacy-api-build"
      ServiceRole: !GetAtt CodeBuildServiceRole.Arn
      Source:
        Type: CODEPIPELINE
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        Type: LINUX_CONTAINER
        ComputeType: BUILD_GENERAL1_SMALL
        Image: "my-registry.internal/legacy-api:build-2022-01"
        EnvironmentVariables:
          - Name: "DB_CONNECTION_URI"
            Value: "postgresql://admin:AKIAIOSFODNN7EXAMPLE@legacy-db.internal:5432/pci_db?sslmode=require"
            Type: PLAINTEXT
          - Name: "STRIPE_SECRET_KEY"
            Value: "sk_live_4eC39HqLyjWDarjtT1zdp7dc"
            Type: PLAINTEXT
          - Name: "LEGACY_API_KEY"
            Value: "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAr4t5qL3vL2q7z... (truncated for brevity) ...\n-----END RSA PRIVATE KEY-----"
            Type: PLAINTEXT
      VpcConfig:
        VpcId: vpc-0a1b2c3d4e5f67890
        Subnets:
          - subnet-12345678
          - subnet-87654321
        SecurityGroupIds:
          - sg-0fedcba9876543210

  # IAM Role for CodeBuild - this is the problematic role.
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${EnvironmentName}-codebuild-service-role"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub "${EnvironmentName}-codebuild-policy"
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              # TODO: This policy is a mess from the VPC migration. Needs cleanup.
              - Effect: Allow
                Action:
                  - ec2:CreateNetworkInterface
                  - ec2:DescribeNetworkInterfaces
                  - ec2:DeleteNetworkInterface
                  - ec2:DescribeSubnets
                  - ec2:DescribeSecurityGroups
                Resource: "*"
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: "*"
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: "arn:aws:s3:::artifact-bucket-${EnvironmentName}/*"
              # VULNERABILITY: Missing sts:TagSession permission when assuming roles from within the build.
              # The build script internally tries to assume a cross-account role for deployment, but this base role lacks the tag permission.
              - Effect: Allow
                Action: sts:AssumeRole
                Resource: "arn:aws:iam::987654321098:role/deploy-role-${EnvironmentName}"
      # Tags added for cost allocation, but the role itself cannot tag the session.
      Tags:
        - Key: "CostCenter"
          Value: "PCI-12345"
        - Key: "ManagedBy"
          Value: "Terraform"

# Note: The deployment script in the buildspec.yml uses 'aws sts assume-role --role-arn arn:aws:iam::987654321098:role/deploy-role-* --role-session-name build-session'.
# This fails with AccessDeniedException because sts:TagSession is not allowed on the CodeBuildServiceRole.
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

Fixing CodeBuild AccessDeniedException: Missing sts:TagSession Permission for AssumeRole

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 5–10 mins


TL;DR

  • What broke: CodeBuild's service role (or the role it's trying to assume) is missing sts:TagSession, causing AssumeRole to hard-fail with AccessDeniedException.
  • How to fix it: Add sts:TagSession to the IAM policy attached to the principal initiating the AssumeRole call — not the target role's trust policy.
  • Fast path: Use our Client-Side Sandbox above to auto-refactor your failing policy. Paste it in, get the corrected version without sending your ARNs to a third-party server.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

You hit this in your CodeBuild build logs or CloudTrail:

An error occurred (AccessDeniedException) when calling the AssumeRole operation:
User: arn:aws:sts::123456789012:assumed-role/CodeBuildServiceRole/session
is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::123456789012:role/TargetDeployRole
with an explicit deny or missing permission: sts:TagSession

Immediate consequence: The build pipeline stops cold. No deployment proceeds. If this role assumption is part of a cross-account deploy, staging or production pushes are completely blocked. The error message is deliberately vague — AWS bundles the sts:TagSession denial into the AssumeRole failure, which is why engineers waste 30+ minutes chasing the wrong permission.

Root cause: When session tags are passed during AssumeRole (either explicitly in your buildspec or implicitly by a service like CodePipeline passing PrincipalTag context), AWS requires the calling principal to have sts:TagSession on the target role resource. Without it, the entire AssumeRole call is rejected — not just the tagging.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This is a least-privilege enforcement gap, not a vulnerability in the traditional sense — but misconfiguring the fix creates real risk.

The wrong fix engineers reach for: Granting sts:* or sts:AssumeRole with Resource: "*" to make the error go away. That's now a critical misconfiguration. Any principal with that policy can assume any role in the account that has a permissive trust policy, including roles with AdministratorAccess.

Blast radius of the lazy fix:

  • Compromised CodeBuild execution environment (supply chain attack via a malicious dependency) can call sts:AssumeRole on high-privilege roles.
  • Lateral movement across accounts if cross-account roles exist with weak trust policies.
  • Privilege escalation path: CodeBuild role → sts:AssumeRole * → AdminRole → full account compromise.

The correct blast radius is zero — sts:TagSession scoped to the exact target role ARN adds no new attack surface.


How to Fix It (The Solution)

Basic Fix

Add sts:TagSession to the IAM policy attached to your CodeBuild service role, scoped to the specific target role ARN.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
-       "sts:AssumeRole"
+       "sts:AssumeRole",
+       "sts:TagSession"
      ],
      "Resource": "arn:aws:iam::123456789012:role/TargetDeployRole"
    }
  ]
}

Critical: Resource must be the exact ARN of the role being assumed. Never "*".


Enterprise Best Practice (Condition Key Locking)

Scope sts:TagSession further using aws:RequestedRegion and sts:TransitiveTagKeys condition keys to prevent tag-based privilege escalation via transitive session tags.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAssumeDeployRole",
      "Effect": "Allow",
      "Action": [
-       "sts:AssumeRole"
+       "sts:AssumeRole",
+       "sts:TagSession"
      ],
      "Resource": "arn:aws:iam::123456789012:role/TargetDeployRole",
+     "Condition": {
+       "StringEquals": {
+         "aws:RequestedRegion": "us-east-1"
+       },
+       "ForAllValues:StringEquals": {
+         "sts:TransitiveTagKeys": ["Project", "Environment"]
+       }
+     }
    }
  ]
}

Why sts:TransitiveTagKeys matters: Without this condition, a compromised build could inject arbitrary session tags that propagate to subsequent AssumeRole chains, potentially satisfying ABAC conditions on high-privilege roles downstream.

Also verify the target role's trust policy allows tagged sessions from your CodeBuild role:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/CodeBuildServiceRole"
      },
-     "Action": "sts:AssumeRole"
+     "Action": [
+       "sts:AssumeRole",
+       "sts:TagSession"
+     ]
    }
  ]
}

💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. Checkov (IaC scanning — catches this pre-merge):

Add a custom Checkov check or use the built-in CKV_AWS_110 / CKV_AWS_111 rules to flag any sts:AssumeRole statement missing a paired sts:TagSession when session tags are in use. Run in your PR pipeline:

checkov -d ./iam --framework cloudformation --check CKV_AWS_110

2. OPA / Conftest Policy (enforce in Terraform plan):

deny[msg] {
  stmt := input.resource.aws_iam_policy.document.statement[_]
  "sts:AssumeRole" == stmt.actions[_]
  not contains_tag_session(stmt.actions)
  msg := sprintf("IAM policy '%v' has sts:AssumeRole without sts:TagSession", [input.resource.aws_iam_policy.document])
}

contains_tag_session(actions) {
  actions[_] == "sts:TagSession"
}

3. AWS Config Rule: Enable iam-policy-no-statements-with-admin-access and write a custom Config rule that flags CodeBuild service roles missing sts:TagSession when cross-role assumptions are detected in CloudTrail.

4. Terraform aws_iam_role_policy module pattern: Enforce a reusable module for all CodeBuild roles that always pairs sts:AssumeRole with sts:TagSession and mandates a non-wildcard Resource. Block direct aws_iam_policy_document usage outside the module via Sentinel (Terraform Cloud) or OPA.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Why does sts:TagSession cause AssumeRole to fail completely instead of just failing the tag operation?
AWS evaluates the entire AssumeRole request atomically. If session tags are included in the request—whether explicitly or injected by a service like CodePipeline—and the calling principal lacks sts:TagSession on the target role, IAM denies the entire AssumeRole call. There is no partial success; it's an all-or-nothing security gate. This is the deep, non-negotiable root cause: missing a single, often-overlooked permission collapses the entire chain of trust.
Q2.Do I need to add sts:TagSession to the target role's trust policy, the calling role's permission policy, or both?
Both, and missing either one is a critical misconfiguration that will blow up your pipeline. Manually editing IAM policies is a high-risk, error-prone trap—one misplaced ARN or condition can open a dangerous blast radius. Don't waste time guessing. Drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix with precise, least-privilege permissions in seconds.
Q3.Is this error specific to CodeBuild, or can it happen with other AWS services?
This is a systemic risk across AWS. Any service or principal that calls AssumeRole with session tags—CodePipeline, Lambda, ECS, CI/CD tooling—will hit this same landmine. At enterprise scale, across hundreds of mono-repos and pipelines, manual fixes become a compliance and audit nightmare. Upgrade to the StackEngine CI/CD Automator (Team Edition) for on-prem, automated pull request generation with Maker-Checker review and policy governance that eliminates this class of error across your entire organization.