No OAuth · No Vault agents · No local secret files

Secrets live remotely.
Your app gets them at runtime.

keyctl pulls encrypted secrets from Azure Key Vault into your process's environment — without storing them on disk or in `.env` files. One small binary, one YAML file.

# commit this (no real values here)
$ cat keyctl.yaml
project: payments-service
secrets:
  DATABASE_URL: database-url
  STRIPE_KEY:   stripe-secret-key

# just run it — secrets inject automatically
$ keyctl run -- node server.js
✓ fetched 2 secrets for payments-service
Server running on :3000

How it works

Four components, zero persisted secrets locally.

1

Create a project

An admin runs keyctl project create payments-service. The API generates a high-entropy setup key and stores only its Argon2id hash in Azure Key Vault.

2

Login once

Each team member runs keyctl login --project payments-service --key <key>. The key is saved to ~/.keyctl/credentials (chmod 600) — nothing else lives locally.

3

Commit keyctl.yaml

A tiny config file in your repo declares which env vars map to which Key Vault secret keys. No values, just names — safe to commit.

4

Run with secrets

keyctl run -- your-command fetches all declared secrets over HTTPS, injects them as env vars into the child process only, then discards them. Secrets never touch disk.

Developer / CI
keyctl run
CLI binary
HTTPS + setup key
Azure Functions API
Managed Identity
Azure Key Vault

Security model

🔐

Argon2id key hashing

Setup keys are never stored in plaintext. The API stores only Argon2id hashes; even if Key Vault is read, no plaintext keys are exposed.

🚫

Nothing on disk

Secrets are fetched fresh for each keyctl run invocation and injected only into the child process's environment. No .env files, no temp files.

🔄

Key rotation

Run keyctl project rotate-key to generate a new setup key and immediately revoke the old one. Distribute the new key to your team.

🛡️

Managed Identity

The API never stores Azure credentials. It uses a system-assigned Managed Identity to talk to Key Vault — no secrets in app settings for the vault itself.

📋

Audit trail

Every secret fetch, set, and delete is visible in Azure App Insights and Key Vault audit logs.

🔒

HTTPS only

TLS 1.2+ enforced everywhere. The Function App is configured with httpsOnly: true and FTPS disabled.

Quick start

1 · Install the binary
# macOS / Linux
curl -fsSL https://orange-sand-0b337180f.7.azurestaticapps.net/install.sh | sh

# or download manually → see Download section
2 · Login to your project (once)
keyctl login \
  --project payments-service \
  --key <setup-key-from-admin> \
  --api-url https://keyctl-api.azurewebsites.net
3 · Run your app
# Instead of: node server.js
keyctl run -- node server.js

# Works with any runtime
keyctl run -- python manage.py runserver
keyctl run -- go run ./cmd/server
1 · Deploy the API to Azure
# Create resource group
az group create --name keyctl-rg --location eastus

# Deploy Bicep (generates admin token automatically)
ADMIN_TOKEN=$(openssl rand -hex 32)
az deployment group create \
  --resource-group keyctl-rg \
  --template-file infra/main.bicep \
  --parameters appName=keyctl adminToken=$ADMIN_TOKEN
2 · Build & publish the API binary
GOOS=linux GOARCH=amd64 go build -o api/keyctl-api ./api
cd api && func azure functionapp publish keyctl-api --no-build
3 · Create a project
KEYCTL_ADMIN_TOKEN=$ADMIN_TOKEN \
  keyctl project create payments-service \
  --api-url https://keyctl-api.azurewebsites.net

# Output:
Project "payments-service" created.
  Setup key (admin): 3f8a2c...
This key is shown only once. Save it now.
4 · Store secrets
keyctl secret set database-url "postgres://..." --project payments-service
keyctl secret set stripe-secret-key "sk_live_..." --project payments-service
5 · Scaffold the config file & commit it
keyctl init --project payments-service
# Edit keyctl.yaml to map your env vars
git add keyctl.yaml && git commit -m "chore: add keyctl config"
GitHub Actions — inject secrets into a build step
# .github/workflows/test.yml
- name: Install keyctl
  run: curl -fsSL https://orange-sand-0b337180f.7.azurestaticapps.net/install.sh | sh

- name: Run tests with secrets
  env:
    KEYCTL_KEY: ${{ secrets.KEYCTL_SETUP_KEY }}
    KEYCTL_API_URL: https://keyctl-api.azurewebsites.net
  run: keyctl run -- go test ./...

Store only the KEYCTL_SETUP_KEY in GitHub Secrets — not the individual app secrets.

Download

Pre-built binaries for every platform, served directly from this site. See checksums.txt to verify.

One-line install (macOS / Linux)
curl -fsSL https://orange-sand-0b337180f.7.azurestaticapps.net/install.sh | sh