Back to Blog
Lesson 16 of the CI/CD: Continuous Integration from Scratch course
DevOpsJuly 16, 20264 min read

Managing Secrets: Securing Your CI/CD Pipelines

Learn how to use GitHub Secrets to store sensitive tokens and API keys, ensuring your CI/CD pipelines remain secure and free from hardcoded credentials.

DevOpsGitHub ActionsCI/CDsecuritysecretsautomation
A close-up of CDs and disks on a desk, featuring hands in a tech environment.

Previously in this course, we covered Building Images in CI. Now that your pipeline can build container images, you likely need a way to push those images to a registry or interact with external services. We cannot hardcode passwords or API keys directly into our YAML files, as that would expose them to anyone with repository access. In this lesson, we will solve this by implementing GitHub Secrets.

The Danger of Hardcoded Credentials

When you need to authenticate with a cloud provider or a package registry, the naive approach is to paste your credentials directly into your workflow file. This is a critical security failure. Once a secret is committed to Git, it is part of the repository history forever, even if you delete the line in a later commit.

GitHub Secrets provides an encrypted key-value store tied to your repository. When you add a secret, GitHub encrypts it at rest. When your workflow runs, GitHub decrypts the value and injects it into the runner’s memory, masking the value in the logs so it never accidentally leaks to the console.

Creating a Repository Secret

Before a workflow can use a secret, it must exist in the GitHub UI. Follow these steps:

  1. Navigate to your repository on GitHub.
  2. Click the Settings tab.
  3. In the left sidebar, expand Secrets and variables and click Actions.
  4. Click New repository secret.
  5. Give it a name (e.g., DOCKERHUB_TOKEN) and paste your actual secret value into the Secret field.
  6. Click Add secret.

Once created, this value is invisible in the UI. You cannot read it back; you can only update or delete it.

Accessing Secrets in Your Workflow

To use the secret, you must map it to an environment variable within your workflow file. You do this using the env context. It is important to remember that GitHub Secrets are not automatically available to your shell; you must explicitly define them.

Here is an example of a workflow step that consumes a secret:

YAML
jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Login to Docker Hub
        run: echo "$DOCKER_PASSWORD" | docker login -u myuser --password-stdin
        env:
          DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}

In this snippet, we map the GitHub Secret DOCKERHUB_TOKEN to the local environment variable DOCKER_PASSWORD. The run command then uses that variable. Because the value is stored in an environment variable, it remains hidden from the log output.

Hands-on Exercise

  1. Create a dummy secret: Go to your repository settings and create a secret named MY_API_KEY with the value super-secret-123.
  2. Update your workflow: Create a new test step in your existing pipeline that echoes this secret.
  3. Verify the mask: Run the workflow and inspect the logs for that step. You should see *** instead of super-secret-123.
  4. Failure test: Try to print the secret without mapping it to an environment variable. Observe that the shell cannot find the variable, confirming the secret is not globally available by default.

Common Pitfalls

  • Assuming global scope: Secrets are not available as system-wide environment variables. If you don't map them using the env keyword in your job or step, they simply won't exist in your shell environment.
  • Logging the secret: While GitHub automatically masks the secret value, if you accidentally transform it (e.g., echo $SECRET | base64), the mask might fail, and the value could appear in your logs. Always avoid manipulating secrets in ways that might bypass masking.
  • Case sensitivity: Remember that secret names are case-sensitive. If you define DOCKER_TOKEN in settings, calling secrets.docker_token in your YAML will return an empty string.

FAQ

Can I use secrets in other repositories? By default, secrets are scoped to the repository where they are created. To share them across multiple projects, you should look into Organization Secrets or GitHub Environments.

What if I need to use the secret in multiple steps? You can define the env block at the job level instead of the step level. This makes the environment variable available to every step within that job.

Is it safe to use secrets for non-sensitive data? It is better to use Environment Variables for configuration that isn't secret. Secrets should be reserved for credentials that, if leaked, would compromise your security.

Recap

GitHub Secrets are the primary mechanism for securing your CI/CD pipelines. By creating them in your repository settings and mapping them to env variables, you ensure your credentials remain private while still being accessible to your automated processes.

Up next: Handling Environment Variables — we will learn how to organize your non-sensitive configuration for better maintainability.

Similar Posts