Executive summary. I can eliminate the need for attaching AdministratorAccess to a Terraform apply role by treating the system as three coupled controls: (a) OIDC trust hardening (who can assume the role), (b) permission modularisation + ABAC (what the role can do, without a permission-drip treadmill), and (c) organisation guardrails (what can never happen, even if (a) or (b) fail). The biggest practical risk is not “OIDC breaks”; it’s mis-scoped trust conditions and over-broad role permissions turning any compromised Spacelift run context into cross-account compromise via AssumeRoleWithWebIdentity. citeturn0search6turn5search0turn15view0turn13view0turn0search32
The AdministratorAccess problem is structural: Terraform executes imperative API calls to converge reality to HCL intent, so a single “apply” identity becomes a high-value target. If the identity is admin, a compromise becomes “full account control,” not “limited service impact.” AWS explicitly recommends starting from minimum permissions and adding only what’s needed; it also recommends using IAM Access Analyzer policy generation from CloudTrail to refine towards least privilege instead of defaulting to broad managed policies. citeturn1search28turn1search1turn1search4
Threat model: what changes when Spacelift OIDC trust is compromised. Spacelift issues an OIDC JWT token to runs; the token is available inside the run environment (including at /mnt/workspace/spacelift.oidc) and is valid for one hour. That token can be exchanged with AWS STS for temporary credentials via AssumeRoleWithWebIdentity if the IAM role trust policy accepts the token’s claims. citeturn12view1turn13view0turn0search6
Attacker capabilities (practical, not hypothetical).
/mnt/workspace/spacelift.oidc and calling aws sts assume-role-with-web-identity, which is a strong signal that token theft is a credible risk if the run environment is compromised. citeturn13view0turn0search6aud and sub), tokens from unintended workloads can assume the role. Security research from entity[“company”,“Wiz”,“cloud security company”] highlights that missing/incorrect IAM trust-policy conditions in AWS OIDC integrations can allow undesired access. citeturn0search32turn10view1How AWS makes this observable (and why you should care). AWS documents that CloudTrail logs authenticated IAM and STS API calls and also logs non-authenticated requests to STS actions including AssumeRoleWithWebIdentity, including information provided by the identity provider. This is essential for detection, tuning, and rollback during migration. citeturn5search0turn5search8
This report targets teams running Terraform via entity[“company”,“Spacelift”,“iac automation platform”] against entity[“company”,“Amazon Web Services”,“cloud provider”] across multiple accounts, typically with Terraform distributed by entity[“company”,“HashiCorp”,“terraform vendor”]. Your “TerraformApplier” role is assumed using Spacelift-issued OIDC tokens (AssumeRoleWithWebIdentity) and must support common workflows like plan/apply, state backends (S3 + optional DynamoDB locking), and service provisioning (ECR, EKS, RDS) while avoiding a permissions maintenance cliff. citeturn12view1turn0search6turn1search0
What Spacelift actually gives you (claims you can enforce). Spacelift’s OIDC token includes:
aud: hostname of your Spacelift account (unique per account),sub: a structured subject string: space:<space_id>:(stack|module):<stack_id|module_id>:run_type:<run_type>:scope:<read|write>,exp: one-hour token lifetime,spaceId, callerType, callerId, runType, runId, scope. citeturn12view1turn0search5turn15view0Important nuance: scope is advisory. Spacelift states that the scope claim (and other claims) are “merely advisory” and it is up to you to decide whether/how to control external access based on claims like scope, space, caller, and run type. This means your security posture is determined by your IAM trust/policy design—not by Spacelift defaults. citeturn13view0turn12view1
Unspecified assumptions I will not invent. You did not specify: AWS account naming conventions, OU layout / organisation structure, environment boundaries (dev/stage/prod patterns), tagging standards (required tags, keys, enforcement), region strategy, or whether you use a hub (“tooling”) account to broker into member accounts vs per-account direct OIDC roles. I’ll provide designs that work for multiple shapes and call out where you must choose. citeturn1search11turn1search2
I recommend modelling this as three concentric enforcement rings:
flowchart TB
subgraph Ring1["Ring 1: OIDC Trust (Who can assume?)"]
A[OIDC provider: <SPACELIFT_HOST>]
B[Role trust policy checks: aud + sub + optional tag/session controls]
end
subgraph Ring2["Ring 2: IAM Permissions (What can it do?)"]
C[Base policies: state + locking + KMS]
D[Capability policies: ECR / EKS / RDS / limited IAM]
E[ABAC: session tags & resource tags]
end
subgraph Ring3["Ring 3: Guardrails (What can never happen?)"]
F[SCPs + permission boundaries + monitoring]
end
A --> B --> C --> D --> E --> F
This aligns with AWS’s separation between trust policies (assume conditions) and identity policies/boundaries, and with Spacelift’s design of exposing claims/tags for you to consume. citeturn10view0turn0search3turn13view0turn15view2
Scope by account and environment first (blast radius). AWS Organisations SCPs are designed as account/OU guardrails; they don’t grant permissions but define maximum permissions boundaries across accounts, which is a perfect fit for constraining CI/CD roles organisation-wide. citeturn1search2turn1search8
Scope by workspace/stack identity (who/where in CI/CD). Spacelift’s sub claim format intentionally includes space, stack/module, run type, and scope. Spacelift also documents wildcarding rules and custom subject templates (space path) so you can build either per-stack trust or hierarchical “all prod under this branch” trust. citeturn12view1turn15view0turn0search1turn6search20
Scope by action and resource type, but design for sustainability.