$ run as a normal user# run as root (or with sudo)
Store secrets
Secrets live at three levels: organisation, repository, environment. Workflows read them with secrets.NAME; they are masked in logs.
gh secret set SMTP_PASSWORD
gh secret set DB_PASSWORD --env production
gh secret list
gh variable set AZURE_REGION --body westeurope- run: ./notify.sh
env:
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}Watch out
Never echo a secret or write it into a file that becomes an artifact. Masking only works for the exact string — a base64 version of it is not masked.
Create environments
An environment is a deployment target with its own rules. A job that uses it must pass the rules first.
Settings → Environments → New environment production:
- Required reviewers: up to 6 people or teams must approve.
- Wait timer: wait N minutes before the job starts.
- Deployment branches and tags: only
main(or release tags) may deploy. - Environment secrets and variables: only jobs of this environment can read them.
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- run: ./deploy.sh staging
deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://shop.example.com
steps:
- run: ./deploy.sh productionRemember
The job waits at environment: production until a reviewer clicks Approve — the approval and the URL are shown in the run.
Limit the GITHUB_TOKEN
Every run gets a temporary GITHUB_TOKEN. Give it only the rights the workflow needs, with permissions:.
permissions:
contents: read
jobs:
release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- run: gh release create "${{ github.ref_name }}" --generate-notes
env:
GH_TOKEN: ${{ github.token }}| Setting | Effect |
|---|---|
permissions: {} | No rights at all |
contents: read | Read the code (a good default) |
id-token: write | Ask for an OIDC token (cloud login without secrets) |
packages: write | Push images to GHCR |
pull-requests: write | Comment on pull requests |
At work
Set the repository default to read-only (Settings → Actions → General → Workflow permissions) and raise rights per job.
Prefer short-lived credentials
A stored cloud password can leak and stays valid. OIDC gives the job a token for minutes only — no secret to store or rotate. See Deploy to Azure with OIDC.