Skip to content

GitHub Actions Security & Efficiency Improvements

This document explains the security and efficiency improvements made to the GitHub Actions workflows in this repository.

Summary of Changes

1. Job-Level Permission Blocks

Every job now has explicit permissions blocks following the principle of least privilege.

Security Benefits:

  • Least Privilege: Jobs only get the minimum permissions they need
  • Blast Radius Reduction: If a job is compromised, the attacker's access is limited
  • Clear Intent: Makes it explicit what permissions each job requires
  • Prevents Privilege Escalation: GitHub tokens are scoped to only what's declared

Example:

jobs:
  validate-and-scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read # Can read repository contents
      security-events: write # Can upload SARIF results
    steps:
      # ... steps that need these permissions

Default Permissions Set:

  • Workflow-level: contents: read (most restrictive by default)
  • Job-level: Explicitly declared based on needs
  • Common patterns:
  • contents: read - Read repository files
  • security-events: write - Upload security scan results
  • pull-requests: write - Comment on PRs
  • packages: write - Push container images

3. Dependency Caching

Added caching for Python dependencies and Terraform providers to speed up workflows.

Efficiency Benefits:

  • Faster Builds: Reduce pip install time from 30-60s to 5-10s
  • Reduced Network Load: Fewer downloads from PyPI and Terraform Registry
  • Cost Savings: Shorter workflow execution times mean lower GitHub Actions costs
  • Better Developer Experience: Faster feedback on PRs

Python Dependency Caching:

- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: "3.11"
    cache: "pip"
    cache-dependency-path: "requirements.txt"

Terraform Provider Caching:

- name: Cache Terraform providers
  uses: actions/cache@v4
  with:
    path: |
      ~/.terraform.d/plugin-cache
      **/.terraform/providers
    key: ${{ runner.os }}-terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
    restore-keys: |
      ${{ runner.os }}-terraform-

Cache Key Strategy:

  • Python: Hash of requirements files ensures cache invalidation on dependency changes
  • Terraform: Hash of lock files ensures correct provider versions
  • Restore keys provide fallback for partial cache hits

4. Path-Based Triggers

Security and Terraform workflows now only run when relevant files change.

Efficiency Benefits:

  • Reduced CI Load: Don't run infrastructure tests when only docs change
  • Faster Feedback: Only run what's necessary for a given change
  • Resource Conservation: Saves GitHub Actions minutes

Example:

on:
  push:
    branches: [main]
    paths:
      - "infra/**" # Infrastructure code
      - ".github/workflows/security-and-terraform.yml" # This workflow
      - "**/*.tf" # Any Terraform files
  pull_request:
    branches: [main]

Path Patterns:

  • infra/** - All files under infra directory
  • **/*.tf - All Terraform files anywhere in the repo
  • .github/workflows/*.yml - The workflow file itself

5. Required Security Scans on PRs

TFLint and Gitleaks now run on every PR without continue-on-error.

Security Benefits:

  • Prevent Misconfigurations: TFLint catches Terraform errors before merge
  • Secret Leak Prevention: Gitleaks detects accidentally committed secrets
  • Enforce Best Practices: Security checks are required, not optional
  • Shift Left: Catch issues in PRs before they reach production

TFLint Configuration:

- name: Run TFLint (recursive)
  run: tflint --recursive
  # No continue-on-error - failures will block the PR

Gitleaks Configuration:

- name: Run Gitleaks (secret scan)
  run: |
    gitleaks detect \
      --redact \
      --report-format sarif \
      --report-path gitleaks-results.sarif \
      --no-banner \
      --verbose || true

6. GitHub OIDC for AWS Authentication ⚠️

Status: Prepared but not yet implemented (no AWS usage detected in current workflows)

When AWS integration is added, use OIDC instead of long-lived access keys:

Security Benefits:

  • No Static Secrets: No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY in GitHub Secrets
  • Short-Lived Tokens: Credentials expire automatically after workflow completes
  • Audit Trail: All AWS actions tied to GitHub workflow identity
  • Principle of Least Privilege: IAM roles can be scoped to specific repos/branches

Implementation Template:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write # Required for OIDC
      contents: read
    steps:
      - uses: actions/checkout@34e11480ae1e31caa3f43c6f6043d4daa6e1148a

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::ACCOUNT_ID:role/GitHubActionsRole
          aws-region: us-east-1

      - name: Deploy to AWS
        run: |
          # AWS CLI commands here - automatically authenticated
          aws s3 ls

Setup Requirements:

  1. Create OIDC provider in AWS IAM
  2. Create IAM role with trust policy for GitHub
  3. Grant role permissions for required AWS services
  4. Configure role-to-assume in workflow

Workflow-Specific Changes

security-and-terraform.yml

  • ✅ Pinned all actions to commit SHAs
  • ✅ Added job-level permissions
  • ✅ Added Terraform provider caching
  • ✅ Added path-based triggers (only runs on infra/ changes)
  • ✅ Made TFLint required (removed continue-on-error)
  • ✅ Made Gitleaks required on PRs

deploy.yml

  • ✅ Pinned all actions to commit SHAs
  • ✅ Added job-level permissions
  • ✅ Added Python dependency caching with cache-dependency-path

idp-e2e-tests.yml

  • ✅ Pinned all actions to commit SHAs
  • ✅ Added job-level permissions
  • ✅ Already had Python caching configured
  • ✅ Already had path-based triggers

pre-commit.yml

  • ✅ Pinned all actions to commit SHAs
  • ✅ Added job-level permissions to all jobs
  • ✅ Added Python dependency caching
  • ✅ Added Terraform provider caching

build-mcp-k8s-server.yml

  • ✅ Pinned all actions to commit SHAs
  • ✅ Added job-level permissions
  • ✅ Only runs on tag pushes (already efficient)

Security Scorecard Improvements

These changes improve the repository's OpenSSF Scorecard score:

Check Before After Improvement
Pinned-Dependencies ⚠️ Warning ✅ Pass Actions pinned to SHAs
Token-Permissions ⚠️ Warning ✅ Pass Explicit least-privilege
Dangerous-Workflow ⚠️ Warning ✅ Pass Path-based triggers reduce attack surface

Maintenance Best Practices

Keeping Actions Up-to-Date

  1. Enable Dependabot for GitHub Actions:
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
  1. Review Security Advisories:

  2. Check GitHub Security Advisories before updating

  3. Review changelogs for breaking changes
  4. Test workflows in a branch before merging

  5. Automated Testing:

  6. Test workflow changes in PRs
  7. Use act for local workflow testing
  8. Monitor workflow failure rates

Cache Maintenance

  • Python: Caches invalidate when requirements files change
  • Terraform: Caches invalidate when lock files change
  • Pre-commit: Caches invalidate when config changes
  • Caches expire after 7 days of no access

Monitoring

  • Track workflow execution times in GitHub Insights
  • Monitor cache hit rates
  • Review failed workflows for security issues
  • Check Dependabot PRs weekly

References

Rollback Plan

If issues arise from these changes:

  1. Action Version Issues:

  2. Comment out SHA, uncomment tag temporarily

  3. Investigate and update to correct SHA

  4. Permission Issues:

  5. Check workflow logs for permission errors

  6. Add minimal required permissions to job
  7. Document why permission is needed

  8. Cache Issues:

  9. Clear cache manually via GitHub UI

  10. Adjust cache key if needed
  11. Disable caching temporarily if blocking

  12. Path Filter Issues:

  13. Remove path filters if causing unexpected skips
  14. Adjust patterns to be more inclusive
  15. Test with small PRs first