AWS 405: Pipeline and deployment-role least privilege with temporary credentials
Why this lesson matters
A delivery system is a chain of principals, not one powerful pipeline role. A compromised source job should not become an organization administrator. Architects must separate orchestration, build, artifact, deployment, infrastructure and runtime authority; use temporary sessions; constrain trust and iam:PassRole; and prove both permitted and denied paths.
Identity and credential model
Long-term access keys do not belong in repositories, build variables or runner disks. AWS-native services receive temporary credentials through service roles. External CI systems should federate through an IAM OIDC/SAML identity provider or another approved broker, exchange a signed workload identity for an STS session, and avoid stored AWS keys.
A role has two authorization surfaces. Its trust policy answers who may obtain a session and under what conditions. Its permissions policy answers what that session may do. Session policies, permissions boundaries, SCPs, resource policies, VPC endpoint policies and explicit denies can further reduce effective permission. No single Allow proves authorization.
Use short session duration, meaningful RoleSessionName, source identity where supported and session tags only from trusted claims. CloudTrail must tie the assumed-role session to repository, workflow, commit, environment and approver without putting secrets in tags. Revocation is not instant for issued sessions, so contain by disabling trust, denying sensitive calls and respecting maximum session lifetime.
Separate delivery roles
The pipeline role reads pipeline configuration and starts stages. The build role reads exact source/artifact versions, writes its output and logs, but cannot deploy. The artifact role or policies control versioned object/KMS use. A deployment role mutates only the target application/environment. A CloudFormation execution role controls resources a stack can create. Runtime roles belong to workloads and are never inherited by deployment jobs.
iam:PassRole does not assume a role; it lets a principal tell an AWS service which role to use. Restrict it to exact role ARNs and expected service using iam:PassedToService where applicable. Prevent creation or modification of policies, roles, trust, boundaries and pipelines that would let the principal manufacture a privilege-escalation path.
| Principal | Required authority | Must not have |
|---|---|---|
| Pipeline orchestrator | Start approved stages, read state | Build, deploy or change IAM directly |
| Build role | Read exact source, write candidate | Production mutation or signer administration |
| Deployment role | Deploy approved digest to one environment | Change pipeline, source or unrelated accounts |
| Stack execution role | Manage declared stack resources | Self-edit trust/policy or pass arbitrary roles |
| Runtime role | Application data-plane calls | Pipeline/artifact administration |
| Investigator | Read logs, policy and trail evidence | Routine deployment mutation |
Cross-account promotion uses one narrowly trusted role per environment/account. Bind trust to the source principal and context. For third parties use a unique external ID where appropriate. For service principals use supported aws:SourceArn, aws:SourceAccount or organization conditions to reduce confused-deputy risk. For OIDC validate issuer, audience and precise subject claims such as approved repository, branch/tag and protected environment; a wildcard subject can make every repository a production principal.
Policy design and proof
Start from actions observed in a successful isolated deployment, then add documented read and rollback actions. Scope resources, Regions, tag conditions and KMS encryption context where the service supports them. Do not blindly paste console-generated wildcards. Some list/describe APIs require Resource: "*"; keep those read-only and separate from mutation.
aws iam get-role --role-name ProductionDeployRole
aws iam list-attached-role-policies --role-name ProductionDeployRole
aws iam list-role-policies --role-name ProductionDeployRole
aws accessanalyzer validate-policy --policy-type IDENTITY_POLICY \
--policy-document file://deploy-policy.json
aws iam simulate-principal-policy --policy-source-arn ROLE_ARN \
--action-names s3:GetObject cloudformation:UpdateStack iam:CreateUser
Validation and simulation find classes of error but do not model every control or live resource context. Use isolated positive and negative integration tests. Prove the job can fetch only the approved digest, deploy to the intended environment, pass only the intended execution role and roll back. Prove it cannot access another environment, alter IAM, disable logs, decrypt unrelated data, change its pipeline or deploy an unapproved artifact.
Workshop and threat analysis
Draw every STS hop for a three-account dev/test/production pipeline. Write trust and permission pseudopolicies, a PassRole matrix, credential lifetime/revocation plan and CloudTrail evidence query. Analyze source-fork, pull-request, branch, tag, environment-approval and runner-compromise paths. Separate who can change pipeline code, approve production, change trust, change artifacts and investigate logs.
Test 22 failures: static key, key in cache, broad OIDC subject, wrong audience, fork trusted, service principal unconstrained, reused external ID, wildcard trust, role chain expiry, tags supplied by attacker, broad PassRole, mutable execution role, build can deploy, deploy can alter IAM, prod role trusts dev wildcard, artifact substitution, unrelated KMS decrypt, missing boundary, SCP denial misdiagnosed, simulator treated as proof, CloudTrail identity ambiguous, and issued session not considered during revocation.
Cost and acceptance
IAM, STS and policy analysis may have no direct charge, but CI runtime, logs, artifact/KMS usage and test deployments do. This lesson creates nothing. Submit identity/data-flow diagrams, role matrix, trust/permission designs, escalation analysis, positive/negative tests, CloudTrail evidence and all failure diagnoses. Pass requires no long-term key, narrow trust, constrained PassRole, environment separation and reproducible denial evidence.