Resources

Enhance your GitHub Actions Security with these Secrets Management Best Practices

Explore how to use GitHub Actions secrets securely by restricting organizational secrets, using secrets exclusively for sensitive data, and implementing least privileged access.

Ashish Kurmi
January 10, 2024

Table of Contents

Subscribe

Share This Post

Share This Post

Table of
Contents

Introduction

This is a follow-up post for our first blog post titled “GitHub Actions Security Best Practices (With Checklist)” in the series. In this post, we will deep dive into GitHub Actions secret management best practices.

GitHub Action workflows need secrets to perform sensitive operations such as managing cloud resources, pushing built container images to registries, and so on. As these are privileged credentials with elevated access, it's paramount for enterprises to make sure that GitHub Actions secrets are secured.  

We will discuss the use of OpenID Connect (OIDC) and the least privileged access tokens in separate blog posts. This blog covers all the other best security practices for GitHub Actions secrets.

What are GitHub Actions Secrets?

GitHub Actions secrets are variables that enable you to store sensitive information in your repositories. These can be admin access keys, credentials, or organization secrets- all sensitive data that needs to be fully secured. These secrets could be created at the organization, repository, or repository environment levels. Although securing GitHub Actions secrets can be quite a tricky job, we have provided practical easy-to-follow tips below to implement GitHub Actions secrets best practices.

Rotate Secrets Regularly

It is important to rotate your GitHub Actions secrets and invalidate old ones to keep them secure in workflows.  

To view your Actions secrets, you can visit the repository settings page. Although you will not be able to explore all your GitHub secrets and their metadata in one place, there are ways you can view this inventory. Here are some of them:

  1. Explore secrets on the repository settings page for each of the repositories.
  2. Utilize GitHub APIs to create an application that catalogs all secrets and their metadata throughout your GitHub organization.

Using Actions secrets only for storing secrets and not non-sensitive information can make it easier for organizations to use the methods described above to discover stale secrets and rotate them without worrying about false positives.

Did you know that StepSecurity’s GitHub Actions security platform can help you discover stale GitHub Actions secrets across your GitHub organization? Get started for free here.

Screenshot showing a dashboard displaying the number of days since secrets have been rotated
Screenshot showing a dashboard displaying the number of days since secrets have been rotated

Restrict Organizational Secrets to Specific Repositories

Whenever possible, you should avoid using Organizational secrets as these secrets could potentially be available to all repositories in your organization. If you have a common secret that you would like to use across multiple repositories, you should create an organizational secret and scope it to only specific repositories that need it. By default, organizational secrets are available to all internal and private repositories. In a large enterprise environment, this could mean hundreds of repositories can access these shared organizational secrets. You should instead scope it to be used by specific repositories in your organization.

Screenshot showing how to set your repositories to be private and internal
Screenshot showing how to set your repositories to be private and internal

Use Actions Secrets Only for Storing Secrets

This is a practical tip to enable organizations to reduce the operational burden of managing GitHub Actions secrets. GitHub Actions secrets must only be used for storing secrets. For non-sensitive data, Actions variables must be used. Like GitHub Actions secrets, Actions variables can be created at the organization, repository, or repository environment levels.

We have seen many enterprises use GitHub secrets for storing configuration values such as environment type (e.g., dev, prod, etc.), resource names (e.g., AWS account number), etc. Such non-sensitive information must be migrated over to GitHub variables.  This will allow enterprises to invest their resources to truly secure Actions secrets and not worry about non-sensitive data in their Actions environments.

Screenshot showing the creation of a new Action variable
Screenshot showing the creation of a new Action variable

Use Least Privileged Secrets

Just like any other secrets, you must use the least privileged secrets with your GitHub Actions. A practical matter to consider for GitHub Actions is whether to reuse the same secret across multiple workflows (e.g., AWS identity) or create a unique GitHub secret per environment.  

From a security perspective, having a unique secret per workflow job is ideal. However, this will be an operational nightmare for large organizations that may have hundreds/thousands of GitHub Actions workflow jobs in their environment. A practical approach could be to segment Action workflows by environments (e.g., dev vs prod) or services (e.g., payment service vs service health monitoring service) and do not re-use Actions secrets across workflows belonging to multiple segments.

Leverage Environment Secrets and Mandatory Reviews for Production Secrets

Your GitHub Actions secrets can be easily exfiltrated and leaked by bad actors. This may include sensitive data like admin cloud credentials, organization secrets, or public keys. All the workflows and branches in the repository have access to your GitHub Actions secrets and can be exfiltrated by updating a workflow or creating a new one and referencing the secret.  

One way you can secure your GitHub Actions secrets is by leveraging environment secrets. These secrets stored at an environment level enable you to implement guardrails by enforcing mandatory reviews. This means they can only be accessed by an authorized reviewer who can approve the workflow run. No job will have access to these secrets without the approval of the reviewer.  

