{"id":51016495,"url":"https://github.com/idestis/kerf","last_synced_at":"2026-06-21T11:02:48.558Z","repository":{"id":362045619,"uuid":"1252531830","full_name":"idestis/kerf","owner":"idestis","description":"Diff-aware secrets management tool","archived":false,"fork":false,"pushed_at":"2026-06-02T10:07:11.000Z","size":1675,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-02T11:25:00.371Z","etag":null,"topics":["aws","azure","devops","gcp","secret-distribution","secret-management","secrets"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/idestis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-28T16:02:38.000Z","updated_at":"2026-06-02T10:07:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/idestis/kerf","commit_stats":null,"previous_names":["idestis/kerf"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/idestis/kerf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idestis%2Fkerf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idestis%2Fkerf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idestis%2Fkerf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idestis%2Fkerf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/idestis","download_url":"https://codeload.github.com/idestis/kerf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idestis%2Fkerf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34607126,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","azure","devops","gcp","secret-distribution","secret-management","secrets"],"created_at":"2026-06-21T11:02:47.733Z","updated_at":"2026-06-21T11:02:48.552Z","avatar_url":"https://github.com/idestis.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kerf\n\n\u003e Diff-aware, KMS-first encryption for structured secret files.\n\n[![Documentation](https://img.shields.io/badge/docs-idestis.github.io%2Fkerf-2563eb)](https://idestis.github.io/kerf/)\n\nA kerf is the narrow cut a saw makes through wood — only the material along the blade's path is removed, the rest is untouched. `kerf` encrypts the same way: edit one value in a YAML/JSON/TOML/ENV/INI file, and only that value's ciphertext changes in git.\n\nTools like SOPS reroll every nonce on every encrypt, so changing one secret produces a diff that touches every encrypted line. That makes code review of secret changes effectively impossible. `kerf` fixes this with a single invariant: **if a value's plaintext is unchanged, its on-disk ciphertext, nonce, and authentication tag are byte-identical to the previous version.**\n\nFull documentation — install, CLI reference, and per-provider guides — is at **[idestis.github.io/kerf](https://idestis.github.io/kerf/)**. See [`SPEC.md`](SPEC.md) for the format and algorithm, and [`CLAUDE.md`](CLAUDE.md) for contributor rules.\n\n## Status\n\n**v0.1.0 — pre-alpha.** Working end-to-end: diff-aware encrypt/decrypt with the byte-identity rule, file MAC, five formats (YAML / JSON / TOML / ENV / INI), and recipients for **age**, **AWS KMS**, **GCP Cloud KMS**, and **Azure Key Vault**. AWS and GCP are verified against local emulators; Azure's production path follows the documented SDK usage but isn't emulator-verified yet (see [Testing](#testing)). Not yet audited — don't protect real secrets with it until it stabilises.\n\nRecipient backends are cargo features (`aws-kms` on by default; `gcp-kms`, `azure-kv` opt-in) so you only build the cloud SDKs you use.\n\n## Roadmap\n\nWhat's done and what's next. The full porcelain surface is implemented: `init`, `encrypt`, `decrypt`, `verify`, `keygen`, `edit`, `view`, `diff`, `set`, `unset`, `exec`, `rotate`, `keys`, plus the plumbing set (`metadata`, `recipients`, `mac --verify`, `path-encrypted`).\n\n### Core / crypto\n- [x] Diff-aware encrypt with the byte-identity rule\n- [x] File MAC (HMAC-SHA256, AES-GCM-wrapped, AAD `__kerf_mac__`)\n- [x] AES-256-GCM per value, AAD = dotted path\n- [x] Fuzz targets for the file, envelope, and recipient-block parsers (`cargo-fuzz`)\n\n### Formats\n- [x] YAML, JSON, TOML, ENV (dotenv)\n- [x] Comment / whitespace preservation on round-trip (YAML, TOML, ENV, INI; JSON has no comments)\n- [x] INI\n\n### Recipients\n- [x] age (local, no network)\n- [x] AWS KMS — emulator-verified (floci)\n- [x] GCP Cloud KMS — emulator-verified (fake-cloud-kms)\n- [x] Azure Key Vault (RSA-OAEP-256 wrap/unwrap)\n- [ ] Verify Azure end-to-end against an emulator with the Keys API\n\n### CLI commands\n- [x] `kerf init` — write `.kerf.yaml` creation rules\n- [x] `kerf verify` — MAC + AAD check, no plaintext output (exit codes per SPEC § 7.6)\n- [x] `kerf rotate` — fresh DEK, re-encrypt every value, re-wrap\n- [x] `kerf edit` — decrypt → `$EDITOR` → minimal-diff re-encrypt, scratch wiped on exit\n- [x] `kerf exec -- \u003ccmd\u003e` — decrypt into child env, no plaintext on disk\n- [x] `kerf set` / `kerf unset` — scripted single-value mutations (`set` reads from `--stdin`)\n- [x] `kerf view` — read-only inspection (whole file or one `--path`)\n- [x] `kerf diff` — plaintext diff of two encrypted files (redacted unless `--show-values`)\n- [x] `kerf keys add` / `remove` / `list` — recipient management without DEK rotation\n- [x] Plumbing commands (`recipients`, `metadata`, `mac --verify`, `path-encrypted`)\n\n### Migration \u0026 distribution\n- [ ] `kerf import-sops` — read SOPS-format files and re-encrypt into kerf format\n- [ ] Security audit before any 1.0 / \"safe for real secrets\" claim\n\n## Install\n\n### GitHub Releases\n\nDownload the binary for your platform from the [Releases](https://github.com/idestis/kerf/releases) page. Verify the checksum against `SHA256SUMS` published alongside the archives.\n\n```\ntar -xzf kerf-v0.1.0-aarch64-apple-darwin.tar.gz\nsudo mv kerf-v0.1.0-aarch64-apple-darwin/kerf /usr/local/bin/\nkerf --version\n```\n\nSupported platforms:\n\n| OS | Architecture |\n|---|---|\n| Linux | x86_64, aarch64 |\n| macOS | arm64, x86_64 |\n| Windows | x86_64 |\n\n### From source\n\n```\ncargo install --git https://github.com/idestis/kerf kerf-cli\n```\n\nRequires Rust 1.96 or newer.\n\n## Quick example\n\n```bash\n# Initialise config in the repo root\nkerf init --recipient 'aws-kms:arn:aws:kms:us-east-1:111:key/prod-secrets'\n\n# Encrypt a plaintext file\nkerf encrypt secrets/prod.yaml\n\n# Decrypt to stdout\nkerf decrypt secrets/prod.kerf.yaml\n\n# Edit in $EDITOR — minimal-diff re-encrypt on save\nkerf edit secrets/prod.kerf.yaml\n\n# Verify integrity (MAC + AAD) without producing plaintext\nkerf verify secrets/prod.kerf.yaml\n```\n\nEditing one value touches one line of ciphertext (plus the one-line file MAC, which covers every encrypted leaf) — that minimal, reviewable diff is the entire point.\n\n## See it in git\n\nThe [`examples/`](examples/) directory is a worked demonstration in real git\nhistory. Each step is its own commit, so you can click the diff and see the\nbyte-identity rule hold:\n\n1. **[Encrypt](https://github.com/idestis/kerf/commit/37e38e0feea74c8f0223b71d3543cdcae96d4b27)** — six lines of plaintext config become `config.kerf.yaml`; only secret-shaped keys turn into `ENC[...]`.\n2. **[Change one secret](https://github.com/idestis/kerf/commit/e716e3a936ef6fdd96ee8ec5056a14013d9b129d)** — rotating `database.password` is a two-line diff: the value and the file MAC. `api.token` is byte-identical.\n3. **[Add a new secret](https://github.com/idestis/kerf/commit/25082ab5c7e3177d16487ff29afed2cc3427e425)** — adding `cache.password` adds two lines and updates the MAC; every pre-existing ciphertext line is unchanged.\n\nCompare that to SOPS, where any encrypt rerolls every nonce and the diff\ntouches every encrypted line. Run [`examples/reproduce.sh`](examples/reproduce.sh)\nto regenerate the whole flow locally with a throwaway key.\n\n## Development\n\nCommon tasks are exposed via [Taskfile](https://taskfile.dev):\n\n```bash\ntask            # list everything\ntask test       # unit + offline tests (no network, safe anywhere — CI runs this)\ntask lint       # fmt --check + clippy + cargo-deny\ntask build      # release binary at target/release/kerf\ntask release    # bump version, write CHANGELOG, push tag (CI builds binaries)\n```\n\n### Testing\n\nThere are two tiers, split so the default suite never needs the network:\n\n| Command | What it runs | Needs |\n|---|---|---|\n| `task test` | All crypto, format, envelope, MAC, and KMS request-shape tests. KMS end-to-end tests are `#[ignore]`d and skipped here. | nothing |\n| `task test:integration` | Spins up local KMS emulators in Docker, runs the `#[ignore]`d KMS end-to-end tests against the real wire (no mocks — per [`CLAUDE.md`](CLAUDE.md)), then tears the emulators back down. | Docker |\n\n`task test` is what CI runs on every PR — fully offline, runs anywhere.\n\n`task test:integration` is **batteries-included**: it brings the emulators up\n(`docker compose -f docker-compose.test.yml`), waits for them, runs the tests,\nand tears everything down afterwards — even if the tests fail. Each test\nself-provisions its own KMS key (AWS via `kms:CreateKey`, GCP via\n`CreateKeyRing`/`CreateCryptoKey`), so there's nothing to seed. One command:\n\n```bash\ntask test:integration\n```\n\nEmulators used: [floci](https://github.com/floci-io/floci) for AWS on `:4566`\n(free, MIT, no auth token — unlike recent LocalStack, which gates KMS behind a\npaid license), and `fake-cloud-kms` for GCP on `:9010` (floci-gcp has no KMS;\nthe image is amd64-only and runs under emulation on Apple Silicon). Azure's\nbackend is implemented but not in the auto-managed stack yet — its Keys API\nisn't cleanly emulator-testable (floci-az confirms only Secrets; lowkey-vault\nneeds TLS-trust config), so `tests/azure_kv_local.rs` is gated and documents\nmanual setup.\n\nFor a persistent / already-running setup, drive the pieces yourself:\n\n```bash\ntask infra:up                 # start emulators\neval \"$(task infra:env)\"      # export endpoint + credential env vars\ntask test:integration:manual  # run against the running infra (no up/down)\ntask infra:down               # stop + remove\n```\n\nConventional Commits drive both the changelog and the version bump:\n\n```\nfeat(cli): add `kerf rotate --reason` flag\nfix(core): preserve YAML quoting style across encrypt round-trip\nsec(kms): pin aws-sdk-kms to a version with the latest CVE fixes\n```\n\nUse `sec:` for any security-relevant change — it makes the audit trail searchable.\n\n## License\n\nApache-2.0. See [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidestis%2Fkerf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fidestis%2Fkerf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidestis%2Fkerf/lists"}