Course outline · 0% complete

0/29 lessons0%

Course overview →

Secrets and environments

lesson 8-2 · ~11 min · 23/29

Where credentials live

To docker push, the pipeline needs a registry password. It cannot go in the workflow file, because that file is in git, and anything ever committed is effectively public forever (lesson 3-3 kept .env out of images for the same reason).

CI systems solve this with secrets: values stored encrypted in the repo settings, injected into the workflow at run time, and masked as *** if a log tries to print them.

      - name: Log in to registry
        run: docker login ghcr.io -u ada -p "${{ secrets.REGISTRY_TOKEN }}"
      - run: docker push ghcr.io/ada/shop:${{ github.sha }}

${{ secrets.REGISTRY_TOKEN }} is the same expression syntax as github.sha in lesson 7-3, but it reads from the encrypted store. The value exists only on the runner, only during the run.

Environments

Apps also need non-secret config that differs per place they run: staging (the rehearsal copy of production) points at a test database, production points at the real one.

The mechanism is the one you wired in lesson 5-2: environment variables, set differently per environment while the image stays identical. GitHub Actions formalizes this with named environments, each carrying its own variables and secrets:

jobs:
  deploy:
    environment: production
    steps:
      - run: ./deploy.sh
        env:
          DB_HOST: ${{ vars.DB_HOST }}

Same workflow, same image, and DB_HOST resolves to the staging value or the production value depending on which environment the job targets. The next two blocks make you fluent in the bash side of this.

Code exercise · bash

Run this. export sets an environment variable in the shell, and the script reads whatever the environment provides, exactly how a container or CI step gets its config.

Code exercise · bash

Your turn: robust scripts provide defaults for missing config with ${VAR:-default}. First print "db host: localhost" while DB_HOST is unset (use a default of localhost). Then export DB_HOST="db.internal" and print the same line again.

Quiz

A teammate suggests committing the registry password into ci.yml "just temporarily". What is the correct objection?

Problem

One word: what does a CI system call values like registry passwords that are stored encrypted in repo settings, injected only at run time, and masked in logs?