Episode 5 – Secrets, Variables & Environments (Security Done Right)
So far in this series, we’ve learned:
- how GitHub Actions workflows are structured
- when workflows run
- where jobs execute
- how actions are reused
Now it’s time to talk about security.
This episode focuses on something every real-world pipeline needs but beginners often misuse:
Secrets, variables, and environments
Understanding this properly is what separates toy pipelines from production-ready CI/CD.
Why This Topic Matters
Your GitHub Actions workflow can:
- deploy to production
- publish packages
- access cloud infrastructure
- modify repositories
That means:
If secrets are handled incorrectly, the entire system is at risk.
1️⃣ Secrets vs Variables (Core Difference)
🔹 Variables
Variables are non-sensitive configuration values.
Examples:
- Node version
- App name
- Feature flags
- API base URLs
They are:
- stored in plain text
- safe to log
- meant for configuration
Example usage:
env:
NODE_VERSION: ${{ vars.NODE_VERSION }}
🔹 Secrets
Secrets are sensitive credentials.
Examples:
- API keys
- Tokens
- Passwords
- Cloud credentials
They are:
- encrypted at rest
- masked in logs
- injected only at runtime
- never readable after creation
Example usage:
env:
API_KEY: ${{ secrets.API_KEY }}
👉 Rule of thumb
If leaking it is bad → it must be a secret.
2️⃣ Where Can Secrets Live?
GitHub allows secrets at three levels.
🟨 Organization Secrets
- Shared across multiple repositories
- Lowest priority
- Useful for common credentials
🟦 Repository Secrets
- Scoped to one repository
- Most commonly used
- Good for CI pipelines
🟥 Environment Secrets (Most Important)
- Scoped to an environment (
staging,production) - Can have protection rules
- Ideal for deployments
👉 Priority order:
Environment > Repository > Organization
3️⃣ How Secrets Are Accessed in Workflows
Secrets are always accessed like this:
${{ secrets.SECRET_NAME }}
Example:
- run: curl -H "Authorization: Bearer ${{ secrets.API_KEY }}" api.example.com
GitHub automatically masks secret values in logs:
********
4️⃣ What Are Environments?
An environment represents a deployment stage.
Common examples:
developmentstagingproduction
Usage in a job:
jobs:
deploy:
environment: production
Once you do this:
- environment secrets become available
- protection rules are enforced
- deployments are tracked
5️⃣ Environment Protection Rules (Production Safety)
Environments can enforce:
✅ Required reviewers
- Manual approval before job runs
✅ Deployment branch rules
- Only allow deploys from
main
✅ Wait timers
- Delay deployments if needed
This is how real teams protect production.
6️⃣ A Real-World Deployment Example
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- run: echo "Deploying to production"
env:
API_KEY: ${{ secrets.PROD_API_KEY }}
What happens here:
- Workflow starts
- GitHub pauses for approval
- Secrets are unlocked only after approval
- Deployment runs
7️⃣ Common Mistakes to Avoid 🚨
❌ Committing secrets in code
❌ Printing secrets in logs
❌ Using repo secrets for production
❌ Forgetting to specify environment
❌ Exposing secrets to PR workflows
These mistakes are very common and very dangerous.
Final Mental Model (Lock This In)
vars → configuration
secrets → credentials
environment → protection + scope
If this model is clear, your pipelines will already be safer than most.
What’s Next?
👉 Episode 6:
Caching & Artifacts – Faster Pipelines and File Sharing
We’ll focus on:
- speeding up CI
- sharing build outputs
- avoiding flaky pipelines
Follow the series to move closer to production-ready GitHub Actions 🚀
Thanks for reading!
Stay secure 👋
Top comments (0)