a pre-commit integration that automatically encrypts secrets with sops before commiting
Find a file
2025-12-13 14:31:57 +01:00
k8s-secrets-autoencrypter initial commit 2025-12-13 14:16:44 +01:00
LICENSE add LICENSE 2025-12-13 14:31:57 +01:00
README.md initial commit 2025-12-13 14:16:44 +01:00
setup.sh initial commit 2025-12-13 14:16:44 +01:00

k8s-secrets-autoencrypter

A small CLI tool + pre-commit hook that automatically SOPS-encrypts staged Kubernetes Secret YAML manifests, so you dont accidentally commit plaintext secrets to git.

This repo contains one script:

  • k8s-secrets-autoencrypter — encrypts plaintext Secret manifests in-place and re-stages them.

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). Its easy to forget to encrypt a newly created Secret before committing.

This tool makes it automatic:

  1. Create/edit a Kubernetes Secret YAML
  2. git add it
  3. Run git commit
  4. The hook encrypts the Secret (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$
        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

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).