A Buildkite plugin to fetch secrets from multiple providers and inject them into your build environment.
Supported providers:
If upgrading from v1.x.x, note these changes:
- Log format: Uses structured prefixes (
[INFO],[WARNING],[ERROR]) instead of emoji - Removed:
dump_envfunction removed for security - New default: Secrets auto-redacted from logs (requires agent v3.67.0+). Opt out with
skip-redaction: true - Stricter errors: Invalid base64-encoded secrets now fail immediately
The default provider fetches secrets from Buildkite Secrets.
You can create a secret in your Buildkite cluster(s) from the Buildkite UI following the instructions in the documentation here.
Create a Buildkite secret for each variable that you need to store. Paste the value of the secret into buildkite.com directly.
A pipeline.yml like this will read each secret out into an environment variable:
steps:
- command: echo "The content of ANIMAL is \$ANIMAL"
plugins:
- secrets#v2.4.0:
variables:
ANIMAL: llamas
FOO: barCreate a single Buildkite secret with one variable per line, encoded as base64 for storage.
For example, setting three variables looks like this in a file:
Foo=bar
SECRET_KEY=llamas
COFFEE=moreThen encode the file:
cat data.txt | base64Next, upload the base64 encoded data to buildkite.com in your browser with a
key of your choosing - like llamas. The three secrets can be read into the
job environment using a pipeline.yml like this:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
env: "llamas"Fetches secrets from GCP Secret Manager.
- The gcloud CLI must be installed and available on the Buildkite agent.
- The agent must be authenticated to GCP with permissions to access Secret Manager (e.g., the
roles/secretmanager.secretAccessorrole). For Buildkite-hosted agents, use the gcp-workload-identity-federation plugin to authenticate. - The Secret Manager API must be enabled on the GCP project.
The GCP project is resolved in this order:
- The
gcp-projectplugin option - The
CLOUDSDK_CORE_PROJECTenvironment variable - The active
gcloud configproject (gcloud config get-value project)
Create secrets in GCP Secret Manager, then map them to environment variables:
steps:
- command: build.sh
plugins:
- gcp-workload-identity-federation#v1.5.0:
audience: "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/buildkite"
service-account: "my-service-account@my-project-id.iam.gserviceaccount.com"
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
variables:
API_KEY: my-api-key-secret
DB_PASSWORD: my-db-password-secretEach key under variables becomes the environment variable name, and the value is the GCP secret ID to fetch.
Store multiple KEY=value pairs in a single GCP secret, base64-encoded:
# Create a file with your variables
cat > secrets.txt <<EOF
API_KEY=sk-abc123
DB_HOST=db.example.com
DB_PASSWORD=supersecret
EOF
# Base64-encode and store in GCP Secret Manager
base64 secrets.txt | gcloud secrets create ci-env-secrets --data-file=-Then reference the secret in your pipeline:
steps:
- command: build.sh
plugins:
- gcp-workload-identity-federation#v1.5.0:
audience: "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/buildkite"
service-account: "my-service-account@my-project-id.iam.gserviceaccount.com"
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
env: "ci-env-secrets"Use provider: azure to fetch secrets from Azure Key Vault.
- Azure CLI (
az) installed on your Buildkite agent - The agent must be authenticated to Azure. Use the azure-login plugin to authenticate via managed identity or service principal.
- The authenticated identity must have the
Key Vault Secrets Userrole (or equivalentgetpermission) on the vault
Set provider: azure and azure-vault-name in your plugin configuration:
steps:
- command: build.sh
plugins:
- azure-login#v1.0.1:
client-id: "your-client-id"
tenant-id: "your-tenant-id"
- secrets#v2.4.0:
provider: azure
azure-vault-name: my-vault
variables:
API_KEY: my-api-key-secretEach key in variables maps to an Azure Key Vault secret name. The secret's value is fetched and exported as the corresponding environment variable:
steps:
- command: build.sh
plugins:
- azure-login#v1.0.1:
client-id: "your-client-id"
tenant-id: "your-tenant-id"
- secrets#v2.4.0:
provider: azure
azure-vault-name: my-vault
variables:
DB_PASSWORD: db-password
API_TOKEN: api-token
SSH_KEY: deploy-ssh-keyAzure Key Vault secret names must contain only alphanumeric characters and hyphens, and must start with an alphanumeric character.
Store multiple KEY=value pairs as a single base64-encoded Azure Key Vault secret, then use env to fetch and decode them all at once:
steps:
- command: build.sh
plugins:
- azure-login#v1.0.1:
client-id: "your-client-id"
tenant-id: "your-tenant-id"
- secrets#v2.4.0:
provider: azure
azure-vault-name: my-vault
env: batch-secretsTo create the batch secret:
# Create a file with KEY=value pairs
cat > data.txt <<EOF
DB_HOST=mydb.example.com
DB_PASSWORD=supersecret
API_KEY=abc123
EOF
# Base64 encode and store in Azure Key Vault
az keyvault secret set --vault-name my-vault --name batch-secrets --value "$(base64 < data.txt)"Use provider: aws to fetch secrets from AWS Secrets Manager.
- The AWS CLI (
aws) installed on your Buildkite agent. - The agent must be authenticated to AWS with permissions to call
secretsmanager:GetSecretValueon the relevant secrets. Use the aws-assume-role-with-web-identity plugin to authenticate via OIDC; an instance profile or static credentials in the environment also work. - jq installed on the agent if you use
json-variables(see below).
The AWS region is resolved in this order:
- The
aws-regionplugin option - The AWS CLI's configured region (e.g.
AWS_REGION,AWS_DEFAULT_REGION, or the agent's instance/profile configuration)
Create secrets in AWS Secrets Manager, then map them to environment variables:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
variables:
API_KEY: my-api-key-secret
DB_PASSWORD: my-db-password-secretEach key under variables becomes the environment variable name, and the value is the AWS secret name or ARN to fetch.
Store multiple KEY=value pairs in a single AWS secret, base64-encoded:
# Create a file with your variables
cat > secrets.txt <<EOF
API_KEY=sk-abc123
DB_HOST=db.example.com
DB_PASSWORD=supersecret
EOF
# Base64-encode and store in AWS Secrets Manager
aws secretsmanager create-secret --name ci-env-secrets --secret-string "$(base64 < secrets.txt)"Then reference the secret in your pipeline:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
env: "ci-env-secrets"AWS Secrets Manager commonly stores secrets as a single JSON object (e.g. {"username": "admin", "password": "supersecret"}). Use json-variables to expand the keys of a JSON object directly into environment variables, without needing to base64-encode anything or invoke jq yourself:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
json-variables:
- secret-id: rds/my-database-credentialsIf rds/my-database-credentials resolves to:
{
"username": "admin",
"password": "supersecret",
"port": 5432
}Then username, password, and port are each exported as environment variables.
Each entry takes:
secret-id(required) — the AWS secret name or ARN to fetch.json-key(optional, default.) — ajqpath into the secret's JSON content to expand. Use this when the keys you want live under a nested object rather than at the root:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
json-variables:
- secret-id: my-secret-id
json-key: ".Variables"With a secret called my-secret-id containing:
{
"Variables": {
"MY_SECRET": "value",
"MY_OTHER_SECRET": "other value"
}
}This sets the MY_SECRET and MY_OTHER_SECRET environment variables.
Only keys with string, number, or boolean values are expanded — nested objects/arrays are skipped. Keys are sanitized into valid shell variable names by replacing any character that isn't a letter, digit, or underscore with _, and prefixing the result with _ if it would otherwise start with a digit (e.g. My-great key! becomes My_great_key_).
Use provider: op to fetch secrets from 1Password using the op CLI.
- The 1Password CLI (
op) installed on your Buildkite agent - One of the following authentication methods configured on the agent:
- Connect Server (recommended for self-hosted agents): set
OP_CONNECT_HOSTandOP_CONNECT_TOKEN - Service Account: set
OP_SERVICE_ACCOUNT_TOKEN - Interactive session: sign in with
op signinbefore the build runs
- Connect Server (recommended for self-hosted agents): set
Secrets can be specified in either short or full form:
- Short form:
vault/item/field— theop://prefix is added automatically - Full form:
op://vault/item/field— explicit, useful when mixing with other tooling
Where:
vault— the name or ID of your 1Password vaultitem— the name or ID of the item within that vaultfield— the field to read from the item (e.g.password,credential, or a custom field label)
Map environment variable names to secret references:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: op
variables:
API_KEY: my-vault/my-api-key/credential
DB_PASSWORD: my-vault/db-creds/passwordStore multiple KEY=value pairs in a single 1Password item field, base64-encoded, and use env to fetch and decode them all at once:
# Create a file with KEY=value pairs
cat > data.txt <<EOF
DB_HOST=mydb.example.com
DB_PASSWORD=supersecret
API_KEY=abc123
EOF
# Base64 encode and store as a 1Password item (e.g. in a "Password" or "Text" field)
op item create --category=login --title="ci-batch-secrets" --vault=my-vault \
credential="$(base64 < data.txt)"Then reference it in your pipeline:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: op
env: my-vault/ci-batch-secrets/credentialYou can use env and variables together to fetch both batch and individual secrets in a single plugin call.
GCP:
steps:
- command: build.sh
plugins:
- gcp-workload-identity-federation#v1.5.0:
audience: "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/buildkite"
service-account: "my-service-account@my-project-id.iam.gserviceaccount.com"
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
env: "ci-env-secrets"
variables:
DEPLOY_KEY: deploy-key-secretAzure:
steps:
- command: build.sh
plugins:
- azure-login#v1.0.1:
client-id: "your-client-id"
tenant-id: "your-tenant-id"
- secrets#v2.4.0:
provider: azure
azure-vault-name: my-vault
env: batch-secrets
variables:
DEPLOY_KEY: deploy-key-secretAWS:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
env: "ci-env-secrets"
variables:
DEPLOY_KEY: deploy-key-secret
json-variables:
- secret-id: rds/my-database-credentials1Password:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: op
env: my-vault/ci-batch-secrets/credential
variables:
DEPLOY_KEY: my-vault/deploy-key/credentialBy default, the latest version of each secret is fetched. To pin to a specific version:
steps:
- command: build.sh
plugins:
- gcp-workload-identity-federation#v1.5.0:
audience: "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/buildkite"
service-account: "my-service-account@my-project-id.iam.gserviceaccount.com"
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
gcp-secret-version: "5"
variables:
API_KEY: my-api-key-secretBy default, the latest version of each secret is fetched. To pin to a specific version:
steps:
- command: build.sh
plugins:
- azure-login#v1.0.1:
client-id: "your-client-id"
tenant-id: "your-tenant-id"
- secrets#v2.4.0:
provider: azure
azure-vault-name: my-vault
azure-secret-version: "a1b2c3d4e5f6"
variables:
API_KEY: my-api-keyBy default, the AWSCURRENT staged version of each secret is fetched. To pin to a specific version:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
aws-secret-version-id: "EXAMPLE1-90ab-cdef-fedc-ba987EXAMPLE"
variables:
API_KEY: my-api-key-secretOr pin to a staging label (e.g. AWSPREVIOUS) with aws-secret-version-stage:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: aws
aws-region: us-east-1
aws-secret-version-stage: "AWSPREVIOUS"
variables:
API_KEY: my-api-key-secretUse the git-credentials option to fetch git credentials from any of the
supported providers and configure them for the agent's checkout, without storing
them as a Kubernetes Secret or a static file on the agent.
The plugin runs in the environment hook, which the Agent runs inside the
checkout container before the repository is cloned. The referenced secret
value is used as a git credentials file
entry, and the
plugin configures git's store credential helper to use it:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
git-credentials: github-https-credentialsStore the secret value in the standard git credentials format, one entry per line:
https://x-access-token:ghp_yourtoken@github.com
The fetched credentials are written to a private, job-scoped file and removed again in the
pre-exit hook. Set git-credentials-file to control where the file is
written. By default, this will create a temporary file.
The credentials may be stored raw or base64-encoded. The plugin detects and decodes base64 automatically.
git-credentials and git-ssh-key are mutually exclusive. Configure one git
auth method per step. Setting both will result in an exit 1.
For SSH-based checkouts such as git@host:... or ssh://... remotes, use git-ssh-key.
The plugin fetches an SSH private key from the active provider, writes it to a
private file, and configures git's core.sshCommand to use it, with host key
verification enabled. The configured ssh ignores user and system ssh_config,
to ensure that tokens are used per-job, opposed to agent-wide.
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
git-ssh-key: deploy-keyHost key verification uses GitHub's published host keys by default. To verify a
different host such as a self-hosted git server, supply your own
known_hosts contents:
- secrets#v2.4.0:
provider: gcp
gcp-project: my-project-id
git-ssh-key: deploy-key
git-ssh-known-hosts: |
git.internal.example.com ssh-ed25519 AAAA...The key is written to a private job scoped file and removed again in the
pre-exit hook. The key may be stored raw or base64-encoded. The plugin
detects and decodes base64 automatically.
git-credentials and git-ssh-key are mutually exclusive. Configure one git
auth method per step. Setting both will result in an exit 1.
This plugin never writes or modifies ~/.gitconfig. It injects config only through
job scoped GIT_CONFIG_* environment variables that apply to this job's git
processes. The credential helper is scoped to each host in your secret, and for those
hosts it first resets any inherited helper so nothing else can intercept the request
or store the token. Any credential helper the agent already had keeps working for
every other host, and the injected core.sshCommand applies only to this job. The
pre-exit hook removes the secret file it wrote.
Match the option to how the repository is cloned. git-credentials authenticates HTTPS remotes and git-ssh-key authenticates SSH remotes. The two do not cross over,
so an HTTPS credential cannot authenticate an SSH clone. If your pipeline checks out over SSH, you will need to select git-ssh-key. If it checks out over HTTPS you need git-credentials.
Because the plugin runs before the checkout, the fetched git-credentials or git-ssh-key will be used for the repo's own checkout, not only repositories you clone later in the build.
As such, the method you select should to match your pipeline repo's clone URL, not just the URLs you use in your build steps.
git-ssh-key configures a job wide core.sshCommand, so the fetched key becomes the only SSH identity git uses for the whole job, including the checkout.
Any pre-existing SSH identity is not used while the key is configured.
On the Agent Stack for Kubernetes the environment hook runs in every container that runs the plugin phase, which is
both the checkout container and the command container in this case. Each one fetches the secret and configures git locally, so the credential is available for the checkout and for
command phases you run in your build. The token will be destroyed in the pre-exit phase.
By default, the Buildkite Agent ships with git and ssh which are required for this plugin,if you are using a custom image, please ensure that git, ssh and if your token is base64 encoded, base64
are installed.
These options apply to all providers.
| Option | Type | Default | Description |
|---|---|---|---|
provider |
string | buildkite |
The secrets provider to use. Supported values: buildkite, gcp, azure, aws, op. |
env |
string | - | Secret key name for fetching batch secrets (base64-encoded KEY=value format). |
variables |
object | - | Map of ENV_VAR_NAME: secret-path pairs to inject as environment variables. |
json-variables |
array | - | List of { secret-id, json-key } objects (AWS only). Expands the JSON object at json-key (a jq path, default .) within each secret into one environment variable per key. |
mute-log |
boolean | true |
If true (default), the "Fetching secrets" header renders as a de-emphasized ~~~ group. Set to false to use the bold --- style. |
skip-redaction |
boolean | false |
If true, secrets will not be automatically redacted from logs. |
retry-max-attempts |
number | 5 |
Maximum retry attempts for transient failures. |
retry-base-delay |
number | 2 |
Base delay in seconds for exponential backoff between retries. |
git-credentials |
string | - | Secret holding HTTPS git credentials for the checkout. |
git-credentials-file |
string | - | Absolute path to write the credentials to. Defaults to a private temp file. |
git-ssh-key |
string | - | Secret holding an SSH private key for the checkout. |
git-ssh-known-hosts |
string | GitHub | known_hosts contents to verify the SSH host. Defaults to GitHub's keys. |
These options only apply when provider: gcp is set.
| Option | Type | Default | Description |
|---|---|---|---|
gcp-project |
string | - | GCP project ID. Falls back to CLOUDSDK_CORE_PROJECT or gcloud config. |
gcp-secret-version |
string | latest |
The secret version to fetch. |
These options only apply when provider: azure is set.
| Option | Type | Default | Description |
|---|---|---|---|
azure-vault-name |
string | - | The Azure Key Vault name (required when provider is azure). |
azure-secret-version |
string | latest | The secret version to fetch. If not specified, the latest version is used. |
These options only apply when provider: aws is set.
| Option | Type | Default | Description |
|---|---|---|---|
aws-region |
string | - | AWS region to fetch secrets from. Falls back to the AWS CLI's configured region. |
aws-secret-version-id |
string | - | The Secrets Manager version ID to fetch. Defaults to the AWSCURRENT staged version. |
aws-secret-version-stage |
string | - | The Secrets Manager staging label to fetch (e.g. AWSPREVIOUS). Defaults to AWSCURRENT. |
The op provider has no additional plugin options. Authentication is handled via agent environment variables (OP_CONNECT_HOST+OP_CONNECT_TOKEN for Connect Server, or OP_SERVICE_ACCOUNT_TOKEN for service accounts) or an existing op session. All secret paths are specified directly as op://vault/item/field references in env and variables.
By default, this plugin automatically redacts all fetched secrets from your Buildkite logs to prevent accidental exposure. This includes:
- The raw secret values
- Shell-escaped versions of secrets
- Base64-decoded versions of secrets (if the secret appears to be base64-encoded)
The redaction feature uses the buildkite-agent redactor add command, which requires buildkite-agent v3.67.0 or later. If you're running an older version, the plugin will log a warning and continue without redaction.
To disable automatic redaction (not recommended), set skip-redaction: true:
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
env: "llamas"
skip-redaction: trueThis plugin implements automatic retry logic with exponential backoff for secret calls. This will occur for 5xx server errors or any local network issues. If a 4xx code is received, a fast failure will be served.
By default, the base delay will be 2 seconds, with a maximum of 5 retries.
steps:
- command: build.sh
plugins:
- secrets#v2.4.0:
env: "llamas"
retry-max-attempts: 10
retry-base-delay: 2You can run the tests using docker-compose:
docker compose run --rm testsMIT (see LICENSE)