In almost every DevOps discussion today, secret management comes up sooner or later. Tools like HashiCorp Vault, Azure Key Vault, AWS Secrets Manager, and CyberArk are often projected as the default choices. While these tools are powerful and enterprise-grade, they also come with operational overhead, licensing costs, and management complexity especially for small teams, PoCs, labs, and even early-stage production environments.
In my experience working with Terraform, Ansible, and cloud infrastructure, I have realized that not every use case needs a heavyweight secret vault. Sometimes, simplicity and cost-effectiveness matter more without compromising basic security hygiene. This is where GitHub Secrets, when used correctly, fit surprisingly well.
In this article I have explained how GitHub Secrets can be used effectively, how they compare with enterprise vaults, and how to securely consume them inside a GitHub Actions pipeline using a real Terraform-AWS example.
Why Not Always Use HashiCorp Vault or Cloud Key Vaults?
Before diving into GitHub Secrets, let’s be honest about enterprise vaults.
HashiCorp Vault and cloud-native vaults are excellent when:
- You need dynamic secrets with short TTLs
- You require fine-grained RBAC across multiple platforms
- You manage secrets for hundreds of applications and teams
- You need audit trails, auto-rotation, and policy-based access
However, they also introduce:
- Additional infrastructure to manage
- Networking, authentication, and HA complexity
- Licensing or service costs
- Onboarding overhead for developers
For labs, Terraform pipelines, PoCs, sandbox accounts, and controlled production workflows, this can sometimes be over engineering.
Where GitHub Secrets Make Sense
GitHub Secrets work extremely well when:
- You already use GitHub Actions for CI/CD
- Secrets are only required at pipeline runtime
- You want minimal operational overhead
- You need encrypted, repository- or environment-level secrets
- You want zero additional cost
GitHub encrypts secrets at rest and only exposes them to workflows at runtime. They are masked in logs by default, which prevents accidental leaks.
What Kind of Secrets Can Be Safely Managed in GitHub Secrets?
In my pipelines, I commonly store:
- AWS Access Key ID and Secret Access Key (for labs or controlled accounts)
- AWS Region
- IAM Role ARNs (backend role, workload role, cross-account roles)
- Account IDs (network, security, workload accounts)
- Terraform variable values that should not live in Git
For example:
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_PRIMARY_REGION
- BACKEND_ROLE_ARN
- AWS_LAB_ACCESS_ROLE
- NW_ACC_NUMBER, SCS_ACC_NUMBER, WKLD_ACC_NUMBER
Example of Secrets Configured in My GitHub Repository:
Calling GitHub Secrets Inside a GitHub Actions Pipeline
Below is a real Terraform pipeline where GitHub Secrets are consumed securely. This pipeline contains two workflows builds (Build & Test) and apply (Provision & Deploy) the AWS infrastructure using Terraform, while keeping all sensitive values outside the codebase.
name: Primary Region AWS Base Layout Build & Test
on:
workflow_dispatch:
jobs:
build-and-test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: Projects/PrimaryRegion/BaseLayout
steps:
– name: Checkout repository
uses: actions/checkout@v3
# Configure AWS Credentials
– name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4.1.0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_PRIMARY_REGION }}
– name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.12.2
– name: Terraform Init
run: terraform init -backend-config “assume_role={role_arn=\”${{ secrets.BACKEND_ROLE_ARN }}\”}”
– name: Terraform Plan
run: terraform plan -out=baselayout_tfplan \
-var-file=<(cat networks.tfvars security.tfvars storage.tfvars) \
-var=”rolename=${{ secrets.AWS_LAB_ACCESS_ROLE }}” \
-var=”nw_acc_number=${{ secrets.NW_ACC_NUMBER }}” \
-var=”scs_acc_number=${{ secrets.SCS_ACC_NUMBER }}” \
-var=”wkld_acc_number=${{ secrets.WKLD_ACC_NUMBER }}”
– name: Upload Plan Artifact
uses: actions/upload-artifact@v4
with:
name: terraform-plan
path: Projects/PrimaryRegion/BaseLayout/baselayout_tfplan
retention-days: 1
name: Primary Region AWS Base Layout Provision & Deploy
on:
workflow_dispatch:
# Grant minimum required permissions
permissions:
actions: read
contents: read
jobs:
provision-and-deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: Projects/PrimaryRegion/BaseLayout
steps:
– name: Checkout Code
uses: actions/checkout@v3
– name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4.1.0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_PRIMARY_REGION }}
– name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.12.2
– name: Terraform Init
run: terraform init -backend-config “assume_role={role_arn=\”${{ secrets.BACKEND_ROLE_ARN }}\”}”
– name: Install GitHub CLI
run: sudo apt install gh -y
– name: Get Latest Terraform Plan run_id
id: get_run
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
run_id=$(gh run list \
–workflow=”Primary Region AWS Base Layout Build & Test” \
–json databaseId,status \
-q ‘[.[] | select(.status==”completed”)][0].databaseId’)
echo “Latest plan run_id: $run_id”
echo “run_id=$run_id” >> $GITHUB_OUTPUT
– name: Download Plan Artifact
uses: actions/download-artifact@v4
with:
name: terraform-plan
run-id: ${{ steps.get_run.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: Projects/PrimaryRegion/BaseLayout
– name: Terraform Apply
run: terraform apply baselayout_tfplan
What’s Happening Behind the Scenes?
- Secrets are never stored in Git
- They are injected only at runtime
- Terraform receives sensitive values via variables
- Role ARNs are dynamically passed without hardcoding
- Logs automatically mask secret values
This approach keeps the repository clean, secure, and reusable across environments.
Cost Comparison: GitHub Secrets vs Enterprise Vaults
| Feature | GitHub Secrets | HashiCorp Vault / Key Vault |
| Cost | Free | Paid / usage-based |
| Setup | Zero | Moderate to complex |
| Maintenance | None | Ongoing |
| Best for | CI/CD secrets | Enterprise-wide secrets |
| Rotation | Manual | Automated |
| Dynamic secrets | No | Yes |
One thing bear in mind GitHub Secrets are not a replacement, but they are an excellent fit for CI/CD pipelines.
Best Practices When Using GitHub Secrets
From my experience:
- Never echo secrets in scripts
- Use environment-specific secrets
- Prefer IAM roles over static keys when possible
- Rotate secrets periodically
- Combine GitHub Secrets with Terraform remote state security (S3 + DynamoDB)
Wrap up!
Not every problem needs an expensive solution. As DevOps engineers, our responsibility is to balance security, cost, and operational simplicity.
For Terraform pipelines, labs, PoCs, and controlled production workflows, GitHub Secrets provide a clean, cost-effective, and secure way to manage sensitive data without introducing unnecessary complexity.
![]()
- Using GitHub Secrets for Secure and Cost-Effective Secret Management in DevOps Pipelines - January 2, 2026
- What Are Terraform Local and External Variables? Explained with Examples - November 11, 2025
- How to Deploy Docker Containers with NGINX on AWS EC2 Using Ansible and GitHub Actions - April 26, 2025

