Migrate GitHub Actions secrets

GitHub doesn't let you read a secret's value after you save it. To move GitHub Actions repository secrets into Buildkite secrets, use the Buildkite CLI to create a one-use migration workflow.

GitHub Actions sends the selected values directly to Buildkite. The values don't pass through your machine.

Private preview

This feature is in private preview. Contact Buildkite support to have it enabled for your organization.

Until it's enabled, bk secret migrate github-actions run can't start a migration.📘 Buildkite CLI version

Use Buildkite CLI version 3.59.1 or later. Check your version with bk version.

Before you start

You need:

  • A local checkout of a github.com repository that has GitHub Actions repository secrets.
  • The GitHub CLI signed in to an account that can read the repository's Actions secrets.
  • The Buildkite CLI signed in to the Buildkite organization that will receive the secrets, with an API access token that has the read_pipelines, read_secrets_details, and write_secrets scopes.
  • A Buildkite pipeline for the repository.
  • Cluster maintainer access to that pipeline's cluster, or Buildkite organization administrator access.

Create the migration workflow

From your repository, run:

bk secret migrate github-actions prepare \
  --secret DEPLOY_TOKEN \
  --match 'AWS_*' \
  --output .github/workflows/migrate-buildkite-secrets.yml

The Buildkite CLI finds the Buildkite pipeline for your repository and creates a workflow that names each secret it will move. If any selected secret already exists in the destination cluster, the command stops without creating a workflow.

To choose secrets interactively, leave out --secret and --match.

Review and merge the workflow

Review the workflow like any other code change. Check which secrets it moves, where they go, and which pipeline can use them.

By default, only the matched pipeline can use the migrated secrets. To use a different access policy, pass --policy-file when you create the workflow. The policy must contain at least one rule, and every rule must include at least one condition, such as pipeline_id. Buildkite rejects policies that would let every job in the cluster read the secrets.

The Buildkite CLI doesn't commit or push files. Commit the workflow without changing it:

git add .github/workflows/migrate-buildkite-secrets.yml
git commit -m "Migrate GitHub Actions secrets to Buildkite"
git push origin main

If your default branch requires pull requests, create a pull request:

git switch -c migrate-buildkite-secrets
git add .github/workflows/migrate-buildkite-secrets.yml
git commit -m "Migrate GitHub Actions secrets to Buildkite"
git push -u origin migrate-buildkite-secrets
gh pr create --fill

Merge the pull request after it's approved.

Run the migration

Run the workflow:

bk secret migrate github-actions run \
  --workflow .github/workflows/migrate-buildkite-secrets.yml

The Buildkite CLI checks that the workflow on your default branch matches the reviewed workflow before it starts the migration. If the workflow has changed, the command stops.

The command prints the GitHub Actions run URL:

Dispatch accepted for .github/workflows/migrate-buildkite-secrets.yml on main with 3 secrets. The migration is not complete until the GitHub Actions run succeeds.
Actions: https://github.com/acme-inc/app/actions/runs/123456789

A successful command means GitHub started the workflow. The migration is complete only after the GitHub Actions run succeeds.

To watch the run from your terminal:

gh run watch 123456789 --exit-status

A successful run prints the names of the secrets it created:

Created Buildkite secret DEPLOY_TOKEN
Created Buildkite secret AWS_ACCESS_KEY_ID
Created Buildkite secret AWS_SECRET_ACCESS_KEY
Migration complete. Remove this workflow from the default branch.

Each migration can only be used once. If the run fails before it creates the secrets, rerun the command above with the same --workflow path.

The migration runs with the Buildkite permissions of the user who ran the command. If that user leaves the organization or loses permission to manage the destination cluster before the GitHub Actions run sends the secrets, the run fails without creating any secrets.

Remove the workflow

After the migration succeeds, remove the workflow:

git rm .github/workflows/migrate-buildkite-secrets.yml
git commit -m "Remove secret migration workflow"
git push origin main

If your default branch requires pull requests, remove the workflow in a pull request.

Use the migrated secrets

Add each secret to the step that needs it:

steps:
  - label: "Deploy"
    command: "./scripts/deploy.sh"
    secrets:
      - DEPLOY_TOKEN

Secrets in commands

Buildkite Pipelines interpolates $DEPLOY_TOKEN when it uploads your pipeline YAML, before your job receives its secrets. If you reference a secret directly in a YAML command, use $$DEPLOY_TOKEN.

steps:
  - label: "Check secret"
    command: "test -n \"$$DEPLOY_TOKEN\""
    secrets:
      - DEPLOY_TOKEN

Limitations

  • Only github.com repository secrets are supported. GitHub Enterprise Server and other GitHub secret types aren't supported.
  • Each workflow can move up to 40 secrets.
  • Each secret value must not be blank and must be smaller than 32 KiB.
  • You can't migrate GITHUB_TOKEN.
  • The migration never overwrites an existing Buildkite secret.

Workflows prepared by buildkite-gha

buildkite-gha v0.102.0 removed the buildkite-gha migrate-secrets command. If you prepared a migration workflow with buildkite-gha migrate-secrets v0.90.0 or later, you don't need to regenerate or recommit it. Run it with bk secret migrate github-actions run --workflow <path>.

For the trust boundaries of the migration grant, see the secrets migration security model.