Secure the pipeline

Protect secrets and cloud access

Scope secrets to environments and prefer short-lived federated credentials over long-lived cloud keys where supported.

Repository secrets are convenient and dangerous. One AWS_ACCESS_KEY_ID at repo scope is available to every workflow job unless you narrow it.

Secret masking hides values in logs. It does not stop a malicious step from sending the secret outbound. If a process can read a secret, assume it can leak it.

Fork pull requests must not receive production secrets even when the workflow file looks innocent. Environment scoping plus branch filters is how you enforce that separation.

Repository-level secrets are fine for low-risk tokens used on every branch, like a read-only npm registry token. Anything that can change production belongs behind an environment gate.

Scope secrets to environments

Production credentials belong on the production environment, not on the whole repository:

jobs:
  deploy:
    environment: production
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-deploy
          aws-region: eu-west-1

Only jobs that target environment: production receive those secrets. Test jobs on pull requests never see them.

Add required reviewers on the environment so deploy waits for a human.

Prefer short-lived federated credentials

Long-lived cloud keys in GitHub rot slowly and grant wide access. OIDC lets GitHub exchange a job token for a short-lived cloud role:

permissions:
  id-token: write
  contents: read

steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789012:role/github-deploy
      aws-region: eu-west-1

Cloudflare, Azure, and GCP support similar patterns. The credential dies when the job ends.

Inventory and rotate

List every secret: name, which job uses it, who can approve access, last rotation date.

Replace one long-lived deploy key with OIDC or a narrower token. Run a deploy. Revoke the old key.

Rotation without narrowing scope only resets the same blast radius. Pair every rotation with fewer secrets and shorter lifetime.

Try this on your own project: move one production secret from repository settings to an environment and confirm PR workflows still pass without it.

Lesson completed