drone-secrets-sync
is able to idempotently synchronise Drone CI repository and organisation secrets.
# Synchronise repository secrets from JSON file
drone-secrets-sync repo octocat/hello-world secrets.json
# Synchronise organisation secrets from JSON file
drone-secrets-sync org octocat secrets.json
# Synchronise multiple repository secrets from JSON map on stdin
echo '{"some-secret": "example", "other-secret": "value"}' \
| drone-secrets-sync repo octocat/hello-world
# Synchronise multiple organisation secrets from JSON map on stdin
echo '{"some-secret": "example", "other-secret": "value"}' \
| drone-secrets-sync org octocat
The tool will output what secrets have changed, e.g.
["some-secret","other-secret"]
The Drone CI API does not provide access to secret values. Therefore, to allow the determination as to whether a secret already contains the required value, two secrets are created:
- The requested secret with the name, and value supplied.
- A corresponding "hash secret", with a name that contains a salted hash of the secret value.
drone secret ls --format '{{ .Name }}' octocat/hello-world
secret
secret___e861b26001c00803bb492889c1cf3faaf5a093ebc59f2c6838c7e10edfae4d0a
Be aware that exposing hashes makes it possible for an attacker that has gained access to the Drone API to brute force secret values offline. Hashes are generated using Argon2 to make attacks more difficult. The memory and compute required to generate hashes can be configured.
docker run --rm colinnolan/drone-secrets-sync --help
Release builds for various architectures can be downloaded from GitHub, e.g.
curl -fsL https://github.com/colin-nolan/drone-secrets-sync/releases/latest/drone-secrets-sync_linux-amd64 /usr/local/bin/drone-secrets-sync
chmod +x /usr/local/bin/drone-secrets-sync
go install github.com/colin-nolan/drone-secrets-sync/cmd/drone-secrets-sync@latest
make install
The tool uses the Drone API via the official drone-go library. It requires DRONE_TOKEN
and DRONE_SERVER
environment variables to be set, e.g.
# Configure environment - see: https://docs.drone.io/cli/configure
export DRONE_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
export DRONE_SERVER=http://drone.mycompany.com
Usage: drone-secrets-sync [--argon2-iterations ARGON2-ITERATIONS] [--argon2-length ARGON2-LENGTH] [--argon2-memory ARGON2-MEMORY] [--argon2-parallelism ARGON2-PARALLELISM] [--dry-run] [--droneserver DRONESERVER] [--dronetoken DRONETOKEN] [--verbose] <command> [<args>]
Options:
--argon2-iterations ARGON2-ITERATIONS, -i ARGON2-ITERATIONS
number of argon2 iterations to create corresponding hash secret name [default: 32]
--argon2-length ARGON2-LENGTH, -l ARGON2-LENGTH
length of argon2 hash used in corresponding hash secret name [default: 32]
--argon2-memory ARGON2-MEMORY, -m ARGON2-MEMORY
memory for argon2 to use when creating corresponding hash secret name [default: 65536]
--argon2-parallelism ARGON2-PARALLELISM, -p ARGON2-PARALLELISM
parallelism used when creating argon2 hash [default: 4]
--dry-run, -d indicate only what secrets would be updated; does not update secrets
--droneserver DRONESERVER [env: DRONE_SERVER]
--dronetoken DRONETOKEN [env: DRONE_TOKEN]
--verbose, -v enable verbose logging
--help, -h display this help and exit
--version display version and exit
Commands:
repository sync secrets for a repository
repo sync secrets for a repository
organisation sync secrets for an organisation
org sync secrets for an organisation
Usage: drone-secrets-sync repo REPOSITORY [SECRETSFILE]
Positional arguments:
REPOSITORY repository to sync secrets for, e.g. octocat/hello-world
SECRETSFILE location to read secrets from (default: - (stdin))
Global options:
--argon2-iterations ARGON2-ITERATIONS, -i ARGON2-ITERATIONS
number of argon2 iterations to create corresponding hash secret name [default: 32]
--argon2-length ARGON2-LENGTH, -l ARGON2-LENGTH
length of argon2 hash used in corresponding hash secret name [default: 32]
--argon2-memory ARGON2-MEMORY, -m ARGON2-MEMORY
memory for argon2 to use when creating corresponding hash secret name [default: 65536]
--argon2-parallelism ARGON2-PARALLELISM, -p ARGON2-PARALLELISM
parallelism used when creating argon2 hash [default: 4]
--dry-run, -d indicate only what secrets would be updated; does not update secrets
--droneserver DRONESERVER [env: DRONE_SERVER]
--dronetoken DRONETOKEN [env: DRONE_TOKEN]
--verbose, -v enable verbose logging
--help, -h display this help and exit
--version display version and exit
Usage: drone-secrets-sync org NAMESPACE [SECRETSFILE]
Positional arguments:
NAMESPACE name of organisation to sync secrets for, e.g. octocat
SECRETSFILE location to read secrets from (default: - (stdin))
Global options:
--argon2-iterations ARGON2-ITERATIONS, -i ARGON2-ITERATIONS
number of argon2 iterations to create corresponding hash secret name [default: 32]
--argon2-length ARGON2-LENGTH, -l ARGON2-LENGTH
length of argon2 hash used in corresponding hash secret name [default: 32]
--argon2-memory ARGON2-MEMORY, -m ARGON2-MEMORY
memory for argon2 to use when creating corresponding hash secret name [default: 65536]
--argon2-parallelism ARGON2-PARALLELISM, -p ARGON2-PARALLELISM
parallelism used when creating argon2 hash [default: 4]
--dry-run, -d indicate only what secrets would be updated; does not update secrets
--droneserver DRONESERVER [env: DRONE_SERVER]
--dronetoken DRONETOKEN [env: DRONE_TOKEN]
--verbose, -v enable verbose logging
--help, -h display this help and exit
--version display version and exit
# Compile for GOOS and GOARCH of build machine
make build
# Compile for multiple targets
make build TARGET_BUILDS="linux/amd64 linux/arm64 linux/arm darwin/amd64 darwin/arm64"
To run after building:
./bin/drone-secrets-sync --help
make build-image-and-load
To run after building:
docker run --rm --pull never -e DRONE_SERVER -e DRONE_TOKEN "colin-nolan/drone-secrets-sync:$(make version)" --help
make test
make lint
Requires:
make format
Requires: (see Linting)
To run a Drone CI step manually:
drone exec --pipeline=lint <(drone jsonnet --stream --stdout)
When testing against a Drone CI installation, to clear all secrets on a repository:
repository=octocat/hello-world
drone secret ls --format '{{ .Name }}' "${repository}" \
| xargs -I {} drone secret rm --name {} "${repository}"
Or on an organisation:
namespace=octocat
drone orgsecret ls --format '{{ .Name }}' "${namespace}" \
| xargs -n 1 drone orgsecret rm "${namespace}"
Requires:
- drone-secret-sync can synchronise secrets across multiple orgs/repositories. It is not idempotent though, meaning it will update all secrets, every time it is ran.
GPL v3 (contact for other licencing). Copyright 2023 Colin Nolan.
This work is in no way related to any company that I may work for.