Static creds → workload identity.
If your credentials are static, rotating them faster doesn't close the audit finding — only workload identity does. Twelve weeks from "we have a vault" to "the workload proves who it is to the cloud, end-to-end". Closes the Vault Theatre anti-pattern.
Inventory, classify, pick the wedge.
Phase 1 builds the credential map. Most teams discover they have 10× more static credentials than they thought, in places nobody's looked since the system was first set up.
Inventory every credential path — CI · K8s · serverless · humans.
- CI/CD: GitHub Actions secrets · GitLab CI variables · Jenkins credentials · CircleCI contexts
- Production workloads: K8s service account tokens · Lambda env vars · Cloud Function env vars · VM instance profiles
- Third-party SaaS: Datadog · PagerDuty · Slack apps · vendor integrations
- Humans: IAM users · cloud-console logins · long-lived access tokens
Spreadsheet (or ITSM record). Every static credential listed: owner · purpose · age · last-rotated · privilege scope.
Classify by blast-radius. Tackle highest first.
- Tier 0 — sovereign destroyer: AWS root account · GCP org-admin · Azure global-admin · prod DB superuser. Should be near-zero already; verify
- Tier 1 — production write: deploy keys with prod write · prod K8s admin tokens · DB write creds
- Tier 2 — production read or non-prod write: monitoring read · staging admin
- Tier 3 — low-privilege: dev-environment creds
Plan exists for retiring each. No silent unknowns at Tier 0/1.
Pick the wedge pipeline / workload — one that proves the pattern.
- Criteria: high blast-radius (so the win is meaningful) · simple enough to migrate cleanly · owned by a team that can champion the pattern
- Document the “before”: credential path · rotation cadence · last incident · audit findings
Engineering + security agree this is the right first migration. Success criteria documented.
Choose the workload-identity stack per platform.
- GitHub Actions ↔ AWS: OIDC + AWS IAM role trust policy
- GitHub Actions ↔ GCP: Workload Identity Federation
- GitHub Actions ↔ Azure: Federated Credentials
- K8s pods ↔ AWS: IRSA (IAM Roles for Service Accounts) · Pod Identity
- K8s pods ↔ GCP: Workload Identity
- K8s pods ↔ Azure: Azure AD Workload Identity
- Multi-cloud / on-prem: SPIFFE / SPIRE
Decision documented; future migrations don't re-litigate.
Migrate the wedge & document the pattern.
Phase 2 lands workload identity on the wedge pipeline end-to-end, then converts the experience into a repeatable paved-path template.
Configure trust on the cloud side.
- AWS: create IAM role with trust policy on GitHub OIDC provider · scoped to specific repo/branch (claim conditions)
- GCP: create Workload Identity Pool + Provider · service account impersonation grant
- Azure: create app registration · federated credential subject pinned to repo:branch
- Test from a sandbox repo first. Verify token-claim conditions are tight enough (no broad
repo:*)
Test assertion from sandbox succeeds. Audit log shows the federated identity + claim conditions enforced.
Migrate the wedge pipeline.
- Replace static creds: remove
AWS_ACCESS_KEY_ID/GCP_SA_KEYfrom secret store - Configure OIDC step:
actions/configure-aws-credentials@v4withrole-to-assume·aws-region— noaws-access-key-id - Run the pipeline. Pipeline succeeds → credentials never touched a secret store
- Delete the old static creds. Not "rotate one last time" — delete
Test deploy completed. Original static creds deleted (verified absent in secret store).
Document the paved-path template.
- Reusable workflow / shared action: standard OIDC-assume snippet with claim-condition examples
- Terraform module: per-pipeline cloud-side trust setup, accepts repo + branch + role-scope as inputs
- Developer-portal docs: "how to migrate your pipeline off static creds" with a 1-hour walkthrough
- Anti-pattern callouts: what NOT to do (broad claim conditions · over-broad role policies · keeping a back-up static cred “just in case”)
A team that didn't do the wedge migrates a pipeline using only the docs. Time tracked; iterate on the docs.
Migrate K8s workloads on the wedge cluster.
- Enable IRSA / GCP Workload Identity / Azure WI on the cluster
- Per service account: annotate to assume cloud role · remove static-credential mounts
- Verify pods get credentials from the metadata service · audit log shows federated identity, not service-account key
Cluster audit clean. Test pod with missing service-account assumption fails as expected.
Roll across, retire vault usage.
Phase 3 propagates the pattern across the estate and retires the static-credential paths systematically. The vault stays — for things that genuinely need a secret store — but its role shrinks.
Roll the pattern to 5 more pipelines, 2 more clusters.
- Onboarding workshop: 2-hour session for engineering leads · live-migrate one pipeline per attendee
- Office hours: weekly drop-in for engineers needing migration help
- Track migration count + time-to-onboard. Iterate on docs as patterns emerge
Critical mass. Pattern is now “how we do it”, not “the new thing”.
Retire static-creds for SaaS integrations where the vendor supports OIDC.
- Datadog · PagerDuty · Snowflake · Databricks · etc.: many now support cloud-native OIDC or short-lived tokens
- Audit each integration: vendor doc says what's possible · migrate where supported
- Leftover static-credentials: moved to a dedicated “legacy” vault namespace with quarterly rotation cadence and named owner
Legacy list shrinks each quarter. New integrations default to OIDC where available.
Detection — flag any new static credential creation.
- Cloud-side: AWS Config rule / Azure Policy / GCP Org Policy that alerts on
iam:CreateAccessKey· service-account-key creation - Source-side: PR linter that catches new
AWS_ACCESS_KEY_IDpatterns in code or YAML - Vault audit: log any new long-lived secret put. Owner must justify
Detection is the moat — without it the estate drifts back. Alarm reviewed by a named owner.
Document the “before / after” for the audit story.
- Per regulator-relevant area (APRA CPS 234 · NIST 800-53 IA-5 · E8 ML2): before-state credential count vs after-state · evidence of the rollout
- Architecture diagram: updated to show federated-identity path · static-credential removal
- External assurance / internal audit: review the work · sign off · file the evidence for next audit cycle
If APRA / IRAP / SOC 2 auditor asks “show me your credential-management posture”, you produce a binder in <1 hour, not 1 week. Vault Theatre anti-pattern closed.
End of week 13.
Once workload identity is the default, the credential rotation question vanishes — there are no static credentials to rotate. The audit finding for APRA CPS 234 / NIST 800-53 / E8 ML2+ closes structurally, not procedurally.