Cloud Automation Permission Review
Use this page before calling a cloud-aware automation path ready to run. The goal is to make permission and trust-policy work visible early, especially when a workflow, script, Lambda, role, or command gains new authority.
This page is an operations review policy, not a live permission inventory. Durable IAM resources and cloud outputs still belong to Pulumi, reviewed procedures belong to runbooks, and raw proof stays private unless reduced to a reusable lesson.
When To Use This
Section titled “When To Use This”Run this review when a change introduces or broadens:
- A GitHub Actions job that assumes an AWS role or uses a new GitHub environment secret.
- A deploy, smoke, docs, topology, or operations command that calls cloud APIs.
- A shell wrapper that sends SSM commands, invokes Lambda, pushes images, reads provider inventory, writes parameters, or mutates storage.
- A Lambda, EventBridge rule, SSM document, instance profile, OIDC role, or resource policy.
- A Pulumi change that creates, replaces, deletes, or broadens IAM, trust, DNS, runtime, storage, registry, or data-bearing resources.
- A new source of live cloud evidence such as AWS inventory, workflow artifacts, topology captures, or discrepancy reports.
Do not wait for the first failed workflow run to discover the missing grant. Trace the action, resource, and trust path before presenting the automation as ready.
Review Shape
Section titled “Review Shape”Every new or changed automation path should be explainable with this table:
| Question | Required Answer |
|---|---|
| Who acts? | The exact actor: GitHub OIDC role, runtime EC2 role, Lambda role, local infra operator, or service. |
| What API actions run? | The cloud API actions or provider CLI operations, including read, write, wait, and cleanup calls. |
| Which resources? | The smallest resource ARN, prefix, hosted-zone condition, parameter path, repository, or bucket. |
| What trust boundary? | GitHub environment subject, service principal, Lambda invoke source, instance profile, or profile. |
| What evidence appears? | Summary fields, artifact names, SSM command IDs, simulator output, smoke result, or preview line. |
| What is intentionally absent? | Explicit non-goals such as no Pulumi update, no direct EC2 stop, no S3 delete, or no secret read. |
If one answer is unknown, record the gap before mutation. Unknown permission scope is a work item, not a harmless detail.
Least-Privilege Review
Section titled “Least-Privilege Review”Prefer the narrowest authority that still lets the automation complete:
- Scope GitHub OIDC trust to the intended repository and environment.
- Prefer separate roles for app deploy, docs deploy, topology ingest, and future live inventory instead of one broad shared deploy role.
- Keep runtime host authority separate from GitHub orchestration authority.
- Use Lambda or SSM documents as explicit control-plane boundaries when direct API access would be too broad.
- Grant list/read access only where the command actually inspects state.
- Add write/delete permissions only behind explicit command names,
--executegates, or reviewed workflow inputs. - Use resource tags, parameter prefixes, repository ARNs, bucket prefixes, hosted-zone conditions, or function ARNs where the provider supports them.
- Name permission gaps beside the implementation work so the reviewer can see whether the code and IAM change belong in one patch or separate approvals.
Some AWS APIs require broad read scope or * resources. When that happens, document why the service requires it and keep
the mutating action narrow.
Deployed-Dev Actor Pattern
Section titled “Deployed-Dev Actor Pattern”The current deployed-dev shape intentionally splits authority:
| Actor | Owns | Should Not Own |
|---|---|---|
| GitHub operator deploy role | Explicitly selected runtime deploy/reset/readback, database operations, selected smoke permissions, shutdown invoke, image push, deployment-contract reads and canonical release receipt publication. | Automatic application delivery, Pulumi updates, broad inventory, runtime secret reads, or docs publishing. |
| GitHub application-admission role | Exact current deployment contract/release receipt and release-version reads under a separate environment OIDC subject. | Image publication, runtime secrets, SSM commands or other mutation. |
| GitHub application-delivery role | Modeled ECR publish/readback, guarded runtime/record actions, exact private maintenance alias, contract/receipt access, exact version and three public frontend-build parameter reads. | Database maintenance, arbitrary shell, other parameter reads/writes, Pulumi, media mutation or direct EC2 control. |
| GitHub docs deploy role | Docs bucket object writes/deletes, docs CloudFront invalidation, and read-only deployment contract artifact access. | App/API runtime mutation, app media buckets, ECR repositories, SSM runtime parameters, deployment contract writes, or DNS. |
| Runtime EC2 role | Pull modeled images, read runtime parameters, set the exact release-version parameter, access media storage, and register with SSM. | GitHub orchestration, Route53 control-plane writes, shutdown authority, or workflow summaries. |
| Wake Lambda role | Invoke only the coordinator’s qualified public-wake alias and write its own logs. | EC2/SSM/DNS authority, maintenance state or reopen/stop capability. |
| Shutdown Lambda role | Invoke only the coordinator’s qualified shutdown alias and write its own logs. | Direct EC2/SSM/DNS authority, public URL or maintenance ownership. |
| Inactivity monitor Lambda role | Describe the configured host, run the fixed parameterless activity-readback SSM document on that instance, read the command result and invoke the existing shutdown Lambda. | Arbitrary shell/document/instance selection, parameter/secret reads, direct stop, DNS or release mutation. |
| GitHub infra-topology role | Prefix-scoped read-only access to Tendril’s /wavemap state namespace for manual private topology capture and workflow artifact upload. | Pulumi updates, application/docs delivery, deployment contract writes, live AWS inventory, docs publish, commits, or cloud mutation. |
The manual operator role receives the same bounded application-delivery policy for image publication, release receipts, frontend build inputs, the modeled host document and the private maintenance alias. Reusing this policy keeps both delivery paths aligned when the public image or lifecycle contract changes. Its existing privileged database/shell grants and OIDC trust remain separately managed; application delivery never inherits those operator grants.
The public API fallback role invokes only the public-wake alias. Its Function URL uses IAM/OAC with both invoke permissions scoped to the exact CloudFront distribution. The private lifecycle coordinator alone receives exact-instance start/stop, exact-parameter get/put and UPSERT authority for the single origin A record. Its Lambda trust is service-only; EventBridge invokes only the DNS alias from the exact running-instance and reconciliation rules. DescribeInstances and GetCommandInvocation require resource wildcard reads; that exception does not widen mutation targets.
The host retains AmazonSSMManagedInstanceCore for agent registration and messaging. That AWS-managed policy also allows GetParameter/GetParameters on all resources; a narrower runtime-prefix Allow cannot cancel it. The modeled host policy therefore explicitly denies direct and history reads of the lifecycle state. GetParametersByPath is granted only under the runtime prefix. Review the effective union of managed, inline, attached, boundary and organization policies; do not claim that the runtime-prefix policy alone confines every host parameter read. Public-container metadata denial remains a separate required boundary. See the AWS-managed policy definition.
When a new actor is needed, add it deliberately. Do not quietly reuse the nearest existing role if the new job has a different trust boundary, evidence path, or blast radius.
Readiness Checklist
Section titled “Readiness Checklist”Before a cloud automation change is ready for review:
- The owning actor and trust boundary are named.
- The planned cloud API actions are listed, including wait/readback calls.
- The target resources are scoped as tightly as the provider allows.
- The explicit non-goals are written down.
- The command or workflow has a dry-run, preview, or no-mutation mode where practical.
- Mutating execution has a clear
--execute, workflow input, environment protection, or human approval gate. - Required IAM, resource policy, trust-policy, or Pulumi changes are included in the scoped work or called out as a separate approval-gated step.
- The expected evidence is safe to publish in workflow summaries, docs, or private artifacts.
- Secret values, rendered env files, raw cloud inventory, and live identifiers do not cross the public docs boundary.
Documentation Handoff
Section titled “Documentation Handoff”Use the narrowest durable home for the result:
| Result Type | Home |
|---|---|
| Pulumi-owned role, policy, trust, resource, output, or lifecycle class | Infrastructure Change Policy plus IaC source |
| Pipeline actor, job responsibility, profile, cloud plan, or CD secret flow | Deployment Workflows |
| Repeated operator command, failure triage, reset, rollback, or recovery | Runbooks |
| Docs deploy role, docs bucket permissions, docs invalidation, publish gate | Docs Hosting |
| Private raw evidence, sanitized projection, topology graph, publication gate | Generated Documentation |
| Command name, flag, compatibility script, or default mutation posture | Wavemap CLI Command Reference |
Working notes may keep detailed proof history while the shape is moving. Once the actor boundary is stable, promote the reusable lesson here or into the owning operations page.