SecretShift is a CLI tool for migrating and syncing secrets and environment variables between providers. Move secrets from GitHub, GitLab, HashiCorp Vault, etcd, Kubernetes, or local files to any of those destinations.
See CONTEXT.md for domain terminology and conventions.
- 7 provider types: GitHub, GitLab, Vault, etcd, Kubernetes, local file (source + destination)
- Flexible processing: Filter by name regex or type, add prefixes/suffixes to secret names
- Multiple run modes: One-shot, periodic interval, cron-scheduled, or long-running server
- Server mode: HTTP health endpoints (
/healthz,/readyz,/status) for Kubernetes deployments - Dry-run support: Preview changes without writing to the destination
- Encrypted file I/O: Optional AES-256-GCM encryption for file sources and destinations
- Conflict handling: Replace, skip, or report existing secrets at the destination
- Per-step environment variables: Separate
SECRET_SHIFT_SRC_*andSECRET_SHIFT_DST_*for source and destination credentials - Helm chart: Deploy to Kubernetes as a Deployment (periodic/server) or CronJob (one-shot)
brew tap PapaDanielVi/tap
brew install secret-shiftgo install github.com/PapaDanielVi/secret-shift@latestgo build -o secret-shift .Download the binary for your platform from the releases page.
For automated installation and updates, use the provided scripts:
Linux (Auto-detects package manager):
curl -Lo install-linux.sh https://raw.githubusercontent.com/PapaDanielVi/secret-shift/main/scripts/install-linux.sh
chmod +x install-linux.sh
sudo ./install-linux.shThe script detects and uses:
dnf/yum/zypper: RPM packagesapt-get: DEB packagesapk: APK packages (Alpine)pacman: Arch packages- Falls back to tarball if no package manager is found
Windows (PowerShell):
curl -Uri https://raw.githubusercontent.com/PapaDanielVi/secret-shift/main/scripts/install-windows.ps1 -OutFile install-windows.ps1
.\install-windows.ps1Both scripts:
- Fetch and install the latest release automatically
- Remove existing installations before upgrading
- Install to standard system locations
- Add the binary to PATH (Windows only)
Create a secret-shift.json:
{
"source": {
"type": "github",
"repo": "owner/repo",
"token": "ghp_xxx"
},
"process": {
"add_prefix": "PROD_",
"include_regex": "^DB_"
},
"destination": {
"type": "vault",
"vault_address": "https://vault.example.com",
"vault_path": "myapp/config",
"token": "hvs_xxx"
}
}Run the sync:
secret-shift syncAll config keys can be set via environment variables. Source fields use the SECRET_SHIFT_SRC_ prefix and destination fields use SECRET_SHIFT_DST_:
SECRET_SHIFT_SRC_TYPE=github \
SECRET_SHIFT_SRC_GITHUB_TOKEN=ghp_xxx \
SECRET_SHIFT_DST_TYPE=file \
SECRET_SHIFT_DST_PATH=./secrets.json \
secret-shift syncThis per-step convention means you can use different credentials for source and destination, e.g. SECRET_SHIFT_SRC_GITHUB_TOKEN and SECRET_SHIFT_DST_GITHUB_TOKEN.
Execute a sync pipeline.
| Flag | Default | Description |
|---|---|---|
-c, --config |
./secret-shift.json |
Path to config file |
--periodically |
false |
Run in a loop |
--frequency |
5m |
Interval between syncs (e.g. 1m, 1h) |
--cron |
Cron expression (e.g. */5 * * * *) |
|
--dry-run |
false |
Simulate sync without writing to destination |
--server |
false |
Start HTTP server with health endpoints + periodic sync |
--health-port |
8080 |
Port for health HTTP server |
Print the current version.
| Source | What it reads |
|---|---|
| github | GitHub Actions secrets + environment variables |
| gitlab | GitLab project-level CI/CD variables |
| vault | HashiCorp Vault KV v2 secrets |
| etcd | etcd key-value pairs under a prefix |
| kubernetes | K8s Secrets + ConfigMaps (by name, label, or namespace) |
| file | Local JSON or YAML key-value file (optionally encrypted) |
| Destination | What it writes | Notes |
|---|---|---|
| file | Local JSON or YAML file | Optional AES-256-GCM encryption |
| github | GitHub Actions secrets + environment variables | RSA-OAEP encrypted |
| gitlab | GitLab project-level CI/CD variables | |
| vault | HashiCorp Vault KV v2 | Single KV entry |
| etcd | etcd key-value store | One key per secret |
| kubernetes | K8s Secrets + ConfigMaps | Routes by secret type |
When running with --server, secret-shift starts an HTTP server that exposes:
| Endpoint | Description |
|---|---|
GET /healthz |
Liveness probe — always returns {"status":"ok"} |
GET /readyz |
Readiness probe — returns ready after first successful sync, not_ready if no sync has completed or the last sync failed |
GET /status |
Detailed status including sync count, error count, last sync time |
In server mode, syncs run periodically in the background (default every 5 minutes).
Set the url field to your GitHub Enterprise API endpoint:
{
"source": {
"type": "github",
"repo": "owner/repo",
"url": "https://git.mycompany.com/api/v3",
"token": "ghp_xxx"
}
}Set the url field to your GitLab instance:
{
"source": {
"type": "gitlab",
"project_id": "123",
"url": "https://gitlab.mycompany.com",
"token": "glpat-xxx"
}
}The processor runs between source and destination:
- Type filtering:
include_types/exclude_typesfilter by"env"or"secret" - Name filtering:
include_regex/exclude_regexfilter by secret name - Name transformation:
add_prefixandadd_suffixmodify secret names
For destinations that support it (GitHub, GitLab):
| Strategy | Behavior |
|---|---|
replace |
Overwrite existing secrets (default) |
skip |
Silently skip existing secrets |
report |
Print conflict info and skip |
The config system supports separate environment variables for source and destination:
| Variable Pattern | Example |
|---|---|
SECRET_SHIFT_SRC_TYPE |
Source provider type |
SECRET_SHIFT_SRC_GITHUB_TOKEN |
GitHub token for source |
SECRET_SHIFT_SRC_GITLAB_TOKEN |
GitLab token for source |
SECRET_SHIFT_SRC_VAULT_TOKEN |
Vault token for source |
SECRET_SHIFT_SRC_PATH |
File path for file source |
SECRET_SHIFT_SRC_KUBE_NAMESPACE |
K8s namespace for source |
SECRET_SHIFT_DST_TYPE |
Destination provider type |
SECRET_SHIFT_DST_GITHUB_TOKEN |
GitHub token for destination |
SECRET_SHIFT_DST_GITLAB_TOKEN |
GitLab token for destination |
SECRET_SHIFT_DST_VAULT_TOKEN |
Vault token for destination |
SECRET_SHIFT_DST_PATH |
File path for file destination |
SECRET_SHIFT_DST_KUBE_NAMESPACE |
K8s namespace for destination |
SECRET_SHIFT_DRY_RUN |
Enable dry-run mode |
Token resolution order: direct config value → token_env field → SECRET_SHIFT_SRC/DST_<PROVIDER>_TOKEN env var.
See the examples/ directory for ready-to-use configurations for every source→destination combination (49 total), each with a config.json and README.md.
A Helm chart is available at charts/secret-shift/. It supports three modes:
| Mode | Description | Kubernetes Resource |
|---|---|---|
server |
HTTP health endpoints + periodic sync | Deployment |
periodic |
Periodic sync loop | Deployment |
one-shot |
Single sync run on a schedule | CronJob |
helm install secret-shift charts/secret-shift/ --set mode=serversecret-shift/
cmd/ # CLI commands (root, sync, version)
internal/
config/ # Config loading, validation, env resolution
pipeline/ # Sync pipeline (source → process → destination)
provider/ # Provider interfaces + registry
github/ # GitHub source + destination
gitlab/ # GitLab source + destination
vault/ # HashiCorp Vault source + destination
etcd/ # etcd source + destination
kubernetes/ # Kubernetes source + destination
file/ # File source + destination (JSON/YAML, encrypted)
server/ # HTTP health server (/healthz, /readyz, /status)
charts/secret-shift/ # Helm chart for Kubernetes deployment
examples/ # 49 src→dst example configurations
- CLI: Cobra + Viper
- APIs: go-github, GitLab client, Vault API, etcd client, Kubernetes client-go
- Scheduling: cron
- HTTP Server: Standard library
net/http
MIT