Secrets Management & Infrastructure Security

GitHub Secrets & OIDC Authentication

4 min read

GitHub provides built-in secrets management for CI/CD. Combined with OIDC (OpenID Connect), you can eliminate long-lived credentials entirely.

GitHub Secrets Overview

Secret Type Scope Use Case
Repository secrets Single repo API keys, deploy tokens
Environment secrets Specific environment Production vs staging
Organization secrets Multiple repos Shared credentials

Managing Repository Secrets

Via GitHub UI

  1. Go to SettingsSecrets and variablesActions
  2. Click New repository secret
  3. Enter name (e.g., AWS_ACCESS_KEY_ID) and value

Via GitHub CLI

# Set a secret
gh secret set AWS_ACCESS_KEY_ID

# Set from file
gh secret set AWS_SECRET_ACCESS_KEY < secret.txt

# List secrets
gh secret list

# Delete secret
gh secret delete AWS_ACCESS_KEY_ID

Using Secrets in Workflows

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Deploy to S3
        run: aws s3 sync ./dist s3://my-bucket

Environment-Specific Secrets

# Different secrets per environment
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production  # Uses production secrets

    steps:
      - name: Deploy
        run: ./deploy.sh
        env:
          API_KEY: ${{ secrets.API_KEY }}  # Production API key

Configure environments in SettingsEnvironments:

  • Add required reviewers
  • Set deployment branch restrictions
  • Add environment-specific secrets

OIDC: The Future of CI/CD Authentication

OIDC eliminates static credentials by using short-lived tokens:

┌──────────────────┐       ┌─────────────────┐
│  GitHub Actions  │       │ Cloud Provider  │
│    Workflow      │       │ (AWS, GCP, etc) │
└────────┬─────────┘       └────────┬────────┘
         │                          │
         │  1. Request OIDC token   │
         │ ─────────────────────▶   │
         │                          │
         │  2. Verify with GitHub   │
         │ ◀─────────────────────   │
         │                          │
         │  3. Issue short-lived    │
         │     credentials          │
         │ ◀─────────────────────   │
         │                          │
         │  4. Use credentials      │
         │ ─────────────────────▶   │
         │                          │

OIDC with AWS

# No static credentials needed!
jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write    # Required for OIDC
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: us-east-1
          # No aws-access-key-id or aws-secret-access-key!

      - name: Deploy
        run: aws s3 sync ./dist s3://my-bucket

AWS IAM Role Setup

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:*"
        }
      }
    }
  ]
}

OIDC with Google Cloud

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/github/providers/github'
          service_account: 'github-actions@my-project.iam.gserviceaccount.com'

      - name: Deploy to Cloud Run
        run: gcloud run deploy my-service --image gcr.io/my-project/my-app

Secrets Security Best Practices

1. Never Log Secrets

# GitHub automatically masks secrets, but be careful
- name: Debug
  run: |
    # BAD: Could leak in error messages
    curl -H "Authorization: Bearer ${{ secrets.TOKEN }}" https://api.example.com

    # BETTER: Use environment variables
    curl -H "Authorization: Bearer $TOKEN" https://api.example.com
  env:
    TOKEN: ${{ secrets.TOKEN }}

2. Limit Secret Scope

# Only expose secrets to steps that need them
jobs:
  build:
    steps:
      - name: Build
        run: npm run build
        # No secrets here - just building

  deploy:
    needs: build
    environment: production
    steps:
      - name: Deploy
        run: ./deploy.sh
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}

3. Use Environment Protection

# Require approval for production deployments
jobs:
  deploy:
    environment:
      name: production
      url: https://myapp.com
    # Reviewers must approve before job runs

4. Rotate Secrets Regularly

# Automate secret rotation
gh secret set API_KEY --body "$(generate-new-key)"

# Or use OIDC to avoid rotation entirely

Comparison: GitHub Secrets vs Vault

Aspect GitHub Secrets HashiCorp Vault
Complexity Simple Complex
Dynamic secrets No Yes
Audit logging Basic Comprehensive
Multi-cloud GitHub only Any platform
Best for GitHub-native workflows Enterprise, multi-cloud

Next, we'll cover Infrastructure as Code security scanning. :::

Quiz

Module 5: Secrets Management & Infrastructure Security

Take Quiz