Kubernetes
A controller-runtime operator that materializes a Vaultic environment as a native v1.Secret, refreshed on an interval.
The Vaultic Kubernetes operator materializes an environment as a native v1.Secret, kept in sync
on a poll interval — so workloads consume an ordinary Kubernetes Secret, with Vaultic as the
source of truth behind it.
Built with controller-runtime, following standard kubebuilder project conventions, as a standalone Go module.
The CRD: VaulticSecret
apiVersion: vaultic.dev/v1alpha1
kind: VaulticSecret
metadata:
name: backend-api-production
spec:
serverURL: http://vaultic-server.default.svc.cluster.local:4000
workspace: acme
project: backend-api
environment: production
tokenSecretRef:
name: vaultic-token # an existing Secret holding a Vaultic service token
key: token
targetSecretName: backend-api-production # the v1.Secret this controller creates/updates
refreshIntervalSeconds: 60What the controller does on each reconcile
Read the service token
From spec.tokenSecretRef, in the same namespace as the VaulticSecret — the token is never
stored inline in the CR spec.
Fetch the resolved environment
Calls the same fully-resolved (inheritance + ${...} reference) export endpoint
vaultic export and vaultic run use.
Create or update the target Secret
Named spec.targetSecretName (defaults to the CR's own name), owned by the VaulticSecret
via OwnerReference — deleting the CR garbage-collects the Secret automatically, no finalizer
needed.
Report status
Sets a standard Ready condition and status.syncedKeyCount on the CR.
Requeue
After spec.refreshIntervalSeconds (default 60, min 5) — this is what makes refresh happen
even with zero Kubernetes-side events, since the API server has no way to know a secret
changed purely on the Vaultic side. Errors back off to a shorter retry instead of waiting a
full interval.
A single controller replica needs no leader election (a --leader-elect flag exists if you run
more than one).
Deploying
# 1. CRD
kubectl apply -f config/crd/vaultic.dev_vaulticsecrets.yaml
# 2. RBAC + namespace
kubectl apply -f config/manager/namespace.yaml
kubectl apply -f config/rbac/service_account.yaml
kubectl apply -f config/rbac/role.yaml
kubectl apply -f config/rbac/role_binding.yaml
# 3. Load the image into your cluster (it isn't pushed to a registry)
kind load docker-image vaultic/k8s-operator:dev # kind
# or: minikube image load vaultic/k8s-operator:dev # minikube
# 4. Deploy
kubectl apply -f config/manager/deployment.yaml
# 5. Your VaulticSecret + its token Secret
kubectl apply -f config/samples/vaultic_v1alpha1_vaulticsecret.yaml
kubectl get vaulticsecret
kubectl get secret backend-api-production -o yamlTo iterate without rebuilding a container image each time, the manager runs fine as a plain
local process against any cluster your kubeconfig points at: go run ./cmd.
Building
cd k8s-operator
go build -o manager ./cmd # local binary
docker build -t vaultic/k8s-operator:dev . # container image