Gerry Laracuente
04/20/2026, 9:03 PMterraform {
backend "s3" {
...
assume_role = {
role_arn = var.backend_assume_role_arn
}
...
}
}
• This role has permissions to read and write to the s3 bucket, and I'd like to scope down permissions so that I use a read-only role during init and plan phases, and switch to a read-write role for the apply phase.
Where I'm stuck
• I can swap in the read-write role arn before running the apply phase, but the problem I run into is that since the backend config changes, a init -reconfigure is required here.
• If I run tofu init -reconfigure before the apply, this leads to Error: Inconsistent dependency lock file
• I've also attempted tofu init -reconfigure -lockfile=readonly, but that leads to Error: Provider dependency changes detected
• At this point, my only option is to run another tofu plan, which is out of the question.
An alternative
• I can remove the assume_role out of the backend block entirely.
• This allows me to assume a read-only role to begin with (in my terminal, pipeline, etc), and I can init and plan with it
• Then I can assume a read-write role before running the apply
• This does work, but I'm reaching out for other ideas here. Ideally, I don't want to have to switch role in my terminal or pipeline. The pattern I'm trying to maintain is a single AWS role that can assume the read or write roles to the s3 bucket backend during init/plan vs apply.Erik Osterman (Cloud Posse)
04/20/2026, 9:08 PMErik Osterman (Cloud Posse)
04/20/2026, 9:08 PMErik Osterman (Cloud Posse)
04/20/2026, 9:08 PMErik Osterman (Cloud Posse)
04/20/2026, 9:08 PMErik Osterman (Cloud Posse)
04/20/2026, 9:10 PMErik Osterman (Cloud Posse)
04/20/2026, 9:10 PMErik Osterman (Cloud Posse)
04/20/2026, 9:10 PMYota
04/21/2026, 10:09 AMErik Osterman (Cloud Posse)
04/21/2026, 11:29 AMGerry Laracuente
04/21/2026, 12:58 PMErik Osterman (Cloud Posse)
04/21/2026, 1:55 PMErik Osterman (Cloud Posse)
04/21/2026, 1:55 PMErik Osterman (Cloud Posse)
04/21/2026, 1:56 PMErik Osterman (Cloud Posse)
04/21/2026, 1:56 PMErik Osterman (Cloud Posse)
04/21/2026, 1:57 PMAdrienne Cohea
05/04/2026, 6:48 AMprovider blocks to read-only on plan, read-write on apply is higher leverage for strengthening security posture. But I'm open to other perspectives. 🙂Adrienne Cohea
05/04/2026, 7:03 AMThe pattern I'm trying to maintain is a single AWS role that can assume the read or write roles to the s3 bucket backend duringIf a compromised plan job is in an environment where it has access to this single AWS role that can assume the read-only role and the read-write role anyway, then that pattern isn't guarding the state file from being altered during the plan phase anyway: if someone has RCE in the init-plan job, they could just assume the read-write role you didn't want to be able to access the remote state bucket.vsinit/plan.apply
Erik Osterman (Cloud Posse)
05/04/2026, 7:12 PMsub claim that encodes the repository and the GitHub Environment the workflow is running in. The write role’s trust policy is scoped to only allow tokens originating from a specific protected environment (e.g. prod). Since GitHub Environments can be restricted to the default branch and gated by approvals, only workflows running in that environment can ever produce a token that satisfies the trust policy.
Plan jobs (like PR workflows) run outside that environment, so even with full RCE they cannot mint a token that IAM will accept for the write role. Apply jobs, on the other hand, run inside the protected environment and can. So the boundary is enforced by IAM + OIDC + GitHub Environment protections, not by Terraform configuration.
Thus, this isn’t security theater—it’s actually a pretty elegant way to enforce least privilege in GitHub-native workflows.Adrienne Cohea
05/05/2026, 2:55 AM