Environment variables store configuration data as key-value pairs.
Available to all steps:
env:
DEPLOY_ENV: production
LOG_LEVEL: debug
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo $DEPLOY_ENVAvailable to all steps in a job:
jobs:
deploy:
env:
NODE_ENV: production
runs-on: ubuntu-latest
steps:
- run: echo $NODE_ENVAvailable only to that step:
steps:
- run: npm build
env:
NODE_ENV: production- run: echo "Environment: ${{ env.NODE_ENV }}"Secrets are encrypted environment variables. Use them for sensitive data like API keys, tokens, and credentials.
- 🔐 Encrypted at rest
- 🙈 Not displayed in logs
- 🛡️ Only available in actions/workflows
- 🔑 Can't be accessed by forks (by default)
- Go to your repository
- Settings → Secrets and variables → Actions
- Click "New repository secret"
- Add name and value
- Click "Add secret"
gh secret set DEPLOYMENT_TOKEN --body "your-token-here"jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy with token
run: curl -H "Authorization: Bearer ${{ secrets.DEPLOYMENT_TOKEN }}" https://api.example.com/deploysteps:
- run: echo "Using secrets..."
- name: GitHub Token
run: echo ${{ secrets.GITHUB_TOKEN }}
- name: Custom Secret
run: echo ${{ secrets.MY_API_KEY }}
- name: Azure Credentials
run: echo ${{ secrets.AZURE_CREDENTIALS }}GitHub automatically provides a GITHUB_TOKEN secret for each workflow run.
jobs:
my-job:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- run: gh pr comment -B "Review completed"- uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Create issue
run: |
gh issue create \
--title "Bug report" \
--body "Found a bug" \
--repo owner/repo✅ Use unique secrets for different purposes
✅ Rotate secrets regularly
✅ Use least privilege (only needed permissions)
✅ Never log secrets to output
✅ Use environment-specific secrets
✅ Document where secrets are used
GitHub automatically masks secrets in logs, but you can manually mask:
steps:
- run: |
echo "::add-mask::password123"
echo "My password is password123"
# Output: My password is ***# ❌ Bad - might leak secret
- run: |
echo "Token: ${{ secrets.API_TOKEN }}"
npm deploy
# ✅ Good - secret is hidden
- run: |
npm deploy --token "${{ secrets.API_TOKEN }}"| Use Case | Variable | Secret |
|---|---|---|
| Public URLs | ✅ | ❌ |
| API Keys | ❌ | ✅ |
| Configuration | ✅ | ❌ |
| Tokens | ❌ | ✅ |
| Database URLs | ❌ | ✅ |
| Version Numbers | ✅ | ❌ |
For enterprise, set secrets at organization level:
- Go to Organization Settings
- Secrets and variables → Actions
- Add organization secrets
- Grant repository access
Usage is the same:
run: echo ${{ secrets.ORG_SECRET }}Different environments need different secrets:
jobs:
deploy-staging:
environment: staging
runs-on: ubuntu-latest
steps:
- run: echo ${{ secrets.STAGING_TOKEN }}
deploy-prod:
environment: production
needs: deploy-staging
runs-on: ubuntu-latest
steps:
- run: echo ${{ secrets.PROD_TOKEN }}name: Deploy Application
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Login to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy to App Service
uses: azure/webapps-deploy@v2
with:
app-name: my-app
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}
- name: Notify Slack
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \
-H 'Content-Type: application/json' \
-d '{"text":"Deployment completed"}'For Azure deployments, you'll typically need:
secrets:
AZURE_CREDENTIALS: |
{
"clientId": "...",
"clientSecret": "...",
"subscriptionId": "...",
"tenantId": "..."
}
AZURE_APP_SERVICE_NAME: my-app
AZURE_RESOURCE_GROUP: my-rg- Never hardcode secrets in workflows
- Use GitHub Secrets for sensitive data
- Rotate secrets regularly
- Use environment-specific secrets
- Review secret access permissions
- Audit secret usage in logs
- Use branch protection with secret rotation
- Build and Test - Practical CI examples
- Deploy to Azure - Secure deployments
- GitHub Actions Documentation
Your workflows are now secure! Let's move to building and testing applications.