DEV Community

Cover image for I built a tokenless secrets manager that runs entirely on Git and KMS (No Vault required)
Clef.sh
Clef.sh

Posted on • Edited on

I built a tokenless secrets manager that runs entirely on Git and KMS (No Vault required)

If you've ever had to manage secrets for a production application, you know the pain of the "Secret Zero" problem: How do you securely deliver a secret to a workload without giving it a static .env file or password first?

Today, the industry standard way to solve this is to use HashiCorp Vault or Infisical tied to your cloud's machine identity (like AWS IAM Auth or Kubernetes Service Accounts).

That works beautifully, but the infrastructure cost is massive. You have to run an HA cluster, manage unseal keys, configure storage backends, and maintain a dedicated secrets server just to securely pass an API key.

The alternative is raw Mozilla SOPS + Git, which gives an amazing developer experience but leaves you writing messy custom KMS-decryption bash scripts in your CI pipelines to get those secrets into production.

I wanted the developer experience of Git, but the enterprise security of a tokenless, zero-trust architecture—without running a server. So, I built Clef.

What is Clef?

Clef (https://clef.sh) is an open-source secrets manager. It bridges the gap by treating your Git repository as the authoritative state and your cloud's native IAM as the authentication layer.

Here is how the architecture works from development to production:

1. Local Development (Secrets as Code)

Secrets are encrypted locally using SOPS and Age encryption. You define your service identities and namespaces in a simple clef.yaml manifest. No plaintext is ever written to disk.

# Initialize a new project
clef init

# Set a secret in development
clef set database/development DB_URL "postgres://localhost:5432/myapp"

# Inject secrets directly into your local Node process
clef exec database/development -- node server.js
Enter fullscreen mode Exit fullscreen mode

2. CI/CD (The Pack Phase)

When you merge your code, your CI pipeline runs clef pack. It decrypts only the SOPS files scoped to that specific service, merges them, and creates a lightweight JSON artifact.

3. Solving "Secret Zero" (KMS Envelope Encryption)

This is where the magic happens. To deliver that JSON artifact securely without static credentials, the CI pipeline generates an ephemeral, one-time-use Age key pair.

It encrypts the artifact with the ephemeral key, and then wraps the ephemeral private key using your cloud KMS (AWS or GCP).

4. Production Runtime (The Agent)

A lightweight Clef Agent sidecar runs next to your production app. It doesn't need a password or a .env file. Using the machine's native cloud IAM role (like an AWS EC2 or ECS Task Role), the agent simply asks KMS to unwrap the ephemeral key.

It then decrypts the artifact and serves the secrets to your app via a localhost API (127.0.0.1:7779).

// Your app code just fetches from localhost
const secrets = await fetch("http://127.0.0.1:7779/v1/secrets", {
  headers: { Authorization: "Bearer <local-token>" }
}).then(r => r.json());
Enter fullscreen mode Exit fullscreen mode

The Honest Trade-off

Security is always a trade-off. By eliminating the central server, your Git repository effectively becomes your access control list. You are trading infrastructure complexity for strict GitOps process discipline. If an insider can merge a PR that adds their personal public key to your clef.yaml manifest, they gain access to your secrets. To use Clef safely, you must enforce strict branch protection, require CODEOWNERS reviews on your security manifests, and run isolated CI pipelines.

Properly securing Git + CI is easier than securing Git + CI + Vault, but you have to treat your repo with the seriousness of a vault.

Try it out

Clef is fully open-source under the MIT license.

I wrote a detailed whitepaper breaking down the architecture, the KMS envelope math, and the threat model. I’d love for the DEV community to tear it apart, try out the CLI, and let me know what you think!

Let me know in the comments: For those of you running Vault today, is the operational overhead worth having a centralized policy engine, or would you trade it for a Git-native ACL like this?


Top comments (2)

Collapse
 
mfc_keibisoft profile image
Marius-Florin Cristian

The idea is cool I did saw people use mozila SOPS out there, anything that makes their life easier I think its cool!

I think it becomes hard to manage rotating secrets as people come and go, you now need to revoke public keys also. what I found painful is the actual discipline and control part, especially as orgs go in the happy path from 3 people to 50 people to 200 people.

what works for my use case is to just use the default tools in azure/aws/gcp, have everything codified in terraform, and let the apps pull secrets at runtime; and have playbooks for rotating secrets.

but me not specific devops person. I just have the ghost pain from it :D

Collapse
 
clef_3b283a3ce628 profile image
Clef.sh

Haha, I completely understand that "ghost pain"! Managing and rotating public keys when people leave is exactly why vanilla SOPS gets painful as a team grows from 3 to 50 people.

You're spot on that doing this manually is tough. To fix this, Clef uses a namespace-by-environment matrix. Instead of one giant list of public keys for the whole repo, you scope them.

You can set it up so your development environment uses one set of age keys, and your production environment uses a completely different age key (or even an AWS/GCP KMS key). This way, if a developer leaves, they likely never had the production key in the first place, so you don't have to rotate your prod secrets or touch those files. It keeps the blast radius small.

Honestly, native cloud tools + Terraform is a rock-solid way to handle it. For teams that have that dialed in, it works beautifully. When I was building Clef I was trying to give atomic deployments out of the box. Since everything is in git, code and secrets, the sync part becomes a static analysis problem. The application code and the secrets it expects are versioned in the exact same Git commit, which just removes the need to orchestrate state across a Terraform pipeline and an app deployment pipeline to keep them in sync.

Thanks for checking it out and for the feedback!