Implementing least privilege for secrets in GitHub Actions
GitHub Actions provide a powerful, extensible way to automate software development workflows. When access to outside resources is required, GitHub provides the ability to store encrypted secrets used by GitHub…
GitHub Actions provide a powerful, extensible way to automate software development workflows. When access to outside resources is required, GitHub provides the ability to store encrypted secrets used by GitHub Actions to authenticate against these resources. This makes managing access more simple and secure.
Good secret management practices include following principles of least privilege by narrowly scoping secrets to provide access to only what is required, limiting the manner in which the secret can be invoked, and rotating secrets when necessary. GitHub Actions provide several features to help your organization effectively implement a secret management strategy based on least privilege.
Secret availability
Secrets can be stored within GitHub at three different levels: the organization, a single repository, or a repository environment. The level at which the secret should be stored depends on its scope and intended use.
For example, a Slack bot token with permissions to only post to organization-owned workspaces is used to broadcast status updates as part of CI/CD workflows. This token has no special access to any resources, and many different repositories’ workflows will post similar updates to Slack. This secret might be stored at the organization level. When creating an organization secret, you can choose to make it available to all repositories in the organization, only private and internal repositories, or a selected set of repositories.
A containerized application stores its custom images in AWS Elastic Container Registry (ECR). To ensure the automation used to deploy the application cannot be used to pull other containers, a unique token is created for the repository and stored as a repository-level secret.
That same containerized application is deployed as an Azure Web App in different dev, test, and prod environments. Each environment requires its own, unique publishing profile. Using environments, these can be stored as environment-level secrets within a repository.
Limiting use of secrets
Least privilege secret management is concerned not only with what a token can access, but also how can it be used, and by whom. Combining properly scoped secrets with environment protections, CODEOWNERS, and branch protection rules helps ensure secrets are only used for the intended purpose, by those authorized to do so.
Let’s consider the example of a company, MonaCorp, that wants to ensure a secret can only be used to deploy authorized changes of a single Azure Web Application, OctoMittens, to its production environment. Separate publishing profiles exist for dev, test, and production.
First, each of these environments are defined in the repository.
Each environment has its own AZURE_WEBAPP_PUBLISH_PROFILE
secret, storing the respective value.
Without any additional configuration, someone with write access could create a branch unauthorized-production-deployment
, modify a workflow file on that branch, and trigger the workflow—causing the secret to be used to deploy to production. This type of unauthorized credential use can be prevented by:
- Creating an environment protection rule limiting the branch(es) that can deploy to the
production
environment. In this case, a rule is created to allow only themain
branch to deploy toproduction
.
- Configuring CODEOWNERS to establish ownership of the
.github/workflows
directory. Here the@monacorp/automation-review
team is assigned ownership.### Actions workflows .github/workflows/ @monacorp/automation-review
- Creating a branch protection rule that requires review from CODEOWNERS for any merge into
main
and prevents force pushes.
With all these in place, the only available way to use the production AZURE_WEBAPP_PUBLISH_PROFILE
secret is in workflows on the main
branch targeting the production
environment. Any attempt to use this secret elsewhere requires merging a workflow change targeting the production
environment to the main
branch, which requires approval by the automatically assigned @monacorp/automation-review
team.
Integrating with secret stores
Many companies use a centrally-managed secret store, such as HashiCorp Vault or Azure Key Vault, to store secrets and manage access. GitHub Actions can integrate with these stores while following all of the same principles discussed above.
MonaCorp chooses to store all secrets in HashiCorp Vault. Storing those same secrets in multiple places would violate the DRY principle, create additional management overhead, and add unnecessary risk. MonaCorp needs to provide the same limited scope and access to secrets using HashiCorp Vault as they can completely within GitHub.
To do this, MonaCorp first creates unique AppRoles in HashiCorp Vault for each of OctoMittens’ environments: dev, test, and prod. Each AppRole is granted access only to the secrets necessary to deploy to its respective environment.
Second, MonaCorp stores the roleId
and secretId
for each HashiCorp Vault AppRole in GitHub as secrets in the corresponding environment.
Third, MonaCorp configures their jobs in their GitHub Actions workflows to target a specific environment. Each job uses the Vault Secrets action to authenticate against HashiCorp Vault as the AppRole for that environment, retrieve the desired secrets, and map them to environment variables. The action uses GitHub’s built-in masking to prevent the values from showing up in any output to logs or the console.
Similar capabilities are available for those using Azure Key Vault via the Azure Key Vault – Get Secrets action.
Rotating secrets
MonaCorp has a defined policy for secret rotation. Secrets maintained in Vault are rotated in Vault. These changes are automatically picked up by Actions workflows as the Vault Secrets action retrieves new credentials with each workflow run. When a secret stored in GitHub needs to be changed, such as the secretId
, MonaCorp can automate updating secrets in GitHub via the REST API.
Keeping things secret
With appropriately scoped secrets stored in the proper location(s), environment protection rules, CODEOWNERS, and optional integration with centrally-managed secret stores, GitHub provides organizations all the tools they need to securely manage authentication in their Actions workflows.
Tags:
Written by
Related posts
Execute commands by sending JSON? Learn how unsafe deserialization vulnerabilities work in Ruby projects
Can an attacker execute arbitrary commands on a remote server just by sending JSON? Yes, if the running code contains unsafe deserialization vulnerabilities. But how is that possible? In this blog post, we’ll describe how unsafe deserialization vulnerabilities work and how you can detect them in Ruby projects.
10 years of the GitHub Security Bug Bounty Program
Let’s take a look at 10 key moments from the first decade of the GitHub Security Bug Bounty program.
Where does your software (really) come from?
GitHub is working with the OSS community to bring new supply chain security capabilities to the platform.