# how to set up short-lived credentials for CI

## TL;DR

Stop putting long-lived cloud keys in CI secrets. Use OIDC federation so each workflow run mints a short-lived credential that dies when the job ends, or use your vault's dynamic secrets. The setup is a trust policy on the cloud side plus a permissions tweak on the CI side, and then there is nothing to rotate or leak.

```text
how to set up short-lived credentials for CI
```

## Use this when

- A static deploy key or cloud access key has lived in CI secrets for way too long
- You are setting up a new pipeline and want to do it right from the start
- An audit flagged long-lived CI credentials
- A CI secret leaked and you want the replacement to be better

## Not for this skill when

- You need credentials on a developer laptop (different problem)
- Your CI runs fully on-prem with no cloud access (static secrets may be fine there)
- You are looking for general CI security hardening (broader topic)

## Steps

### 1. Create the OIDC trust on the cloud side

Tell your cloud provider to trust tokens from your CI. In AWS this is an IAM role with a trust policy pointing at your CI's OIDC issuer; other clouds have equivalents.

```bash
aws iam create-role --role-name ci-deploy --assume-role-policy-document file://trust-policy.json
```

Expected: the role exists. The trust policy should pin the exact repo (something like `repo:your-org/your-repo` with a ref qualifier), not your whole org, or any repo can mint creds.

### 2. Grant the workflow permission to request the OIDC token

In GitHub Actions, the workflow needs the OIDC permission under `permissions`. Without it, the token request fails.

```yaml
permissions:
  contents: read
```

Expected: the workflow runs. The OIDC permission is the one GitHub names id-token, set to write; add it alongside contents read. If the job fails with a token error, this permission is the first thing to check.

### 3. Assume the role in the workflow instead of using stored keys

Use the official cloud action to exchange the OIDC token for short-lived credentials. No static keys in CI secrets at all.

```yaml
- name: configure cloud credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::[account id]:role/ci-deploy
    aws-region: [region]
```

Expected: subsequent steps can call cloud APIs, and the credentials expire when the job ends. Check the CI secrets list afterward: no cloud keys should remain.

### 4. Scope the role's permissions tightly

The role should allow exactly what the pipeline does and nothing else. Start from what the deploy actually needs.

```bash
aws iam get-role --role-name ci-deploy --query "Role.AssumeRolePolicyDocument"
```

Expected: the trust document shows only your repo. Attach a permissions policy limited to the deploy targets; use Access Analyzer or CloudTrail to trim what the job never calls.

### Variant: dynamic secrets from a vault

If you use HashiCorp Vault or similar, skip OIDC and have CI request dynamic cloud credentials from the vault with a short TTL. Same outcome: nothing static to leak, and the vault audit log shows every issuance.

### 5. Delete the old static credentials

The migration is not done until the long-lived keys are gone. Remove them from CI secrets and revoke them at the provider.

```bash
echo "CI settings: secrets section, delete the old cloud key; provider console: revoke the old key; then run a dry-run deploy"
```

Expected: a dry-run deploy succeeds using only the OIDC path, and the old key returns unauthorized if tested. If anything still references the old secret name, the dry run will tell you.

## Why this happens

Static CI credentials are copied into every run, logged in debug output, and forgotten in repo settings. They also never expire, so a leak from two years ago still works. Short-lived credentials bound to a single workflow run shrink the blast radius to minutes and remove rotation from your todo list entirely.

## Edge cases and pitfalls

- The trust policy must pin the repo and ideally the branch or environment; a loose subject claim lets any repo in the org assume the role.
- Some older CI actions do not support OIDC; upgrade them before migrating.
- Debugging OIDC failures is mostly checking three things: the permissions block, the trust policy subject, and the role ARN.
- If your pipeline needs credentials that outlive one job (like a multi-hour deploy), set the session duration explicitly; the default is one hour.
- Do not forget scheduled workflows and Dependabot runs; they need the same treatment or they break when you delete the static keys.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_4IfbvDfpLlaWsZ-PbB638w
