a pre-commit integration that automatically encrypts secrets with sops before commiting
Find a file
2026-05-20 15:38:04 +00:00
k8s-secrets-autoencrypter add dotenv support 2026-05-20 15:38:04 +00:00
LICENSE add LICENSE 2025-12-13 14:31:57 +01:00
README.md add dotenv support 2026-05-20 15:38:04 +00:00
setup.sh add dotenv support 2026-05-20 15:38:04 +00:00
sops-decrypt-env add dotenv support 2026-05-20 15:38:04 +00:00

k8s-secrets-autoencrypter

A small CLI tool + pre-commit hook that automatically SOPS-encrypts staged Kubernetes Secret YAML manifests and .env files, so you don't accidentally commit plaintext secrets to git.

This repo contains two scripts:

  • k8s-secrets-autoencrypter — encrypts plaintext Secret manifests and .env files in-place and re-stages them.
  • sops-decrypt-env — decrypts .env files in-place after git pull / git checkout. Installed as post-checkout and post-merge hooks.

It intentionally does not handle private keys. For encryption, SOPS only needs the recipient public key (e.g. age recipient), which should be configured via .sops.yaml (recommended) or via CLI flags.


Why

With Flux GitOps, secrets live in the repo (encrypted). It's easy to forget to encrypt a newly created Secret before committing.

This tool makes it automatic:

  1. Create/edit a Kubernetes Secret YAML or .env
  2. git add it
  3. Run git commit
  4. The hook encrypts the file (if needed) and re-stages it

Requirements

Local tools:

  • sops
  • yq (mikefarah/yq v4 recommended)
  • git
  • pre-commit (recommended; needed if you want automatic hook execution)

Installation

Clone the repo and run:

git clone <repo-url>
cd k8s-secrets-autoencrypter
./setup.sh

The setup script will:

  • ensure the script is executable
  • let you choose symlink vs copy
  • let you choose install target:
    • ~/.local/bin (recommended; no sudo)
    • /usr/local/bin (system-wide)
  • check for dependencies and warn if missing

Make sure the chosen directory is in your $PATH.


How it works

For each candidate YAML file, k8s-secrets-autoencrypter:

  • checks kind: Secret
  • checks there is data: or stringData:
  • checks the file is not already SOPS-encrypted (no top-level sops: key)
  • runs sops -e -i <file>
  • runs git add <file>

The script is idempotent: already-encrypted secrets are safely skipped.


To encrypt new files, SOPS must know which recipients to encrypt for. The best way is a repository-local .sops.yaml that contains only public recipients.

Example .sops.yaml:

creation_rules:
  - path_regex: .*\.ya?ml
    encrypted_regex: '^(data|stringData)$'
    age:
      - age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

This also limits encryption to data and stringData, keeping manifests readable.

If you dont want .sops.yaml, you must pass recipients on the command line (less ergonomic).


Pre-commit integration

In each Flux/Kubernetes repo where you want auto-encryption, add .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: k8s-secrets-autoencrypter
        name: Auto-encrypt Kubernetes Secrets with SOPS
        entry: k8s-secrets-autoencrypter
        language: system
        files: \.ya?ml$|\.env$
        stages: [pre-commit]

Then install hooks:

pre-commit install

Test without committing:

pre-commit run -v k8s-secrets-autoencrypter

Test against all files:

pre-commit run -v k8s-secrets-autoencrypter --all-files

Dotenv (.env) support

The tool can also encrypt .env files in-place using SOPS dotenv format. Variable names remain visible; only values are encrypted. The file stays as valid dotenv.

Auto-decrypt after pull

The sops-decrypt-env script decrypts .env in-place if a private key is available. Install it as git hooks:

# Manual install
ln -sf /path/to/sops-decrypt-env .git/hooks/post-checkout
ln -sf /path/to/sops-decrypt-env .git/hooks/post-merge

Or use setup.sh which offers to install them interactively.

If no private key is available (e.g., cloned on a machine without the key), the script exits silently and .env stays encrypted.

.sops.yaml for dotenv

Add a creation rule for .env files:

creation_rules:
  - path_regex: \.ya?ml$
    encrypted_regex: '^(data|stringData)$'
    age: >-
      age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  - path_regex: \.env$
    age: >-
      age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Note: for dotenv, encrypted_regex is not used — SOPS encrypts all values.


Troubleshooting

Nothing gets encrypted

Verify:

  • the file is staged: git add path/to/secret.yaml
  • kind: Secret is present
  • data: or stringData: exists
  • its not already encrypted (file contains sops: at top level)
  • SOPS has recipients configured (via .sops.yaml or CLI flags)

“No keys found” / “Missing recipients”

For new (unencrypted) files, SOPS needs recipients. Add .sops.yaml with your age recipient(s).