projection

module
v0.1.0-alpha.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 13, 2026 License: Apache-2.0

README

projection

The Kubernetes CRD for declarative resource mirroring across namespaces — any Kind, conflict-safe, watch-driven.

CI Release Go Report Card License Go Reference

projection is a Kubernetes operator that mirrors any Kubernetes object — ConfigMap, Secret, Service, your custom resources — from a source location to a destination, declaratively, per resource. Each Projection CR is its own first-class object with status conditions, events, and a metric you can alert on. Edits to the source propagate to the destination in roughly 100 milliseconds.

It exists because every team eventually rebuilds this with a one-off controller or a Kyverno generate policy, and neither approach is the right shape. projection is meant to be the answer when somebody asks "how do you mirror a Secret across namespaces in this cluster?"

Why projection

projection emberstack/Reflector Kyverno generate
Works on any Kind ConfigMap & Secret only
Source-of-truth lives in a CR you can kubectl get ✓ (Projection) ✗ (annotations on the source) ✗ (cluster-wide policy)
Per-resource status + Kubernetes Events partial
Conflict-safe (refuses to overwrite unowned objects)
Watch-driven propagation (~100ms)
Admission-time validation of source fields n/a
Prometheus metrics per reconcile outcome partial
Footprint one CRD, one Deployment one CRD, one Deployment full policy engine

60-second demo

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: platform
data:
  log_level: info
---
apiVersion: projection.be0x74a.io/v1
kind: Projection
metadata:
  name: app-config-into-tenants
  namespace: platform
spec:
  source:
    apiVersion: v1
    kind: ConfigMap
    name: app-config
    namespace: platform
  destination:
    namespace: tenant-a
  overlay:
    labels:
      projected-by: projection
$ kubectl get projections -A
NAMESPACE   NAME                       KIND        SOURCE-NAMESPACE   SOURCE-NAME   DESTINATION   READY   AGE
platform    app-config-into-tenants    ConfigMap   platform           app-config    app-config    True    2s

$ kubectl get configmap -n tenant-a app-config -o jsonpath='{.metadata.annotations.projection\.be0x74a\.io/owned-by}'
platform/app-config-into-tenants

Edit the source — destination updates within ~100ms. Delete the Projection — destination is removed (only if projection still owns it). Pre-existing object at the destination? Ready=False reason=DestinationConflict. We don't overwrite strangers.

Features

  • Any KindRESTMapper-driven GVR resolution. Works on built-in resources, your CRDs, anything the apiserver knows about.
  • Watch-driven — dynamic informer registration per source GVK. Edits propagate in ~100ms; no periodic polling.
  • 🔒 Conflict-safe — ownership annotation marks our destinations. We refuse to overwrite objects we don't own and report DestinationConflict on status.
  • 🧹 Clean deletion — finalizer removes the destination on Projection deletion. If ownership has been stripped, we leave the object alone.
  • 📊 Observable — three status conditions (SourceResolved, DestinationWritten, Ready), Kubernetes Events for every state transition, and a projection_reconcile_total{result} Prometheus counter.
  • 🛡️ Validated at admissionSource fields are pattern-validated (DNS-1123 names, PascalCase Kinds) so typos fail at kubectl apply, not at runtime.
  • 🪞 Smart copy — strips server-owned metadata, drops .status, removes kubectl.kubernetes.io/last-applied-configuration, and preserves apiserver-allocated fields like Service.spec.clusterIP on update.
  • 🪶 Small — one CRD, one Deployment, one container. Distroless image, multi-arch (amd64, arm64).

Quick start

Helm
helm install projection oci://ghcr.io/be0x74a/charts/projection \
  --version 0.1.0-alpha \
  --namespace projection-system --create-namespace
kubectl apply
kubectl apply -f https://github.com/be0x74a/projection/releases/download/v0.1.0-alpha/install.yaml

Then create your first Projection:

kubectl apply -f https://raw.githubusercontent.com/be0x74a/projection/main/examples/configmap-cross-namespace.yaml
kubectl get projections -A

How it works

When you create a Projection, the controller resolves the source GVR via the RESTMapper, fetches the source object via the dynamic client, builds a sanitized destination object (overlay applied, ownership annotation stamped, server-owned metadata stripped), and creates or updates the destination — but only if projection already owns it. The first reconcile also registers a metadata-only watch on the source's GVK, so future edits to any source of that Kind enqueue the relevant Projections via a field-indexed lookup. Updates that wouldn't change the destination are skipped to avoid noisy events and metric churn.

See docs/concepts.md for the full picture, docs/observability.md for status/events/metrics, and docs/comparison.md for the deep comparison vs Reflector and Kyverno.

Use cases

  • Secrets across namespaces — distribute a TLS cert from cert-manager to multiple application namespaces without manual kubectl create.
  • Shared config distribution — one ConfigMap in platform, mirrored into each tenant namespace with overlay labels for tenant tagging.
  • Service mirroring — expose a backend Service from one namespace into another without a manual ExternalName dance.
  • CR replication — mirror an Issuer, a KafkaTopic, or any custom resource between namespaces in the same cluster.

v0 limitations (and what's planned)

  • Single destination per Projection. Multi-destination fan-out via label selector is on the roadmap; for now declare one Projection per destination namespace.
  • Same-cluster only. Cross-cluster mirroring is a non-goal for v0.
  • A few Kinds need extra care. Service, PersistentVolumeClaim, and Pod have apiserver-allocated spec fields handled out of the box. Other Kinds with similar fields (rare) may need an addition to droppedSpecFieldsByGVK.
  • Alpha. API may change before v1.0.0. CRD storage version is v1; future versions will be served alongside with conversion.

Documentation

Contributing

Pull requests welcome. See CONTRIBUTING.md. Be excellent to each other — see CODE_OF_CONDUCT.md.

Security

Found a vulnerability? Please report it privately via GitHub Security Advisories. See SECURITY.md.

License

Apache 2.0. See LICENSE.

Directories

Path Synopsis
api
v1
Package v1 contains API Schema definitions for the projection v1 API group +kubebuilder:object:generate=true +groupName=projection.be0x74a.io
Package v1 contains API Schema definitions for the projection v1 API group +kubebuilder:object:generate=true +groupName=projection.be0x74a.io
internal
test

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL