Securing GitHub Actions¶
GitHub Actions settings exist on organization level (settings.workflows)
and on repository level (workflows). When the
organization setting is more restrictive, the repository setting is ignored, see
Organization settings take precedence. This guide covers
the settings that limit what workflows can do.
Restrict the permissions of the GITHUB_TOKEN¶
Every workflow run receives a GITHUB_TOKEN. The setting default_workflow_permissions defines its default
permissions:
read: read access to the repository contents and packages onlywrite: read and write access for all permission scopes
Workflows that need more permissions declare them explicitly with the
permissions
key, e.g. a release job:
orgs.newOrg('my-project', 'my-org') {
settings+: {
workflows+: {
default_workflow_permissions: "read",
},
},
}
Recommendation
Use read as default and grant additional permissions per workflow or job. A compromised step, e.g. a
dependency of the build, can then not modify the repository. Since February 2023, GitHub uses read for new
organizations, but older organizations and repositories may still use write, see the
GitHub changelog.
A configuration imported from such an organization contains default_workflow_permissions: "write".
To switch an existing organization from write to read:
- Identify the workflows that need write access, e.g. workflows that push commits or tags, create releases,
publish packages or comment on pull requests, and add the required
permissionsto them. - Switch the repositories with such workflows first, e.g. one repository at a time, with
workflows+: { default_workflow_permissions: "read" }. - Switch the organization setting. From then on, a repository setting
writeis ignored. - Watch for failing workflow runs with errors like
Resource not accessible by integration.
Prevent workflows from approving pull requests¶
The setting actions_can_approve_pull_request_reviews controls whether workflows can create and approve pull
requests with the GITHUB_TOKEN.
orgs.newOrg('my-project', 'my-org') {
settings+: {
workflows+: {
actions_can_approve_pull_request_reviews: false,
},
},
}
Organization policy
An approval by a workflow is not a human review: disable this setting if pull requests require reviews. Some
automation, e.g. tools that open release or update pull requests with the GITHUB_TOKEN, needs this setting;
in that case, consider a GitHub App token for this automation instead. GitHub disables the setting by default
for new organizations, see
Preventing GitHub Actions from creating or approving pull requests.
Control which actions can run¶
The setting allowed_actions controls which actions and reusable workflows can run:
all: any actionlocal_only: only actions and reusable workflows defined in the organizationselected: actions created by GitHub (allow_github_owned_actions), by verified creators (allow_verified_creator_actions) and actions that matchallow_action_patterns
orgs.newOrg('my-project', 'my-org') {
settings+: {
workflows+: {
allowed_actions: "selected",
allow_github_owned_actions: true,
allow_verified_creator_actions: false,
allow_action_patterns+: [
"my-org/*",
"example-owner/example-action@*",
],
},
},
}
Organization policy
An allow-list reduces the risk of running untrusted code, but every new action requires a configuration change. It suits organizations with a central review of dependencies. Otherwise, pinning actions to a commit SHA, e.g. with the Pin Workflow blueprint, and keeping them up to date with Dependabot provides a good level of control with less maintenance.
Patterns are described in Allowing select actions and reusable workflows to run. The GitHub policy that requires actions to be pinned to a full-length commit SHA cannot be configured with otterdog.
Approve workflows from forks¶
Pull requests from forks can run workflows. The setting fork_pr_approval_policy defines when a maintainer has to
approve such runs:
| Value | Approval required for |
|---|---|
first_time_contributors_new_to_github |
users who are new to GitHub and never had a contribution merged in the repository |
first_time_contributors |
users who never had a contribution merged in the repository |
all_external_contributors |
all users who are not members of the organization |
orgs.newOrg('my-project', 'my-org') {
settings+: {
workflows+: {
fork_pr_approval_policy: "all_external_contributors",
},
},
}
Organization policy
Requiring an approval for all external contributors gives maintainers a chance to review the changes before any workflow runs, at the cost of an additional step for every external pull request. It is especially relevant for repositories that use self-hosted runners, see Approving workflow runs from forks.
Disable GitHub Actions where it is not needed¶
Repositories that do not use workflows, e.g. mirrors, can disable GitHub Actions entirely:
orgs.newOrg('my-project', 'my-org') {
_repositories+:: [
orgs.newRepo('my-mirror') {
workflows+: {
enabled: false,
},
},
],
}
On organization level, enabled_repositories set to selected only enables GitHub Actions for the repositories
listed in selected_repositories.
Cache size and costs¶
The setting max_cache_size_gb limits the total size of the GitHub Actions caches of a repository. Increasing it
may incur costs: depending on the setup of your otterdog installation, such changes require a review by a
designated team, see Cost policy.
Policies can enforce further restrictions on GitHub Actions, e.g. the usage of macOS large runners.
Summary¶
| Setting | Suggested value | Reason |
|---|---|---|
default_workflow_permissions |
read |
least privilege, grant more per workflow |
actions_can_approve_pull_request_reviews |
false |
approvals should come from people |
fork_pr_approval_policy |
first_time_contributors or stricter |
review unknown code before it runs |
allowed_actions |
depends on your organization policy | trade-off between control and maintenance |