Every customer account's trust policy names the reaper's execution role by an ARN containing a CloudFormation-generated physical ID:
arn:aws:iam::966362334030:role/spawn-ttl-reaper-production-TTLReaperFunctionRole-ZJ84YZ2dCPei
^^^^^^^^^^^^
Recreating the spawn-ttl-reaper-production stack regenerates that suffix. Every trust policy referencing the old ARN then denies, simultaneously, across every account.
Why it is worse than it sounds
This is #457 trap 1, and #469 documented the consequence precisely: from the reaper's side, "our role ARN changed" is indistinguishable from "the entire customer base uninstalled at once." #469's per-account aggregation means each broken account contributes 1 to AccountsDenied, and REAPER REACHED NO ACCOUNTS fires — which is the correct signal, but the operator sees a mass-uninstall shape and has to already know about this trap to look at the role ARN first. (The README's alarm table says "investigate our side first — the #457 role-ARN suffix" for exactly this reason.)
Recovery is O(number of accounts) and needs admin in each: every account must redeploy ttl-reaper-cross-account-role.yaml with the new ARN. For third-party accounts that means asking each owner. There is no way to fix it from the infra account alone.
Now affecting 2 accounts, not 1
435415984226 (Mycelium Development)
942542972736 — added 2026-07-31
Each account added multiplies the blast radius. Fixing this gets strictly more expensive over time and is cheapest now.
Proposed fix
Give the function role a stable, explicit name so its ARN is deterministic and stack-recreation-safe:
TTLReaperFunctionRole:
Properties:
RoleName: !Sub 'spawn-ttl-reaper-${Environment}-role'
Requires CAPABILITY_NAMED_IAM (the Makefile currently passes only CAPABILITY_IAM) and blocks a no-downtime rename, since the role cannot be renamed in place. Migration is the careful part and must not lock us out mid-flight:
- Add the new stable-named role alongside the existing one.
- Have each account's trust policy accept both principals.
- Cut the function over to the new role; confirm
AccountsDenied: 0.
- Drop the old principal from each account, then the old role.
A Path-based ARN or a dedicated non-SAM role stack are alternatives; the two-principal migration is the part that matters regardless of which is chosen.
Acceptance
- The reaper's role ARN survives a full stack delete/recreate.
deployment/cloudformation/ttl-reaper-cross-account-role.yaml documents that the ARN is now stable.
- Migration does not require simultaneous redeploys across accounts.
Related: #457 (trap 1), #469 (why the failure presents as mass-uninstall).
Every customer account's trust policy names the reaper's execution role by an ARN containing a CloudFormation-generated physical ID:
Recreating the
spawn-ttl-reaper-productionstack regenerates that suffix. Every trust policy referencing the old ARN then denies, simultaneously, across every account.Why it is worse than it sounds
This is #457 trap 1, and #469 documented the consequence precisely: from the reaper's side, "our role ARN changed" is indistinguishable from "the entire customer base uninstalled at once." #469's per-account aggregation means each broken account contributes 1 to
AccountsDenied, andREAPER REACHED NO ACCOUNTSfires — which is the correct signal, but the operator sees a mass-uninstall shape and has to already know about this trap to look at the role ARN first. (The README's alarm table says "investigate our side first — the #457 role-ARN suffix" for exactly this reason.)Recovery is O(number of accounts) and needs admin in each: every account must redeploy
ttl-reaper-cross-account-role.yamlwith the new ARN. For third-party accounts that means asking each owner. There is no way to fix it from the infra account alone.Now affecting 2 accounts, not 1
435415984226(Mycelium Development)942542972736— added 2026-07-31Each account added multiplies the blast radius. Fixing this gets strictly more expensive over time and is cheapest now.
Proposed fix
Give the function role a stable, explicit name so its ARN is deterministic and stack-recreation-safe:
Requires
CAPABILITY_NAMED_IAM(the Makefile currently passes onlyCAPABILITY_IAM) and blocks a no-downtime rename, since the role cannot be renamed in place. Migration is the careful part and must not lock us out mid-flight:AccountsDenied: 0.A
Path-based ARN or a dedicated non-SAM role stack are alternatives; the two-principal migration is the part that matters regardless of which is chosen.Acceptance
deployment/cloudformation/ttl-reaper-cross-account-role.yamldocuments that the ARN is now stable.Related: #457 (trap 1), #469 (why the failure presents as mass-uninstall).