Environment secrets also allow you to implement other quality gates including static code analyzers that can flag issues and ensure the absence of vulnerable dependencies in the workflow.

Screenshot showing usage of environment secrets to secure a production secret
Screenshot showing usage of environment secrets to secure a production secret

Avoid Printing Secrets in Actions Run Logs

When GitHub Actions detects a secret in workflow run logs, it hides it by default. This means that the value of the key or secret will be hidden in the log automatically. Take, for instance, a secret named SECRET_API_KEY used in GitHub Actions. When this workflow is executed:

name: Secret Redaction In Logs

on:
  workflow_dispatch:

jobs:
  print-secret:
    runs-on: ubuntu-latest
    steps:
    - name: Print Secret Value
      run: |
        echo "Secret API Key: ${{ secrets.SECRET_API_KEY }}"


The log will show that the API key is actual value is obscured:

Screenshot showing concealed API key
Screenshot showing concealed API key

This feature is limited to secrets that GitHub Actions recognizes, meaning only those secrets explicitly linked to the workflow are masked.

Secrets created during the runtime (e.g., an authorization token generated after completing an OAuth handshake) won't be masked if they appear in build logs. It's crucial to avoid logging secrets altogether. This is especially important for public open-source GitHub repositories, as logs from GitHub Actions in such repositories are accessible to the public. As of now, there's no option to set these logs to private.  

Don't Use Structured Data as Secrets

This is an extension of the previous best practice. If you use custom structured data like a blob of JSON, XML, or YAML to encapsulate a secret value, it will not get redacted. Furthermore, using a custom data structure for storing secrets also leads to engineering issues such as standard dev tools not recognizing the secret correctly as it expects it differently. As GitHub Actions doesn’t provide an easy way to extract GitHub Actions secrets for debugging and troubleshooting, debugging such issues can become complex.

Also Read: Best Practices in GitHub Actions Security: A Case Study with Google’s Use of StepSecurity

Scan GitHub Actions Logs for Secrets

Scanning your GitHub Actions logs for secrets can help you detect accidental leakages of secrets from build tools and third-party components. GitHub does not provide a built-in way to scan GitHub Actions logs, you need to build such a system yourself. One way to implement this system is to create a GitHub App that subscribes to Actions completion events. Once an Action job has finished, you can download logs using the GitHub App and scan them using a secret scanner.

Conclusion

Managing GitHub Actions secrets can be quite a task but with these simple best practices, you should be able to securely manage them and enhance your GitHub Actions security. Stay tuned for our next GitHub Actions security blog post to learn how you can stay ahead of the evolving threats and secure your workflows from serious leaks and attacks.  

Introduction

This is a follow-up post for our first blog post titled “GitHub Actions Security Best Practices (With Checklist)” in the series. In this post, we will deep dive into GitHub Actions secret management best practices.

GitHub Action workflows need secrets to perform sensitive operations such as managing cloud resources, pushing built container images to registries, and so on. As these are privileged credentials with elevated access, it's paramount for enterprises to make sure that GitHub Actions secrets are secured.  

We will discuss the use of OpenID Connect (OIDC) and the least privileged access tokens in separate blog posts. This blog covers all the other best security practices for GitHub Actions secrets.

What are GitHub Actions Secrets?

GitHub Actions secrets are variables that enable you to store sensitive information in your repositories. These can be admin access keys, credentials, or organization secrets- all sensitive data that needs to be fully secured. These secrets could be created at the organization, repository, or repository environment levels. Although securing GitHub Actions secrets can be quite a tricky job, we have provided practical easy-to-follow tips below to implement GitHub Actions secrets best practices.

Rotate Secrets Regularly

It is important to rotate your GitHub Actions secrets and invalidate old ones to keep them secure in workflows.  

To view your Actions secrets, you can visit the repository settings page. Although you will not be able to explore all your GitHub secrets and their metadata in one place, there are ways you can view this inventory. Here are some of them:

  1. Explore secrets on the repository settings page for each of the repositories.
  2. Utilize GitHub APIs to create an application that catalogs all secrets and their metadata throughout your GitHub organization.

Using Actions secrets only for storing secrets and not non-sensitive information can make it easier for organizations to use the methods described above to discover stale secrets and rotate them without worrying about false positives.

Did you know that StepSecurity’s GitHub Actions security platform can help you discover stale GitHub Actions secrets across your GitHub organization? Get started for free here.

Screenshot showing a dashboard displaying the number of days since secrets have been rotated
Screenshot showing a dashboard displaying the number of days since secrets have been rotated

Restrict Organizational Secrets to Specific Repositories

Whenever possible, you should avoid using Organizational secrets as these secrets could potentially be available to all repositories in your organization. If you have a common secret that you would like to use across multiple repositories, you should create an organizational secret and scope it to only specific repositories that need it. By default, organizational secrets are available to all internal and private repositories. In a large enterprise environment, this could mean hundreds of repositories can access these shared organizational secrets. You should instead scope it to be used by specific repositories in your organization.

