GitOps Reverser is a Kubernetes operator that turns live API activity into clean, versioned YAML in Git. It results in a folder with YAML files that can be deployed to any cluster. The commit history is your perfect audit trail.
Want to see the evidence? You can find the commit in ConfigButler/example-audit.
Today teams have to choose between workflows:
- Pure GitOps: safe and auditable, but unfriendly to non‑git users.
- API‑first: fast and interactive, but databases don't come (by default) with a way to deploy or test high-risk changesets.
Reverse GitOps gives you both: the interactivity of the Kubernetes API with Git's safety and traceability. Users, CLIs, and automations talk to a lightweight control plane; the operator immediately reflects desired state to Git.
- Capture: Admission webhook receives Kubernetes API requests.
- Sanitize: Remove status and server‑managed fields; format as clean YAML.
- Queue: Buffer events to handle spikes reliably.
- Commit: Annotate with user, operation, namespace, timestamp; commit to Git.
- Push: It's now in your git repo.
🚨 This is early stage software. CRDs and behavior may change; not recommended for production yet. Feedback and contributions are very welcome!
Current limitation: GitOps Reverser must run as a single pod (replicas=1). Multi-pod/HA operation is not supported yet.
I have been thinking about the idea behind GitOps Reverser for several years (I've given up my fulltime job to work on it). Some of the hardest parts, especially writing to Git efficiently and safely under load, were designed and implemented manually. The rest is vibe coded, and needs more refinement before I would run it in production.
The operator itself is fully deterministic and does not use AI or heuristics at runtime. Given the same inputs, it produces the same Git output.
Feedback, issues, and pull requests are very welcome!
- Signed git commits
- Full HA support by introducing Valkey
- More refined behavior in edge cases (especially with newly added CRDs)
- Migrate to the Kubernetes audit webhook to replace the watcher/webhook combination; see
docs/past/audit-webhook-experimental-design.md.
Prerequisites:
- A Kubernetes cluster with kubectl configured
- cert-manager to create the webhook certificates (run
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.1/cert-manager.yaml) - A test git repository with write access
1. Install GitOps Reverser:
kubectl apply -f https://github.com/ConfigButler/gitops-reverser/releases/latest/download/install.yaml2. Set up Git credentials:
Create an SSH key and add it to your Git provider (GitHub, GitLab, Gitea):
ssh-keygen -t ed25519 -C "gitops-reverser@cluster" -f /tmp/gitops-reverser-key -N ""
# Add /tmp/gitops-reverser-key.pub to your Git provider as a deploy keyCreate a Kubernetes Secret with the private key:
kubectl create secret generic git-creds \
--from-file=ssh-privatekey=/tmp/gitops-reverser-key \
--from-literal=known_hosts="$(ssh-keyscan github.com)" \
--dry-run=client -o yaml | kubectl apply -f -See docs/GITHUB_SETUP_GUIDE.md for detailed setup instructions.
3. Configure what to reconcile:
Reconciliation sources and targets are configured by three types of custom resources. Create these to start reconciling ConfigMaps:
# NOTE: Edit the line with YOUR_USERNAME to match your repository
cat <<EOF | kubectl apply -f -
apiVersion: configbutler.ai/v1alpha1
kind: GitProvider
metadata:
name: your-repo
spec:
url: "git@github.com:YOUR_USERNAME/my-k8s-audit.git"
allowedBranches: ["*"]
secretRef:
name: git-creds
push:
interval: "5s"
maxCommits: 10
EOFCheck the status to see if it's able to connect: kubectl get gitprovider your-repo
cat <<EOF | kubectl apply -f -
apiVersion: configbutler.ai/v1alpha1
kind: GitTarget
metadata:
name: to-folder-live-cluster
spec:
providerRef:
name: your-repo
branch: test-gitops-reverser
path: live-cluster
encryption:
provider: sops
age:
enabled: true
recipients:
extractFromSecret: true
generateWhenMissing: true
secretRef:
name: sops-age-key
---
apiVersion: configbutler.ai/v1alpha1
kind: WatchRule
metadata:
name: only-configmaps
spec:
targetRef:
name: to-folder-live-cluster
rules:
- operations: [CREATE, UPDATE, DELETE]
apiGroups: [""]
apiVersions: ["v1"]
resources: [configmaps]
EOFWhen age.recipients.generateWhenMissing: true is enabled, GitOps Reverser can create the encryption key Secret
automatically.
Back up the generated *.agekey entry immediately and securely.
If you lose that private key, existing encrypted *.sops.yaml files are unrecoverable.
After confirming backup, remove the warning annotation:
kubectl annotate secret sops-age-key -n default configbutler.ai/backup-warning-
4. Test it:
# Create a test ConfigMap
kubectl create configmap test-config --from-literal=key=value -n default
# Check your Git repository - you should see a new commit with the ConfigMap YAMLFor cluster-wide resources (nodes, CRDs, etc.) or watching multiple namespaces, use
ClusterWatchRule. More examples in config/samples/.
Avoid infinite loops: Do not point GitOps (Argo CD/Flux) and GitOps Reverser at the same resources in fully automated mode. Recommended patterns:
- Audit (capture changes, no enforcement)
- Human‑in‑the‑loop (hotfix in cluster, capture to Git, review/merge)
- Drift detection (use commits as alert inputs)
- Hybrid (traditional GitOps for infra; Reverser for app/config changes)
- GitOps Reverser currently supports only a single controller pod (no multi-pod/HA yet).
Secretresources (core/v1,secrets) are written via the same pipeline, but sensitive values are expected to be encrypted before commit.- Configure encryption via
--sops-binary-pathand optional--sops-config-path. - The container image ships with
/usr/local/bin/sops. - Per-path
.sops.yamlfiles are bootstrapped in the target repo for SOPS-based secret encryption. - If Secret encryption fails, Secret writes are rejected (no plaintext fallback).
GitTarget.spec.encryption.age.recipients.generateWhenMissing: truecan auto-generate a date-based*.agekeyin the referenced encryption Secret when no*.agekeyentry exists.- Generated Secret data contains one
<date>.agekey(AGE-SECRET-KEY-...). - Generated Secret annotation
configbutler.ai/age-recipientstores the public age recipient. - Generated Secret annotation
configbutler.ai/backup-warning: REMOVE_AFTER_BACKUPis set by default. - While
configbutler.ai/backup-warningremains, gitops-reverser logs a recurring high-visibility backup warning during periodic reconciliation.
- Generated Secret data contains one
- WARNING: backup generated private keys immediately and securely. Losing the key means existing encrypted
*.sops.yamlfiles cannot be decrypted. - After backup, remove the warning annotation:
kubectl annotate secret <your-encryption-secret> -n <namespace> configbutler.ai/backup-warning-
- Configure encryption via
- Avoid multiple GitProvider configurations pointing at the same repo to prevent queue collisions.
- Queue collisions are possible when multiple configs target the same repository (so don't do that).
| Tool | How it Works | Key Differences |
|---|---|---|
| RichardoC/kube-audit-rest | An admission webhook that receives audit events and exposes them over a REST API. | Action vs. Transport: kube-audit-rest is a transport layer. GitOps Reverser is an action layer that consumes the event and commits it to Git. |
| robusta-dev/robusta | A broad observability and automation platform. | Focused Tool vs. Broad Platform: Robusta is a large platform. GitOps Reverser is a small, single-purpose utility focused on simplicity and low overhead. |
| bpineau/katafygio | Periodically scans the cluster and dumps all resources to a Git repository. | Event-Driven vs. Snapshot: Katafygio is a backup tool. GitOps Reverser is event-driven, providing a real-time audit trail. |
This project includes a DevContainer for consistent development environments.
Linux/macOS: Works out of the box with Docker Desktop or Docker Engine.
Windows: See docs/ci/WINDOWS_DEVCONTAINER_SETUP.md for Windows-specific setup instructions. TL;DR: Use WSL2 for the best experience, or the devcontainer will automatically fix workspace permissions on startup.
make test # Unit tests
make test-e2e # End-to-end tests (requires Docker)
make lint # LintingContributions, issues, and discussions are welcome.
Apache 2.0
