π GitHub Actions Permissions¶
GitHub Actions uses a permission-based security model.
Workflows and individual jobs can be granted specific access levels to follow the principle of least privilege.
This guide focuses on the three most important permissions when deploying documentation (especially MkDocs + GitHub Pages) and modern cloud deployments.
Overview of Key Permissions¶
| Permission | Scope | Typical Use Case | Risk Level | Recommended When |
|---|---|---|---|---|
contents: write | Repository code & branches | Push to gh-pages, commit generated files | π‘ Medium | Writing back to repo |
pages: write | GitHub Pages publishing | Official actions/deploy-pages | π’ Low | Using GitHub-native Pages deploy |
id-token: write | OIDC token issuance | Secret-less auth to AWS/GCP/Azure | π₯ High | Deploying to external clouds |
Detailed Permission Reference¶
1. contents: write¶
permissions:
contents: write
What it allows¶
| Action | Allowed |
|---|---|
| Push commits / create branches | β |
| Modify repository files | β |
Publish to gh-pages branch | β |
| Read repository contents | β |
Common use cases¶
- Deploying MkDocs site via
peaceiris/actions-gh-pages - Auto-updating README, release notes, or generated docs
- Any CI that commits artifacts back to the repo
Risk¶
Compromised workflow could rewrite repository code β use only when necessary
2. pages: write¶
permissions:
pages: write
What it allows¶
| Action | Allowed |
|---|---|
| Deploy to GitHub Pages | β |
| Trigger Pages rebuild | β |
| Configure Pages settings | β |
| Modify repository source code | β |
When required¶
Only with GitHubβs official deployment action:
- uses: actions/deploy-pages@v4
Not needed when using peaceiris/actions-gh-pages (that one uses contents: write instead).
Risk¶
Very low β only affects the published static site.
3. id-token: write¶
permissions:
id-token: write
What it allows¶
| Action | Allowed |
|---|---|
| Mint short-lived OIDC tokens | β |
| Assume roles in AWS/GCP/Azure | β |
| Push to repository | β |
| Deploy to GitHub Pages | β |
Supported cloud providers (OIDC)¶
| Provider | Supported |
|---|---|
| AWS IAM Roles Anywhere / AssumeRole | β |
| Google Cloud Workload Identity Federation | β |
| Azure Federated Credentials | β |
Use cases¶
- Deploy static sites to S3 + CloudFront
- Firebase Hosting, Cloudflare R2, GCP Cloud Storage, Azure Storage
Risk¶
Gives real cloud credentials β treat as high-risk. Only grant when actually deploying to external clouds.
Choosing the Right Permissions for Your Deployment¶
| Deployment Method | Required Permissions | Notes |
|---|---|---|
mkdocs gh-deploy (built-in) | None | Uses your personal GH token |
actions/deploy-pages@v4 | pages: write | Official GitHub method |
peaceiris/actions-gh-pages@v3/v4 | contents: write | Most popular community action |
| Deploy to AWS/GCP/Azure via OIDC | id-token: write (+ sometimes contents) | Secret-less auth |
Where to Declare Permissions (Scope)¶
GitHub supports two scopes:
1. Workflow-level (root)¶
permissions:
contents: write
pages: write
id-token: write
β Applies to all jobs in the workflow (unless overridden)
β Convenient for simple, single-purpose workflows
2. Job-level (recommended for security)¶
jobs:
build:
permissions: {}
# or explicitly read-only
# permissions: read-all
deploy:
permissions:
pages: write
# or contents: write / id-token: write as needed
β Only the deploy job gets write access
β Follows least privilege principle
Decision Table¶
| Scenario | Recommended Placement |
|---|---|
| Single-job workflow | Root or job-level (both OK) |
| Multi-stage pipeline (build β test β deploy) | Job-level only on deploy |
| Security-focused / enterprise | Always job-level, minimal scope |
Secure Enterprise Pattern (Best Practice)¶
name: Deploy Docs
on: [push, workflow_dispatch]
permissions: {} # deny all by default
jobs:
build:
runs-on: ubuntu-latest
steps: [...]
test:
needs: build
runs-on: ubuntu-latest
steps: [...]
deploy:
needs: test
permissions:
contents: write # or pages: write / id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/deploy-pages@v4 # if using official action
# or peaceiris/actions-gh-pages@v4
One-Glance Summary Table¶
| Permission | Main Purpose | Typical Deployment Scenario | Frequency in Real Projects |
|---|---|---|---|
contents: write | Push to repo / gh-pages branch | MkDocs + peaceiris action | π₯ Very common |
pages: write | Official GitHub Pages deploy | actions/deploy-pages | π‘ Common |
id-token: write | OIDC auth to cloud providers | AWS, GCP, Azure hosting | π Professional / Enterprise |
Key Takeaways (Senior Engineer Mindset)¶
- Never grant more permissions than needed
- Prefer job-level permissions in multi-job workflows
- Root-level permissions = convenience, job-level = security
- Use
pages: writeonly with official deploy action - Use
id-token: writeonly for real cloud OIDC deployments