Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXCIII · Credential RotationCloudCredentials

Cloud credential rotation — IAM access keys and OIDC federation

Advanced⏱ ~26 mingitaws-cli

What you'll learn

  • Generate an AWS IAM access key for a service user using the AWS CLI
  • Execute the two-key rotation pattern that prevents downtime during cutover
  • Identify the OIDC federation pattern as the long-term replacement for access keys
  • Apply the discipline of preferring short-lived STS credentials over long-lived access keys

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A cloud credential authenticates the deploy job to the cloud. The two patterns are long-lived access keys (a static string the job presents to the cloud) and OIDC federation (the workflow exchanges its platform token for a short-lived STS credential). Both have rotation procedures; only OIDC has a short enough lifetime that rotation becomes rare. This lesson walks both procedures and the CLI commands that execute them.

The two-key rotation pattern

AWS IAM allows a user to hold two access keys at once. The two-key pattern uses both slots: the deploy job is configured with the primary key, the secondary key sits in reserve, and rotation walks the secondary through validation before the primary is retired.

flowchart LR
    A["Slot A: current primary"] --> B["Slot B: secondary in reserve"]
    B --> C["Rotate: issue new key in slot B"]
    C --> D["Distribute new key to CI secret store"]
    D --> E["Test new key with read-only API call"]
    E --> F["Cut over: switch deploy job to slot B"]
    F --> G["Disable primary key in slot A"]
    G --> H["Wait one rotation cycle"]
    H --> I["Delete primary key from slot A"]

The “wait one rotation cycle” step is the discipline. A deleted key is a key that cannot be recovered; a disabled key is a key that can be re-enabled if the cutover surfaces an undocumented reader. The team disables, watches logs for failures, and deletes only after a full rotation cycle has elapsed without incident.

Issuing the new key

The AWS CLI command to issue a new access key for an IAM user:

aws iam create-access-key --user-name "$DEPLOY_USER" \
  --query 'AccessKey.[AccessKeyId,SecretAccessKey]' \
  --output text

The command returns the new access key ID and secret access key as a tab-separated pair. The --user-name flag takes the IAM user name; the $DEPLOY_USER shell variable is the user the team has provisioned for CI deploys. The --query filter limits the output to the two fields the team needs to write to the secret store.

Distributing and validating

The new key must reach every reader before the primary key is disabled. The distribution is environment-specific:

gh secret set AWS_ACCESS_KEY_ID --env production --body "$NEW_KEY_ID"
gh secret set AWS_SECRET_ACCESS_KEY --env production --body "$NEW_SECRET"

The two commands write the new key ID and secret to the production environment’s secret store. The --env production flag scopes the secret to the environment, which means the production deploy job reads it but a PR build does not. After distribution, the key is validated:

AWS_ACCESS_KEY_ID="$NEW_KEY_ID" AWS_SECRET_ACCESS_KEY="$NEW_SECRET" \
  aws sts get-caller-identity

The get-caller-identity call is read-only, requires no special permissions, and returns the IAM user’s ARN. A successful call proves the new key authenticates; an unsuccessful call proves the cutover should not proceed.

Retiring the primary key

Once the new key is validated, the primary is disabled and eventually deleted.

aws iam update-access-key \
  --user-name "$DEPLOY_USER" \
  --access-key-id "$OLD_KEY_ID" \
  --status Inactive

aws iam delete-access-key \
  --user-name "$DEPLOY_USER" \
  --access-key-id "$OLD_KEY_ID"

The first command disables the key; authentication attempts with it fail, but the key still exists in case reactivation is needed. The second command deletes the key after the rotation cycle has elapsed. A team that skips the disable phase and goes straight to delete has no rollback if the cutover surfaces an undocumented reader a week later.

OIDC federation: the long-term replacement

The two-key pattern still produces a long-lived credential

  • it just rotates the credential more frequently. The durable fix is OIDC federation, which produces a credential that has a one-hour lifetime and is issued fresh on every job.
flowchart TD
    A["GitHub Actions job starts"] --> B["Platform issues OIDC token"]
    B --> C["Workflow calls aws-actions/configure-aws-credentials"]
    C --> D["AWS STS exchanges OIDC for STS credential"]
    D --> E["STS credential valid for 1 hour"]
    E --> F["Job ends; STS credential discarded"]

The OIDC pattern requires three pieces of configuration: an IAM role with a trust policy that accepts the platform’s OIDC tokens, an aud and sub claim condition that constrains which workflows can assume the role, and a workflow step that performs the exchange. The result is that no long-lived AWS credential exists in the team’s secret store; the credential is born at job start and dies at job end.

Production discipline

  1. Use the two-key pattern for access keys. Never rotate by deleting the only key.
  2. Capture the SecretAccessKey at creation. It is unrecoverable after the command returns.
  3. Disable before delete. A deleted key is unrecoverable; a disabled key can be re-enabled.
  4. Prefer OIDC federation over access keys. Short-lived STS credentials are the durable answer.
  5. Constrain the OIDC trust policy by sub and aud. A trust policy that accepts any workflow is not a trust policy.

Cross-course references

  • This course, Part XLIII-04 (OIDC in AWS) covers the trust policy mechanics in depth.
  • This course, Part XCI-04 (Ephemeral per-job credentials) covers the broader pattern of short-lived credentials.
  • Terraform for Production Sysadmins, Part XXIII (AWS provider authentication) covers the provider-side configuration that consumes these credentials.

Quiz

Knowledge check · 4 questions

  1. Q1. A team rotates an IAM access key by issuing a new key, deleting the old key, and updating the CI secret store. Mid-deployment, an undocumented reader (a cron job outside the CI system) fails because it still holds the deleted key. What was the operational mistake?

  2. Q2. The OIDC federation pattern replaces an IAM access key with a long-lived STS credential that the workflow obtains at job start.

  3. Q3. Name the two AWS CLI commands that retire an old access key and identify which one is reversible.

  4. Q4. Diagnose why a team that has migrated its CI workflow to OIDC federation still finds IAM access keys for the deploy user in the team password vault.

    A team migrated its primary deploy workflow to OIDC federation in 2025. The CI workflow no longer holds an access key; it exchanges an OIDC token for a short-lived STS credential. However, an audit in 2026 finds two IAM access keys for the deploy user still listed as Active. The team's runbook says 'use OIDC' but does not say 'delete the access keys'.

Passing score: 75%. Answers are checked in this browser.