Annotation based runtime injection for Helm charts.
A product Helm chart only declares what it needs, for example Redis or NATS. The operator resolves those needs against ResourceProvider objects, injects static environment variables, and creates ExternalSecret resources that pull credentials from OpenBao through External Secrets Operator.
ResourceBinding has been removed. The default contract is now:
Helm chart annotations -> ResourceProvider -> ExternalSecret -> injected env
- Kubernetes
- cert-manager
- External Secrets Operator
- OpenBao/Vault
- A
ClusterSecretStorenamedopenbao
Build and push an image:
make docker-build IMG=ghcr.io/eclipse-xfsc/resource-operator:dev
make docker-push IMG=ghcr.io/eclipse-xfsc/resource-operator:devFor kind:
make docker-build IMG=ghcr.io/eclipse-xfsc/resource-operator:dev
kind load docker-image ghcr.io/eclipse-xfsc/resource-operator:devDeploy:
kubectl apply -k config/defaultVerify:
kubectl get pods -n xsfc-systemThis creates a Redis ResourceProvider. It contains static config and the OpenBao/ESO mapping, but no secret values.
kubectl apply -f examples/redis-provider.yamlThe provider says:
spec:
type: redis
outputs:
env:
REDIS_HOST: redis-master.redis.svc.cluster.local
REDIS_PORT: "6379"
externalSecrets:
- targetSecretNameTemplate: "{{ workload }}-redis"
remoteKeyTemplate: "tenants/{{ namespace }}/redis/{{ workload }}"The external tenant management system must already have written credentials to OpenBao at:
tenants/tenant-a/redis/wallet-api
with properties like:
{
"username": "tenant-a-wallet-api",
"password": "..."
}kubectl apply -f examples/workload.yamlThe Deployment only declares its needs on the pod template:
spec:
template:
metadata:
annotations:
inject.xfsc.io/enabled: "true"
inject.xfsc.io/needs: "redis"The admission webhook patches the Deployment with:
REDIS_HOSTREDIS_PORTREDIS_TLSREDIS_CLUSTERREDIS_USERNAMEfromsecretKeyRefREDIS_PASSWORDfromsecretKeyRef
The workload controller creates the matching ExternalSecret:
kubectl get externalsecret -n tenant-a
kubectl get deployment wallet-api -n tenant-a -o yamlExpected ExternalSecret name:
wallet-api-redis-eso
Expected target Kubernetes Secret name:
wallet-api-redis
Product charts should not create ResourceProvider objects. They should only declare needs:
spec:
template:
metadata:
annotations:
inject.xfsc.io/enabled: "true"
inject.xfsc.io/needs: "redis,nats,service.xy"Platform charts install providers:
kind: ResourceProvider
spec:
type: nats
outputs:
env:
NATS_URL: nats://nats.infra.svc.cluster.local:4222
externalSecrets:
- targetSecretNameTemplate: "{{ workload }}-nats"
remoteKeyTemplate: "tenants/{{ namespace }}/nats/{{ workload }}"If a chart needs a specific provider instead of type based resolution:
inject.xfsc.io/providers: "infra/redis-default"Tenant management:
- creates Redis/NATS/Postgres/S3 accounts
- rotates credentials
- writes secrets to OpenBao
XSFC operator:
- resolves
inject.xfsc.io/needs - renders provider templates
- creates
ExternalSecret - patches workload env
External Secrets Operator:
- reads OpenBao
- creates the Kubernetes Secret