Screenshot showing how to set your repositories to be private and internal
Screenshot showing how to set your repositories to be private and internal

Use Actions Secrets Only for Storing Secrets

This is a practical tip to enable organizations to reduce the operational burden of managing GitHub Actions secrets. GitHub Actions secrets must only be used for storing secrets. For non-sensitive data, Actions variables must be used. Like GitHub Actions secrets, Actions variables can be created at the organization, repository, or repository environment levels.

We have seen many enterprises use GitHub secrets for storing configuration values such as environment type (e.g., dev, prod, etc.), resource names (e.g., AWS account number), etc. Such non-sensitive information must be migrated over to GitHub variables.  This will allow enterprises to invest their resources to truly secure Actions secrets and not worry about non-sensitive data in their Actions environments.

Screenshot showing the creation of a new Action variable
Screenshot showing the creation of a new Action variable

Use Least Privileged Secrets

Just like any other secrets, you must use the least privileged secrets with your GitHub Actions. A practical matter to consider for GitHub Actions is whether to reuse the same secret across multiple workflows (e.g., AWS identity) or create a unique GitHub secret per environment.  

From a security perspective, having a unique secret per workflow job is ideal. However, this will be an operational nightmare for large organizations that may have hundreds/thousands of GitHub Actions workflow jobs in their environment. A practical approach could be to segment Action workflows by environments (e.g., dev vs prod) or services (e.g., payment service vs service health monitoring service) and do not re-use Actions secrets across workflows belonging to multiple segments.

Leverage Environment Secrets and Mandatory Reviews for Production Secrets

Your GitHub Actions secrets can be easily exfiltrated and leaked by bad actors. This may include sensitive data like admin cloud credentials, organization secrets, or public keys. All the workflows and branches in the repository have access to your GitHub Actions secrets and can be exfiltrated by updating a workflow or creating a new one and referencing the secret.  

One way you can secure your GitHub Actions secrets is by leveraging environment secrets. These secrets stored at an environment level enable you to implement guardrails by enforcing mandatory reviews. This means they can only be accessed by an authorized reviewer who can approve the workflow run. No job will have access to these secrets without the approval of the reviewer.  

Environment secrets also allow you to implement other quality gates including static code analyzers that can flag issues and ensure the absence of vulnerable dependencies in the workflow.

Screenshot showing usage of environment secrets to secure a production secret
Screenshot showing usage of environment secrets to secure a production secret

Avoid Printing Secrets in Actions Run Logs

When GitHub Actions detects a secret in workflow run logs, it hides it by default. This means that the value of the key or secret will be hidden in the log automatically. Take, for instance, a secret named SECRET_API_KEY used in GitHub Actions. When this workflow is executed:

name: Secret Redaction In Logs

on:
  workflow_dispatch:

jobs:
  print-secret:
    runs-on: ubuntu-latest
    steps:
    - name: Print Secret Value
      run: |
        echo "Secret API Key: ${{ secrets.SECRET_API_KEY }}"


The log will show that the API key is actual value is obscured:

Screenshot showing concealed API key
Screenshot showing concealed API key

This feature is limited to secrets that GitHub Actions recognizes, meaning only those secrets explicitly linked to the workflow are masked.

Secrets created during the runtime (e.g., an authorization token generated after completing an OAuth handshake) won't be masked if they appear in build logs. It's crucial to avoid logging secrets altogether. This is especially important for public open-source GitHub repositories, as logs from GitHub Actions in such repositories are accessible to the public. As of now, there's no option to set these logs to private.  

Don't Use Structured Data as Secrets

This is an extension of the previous best practice. If you use custom structured data like a blob of JSON, XML, or YAML to encapsulate a secret value, it will not get redacted. Furthermore, using a custom data structure for storing secrets also leads to engineering issues such as standard dev tools not recognizing the secret correctly as it expects it differently. As GitHub Actions doesn’t provide an easy way to extract GitHub Actions secrets for debugging and troubleshooting, debugging such issues can become complex.

Also Read: Best Practices in GitHub Actions Security: A Case Study with Google’s Use of StepSecurity

Scan GitHub Actions Logs for Secrets

Scanning your GitHub Actions logs for secrets can help you detect accidental leakages of secrets from build tools and third-party components. GitHub does not provide a built-in way to scan GitHub Actions logs, you need to build such a system yourself. One way to implement this system is to create a GitHub App that subscribes to Actions completion events. Once an Action job has finished, you can download logs using the GitHub App and scan them using a secret scanner.

Conclusion

Managing GitHub Actions secrets can be quite a task but with these simple best practices, you should be able to securely manage them and enhance your GitHub Actions security. Stay tuned for our next GitHub Actions security blog post to learn how you can stay ahead of the evolving threats and secure your workflows from serious leaks and attacks.