A Kubernetes admission webhook that automatically injects External Secrets Operator (ESO) secrets into pods using the esi-cli tool. This webhook enables seamless integration between your applications and ESO-managed secrets without modifying application code.
- Automatic Secret Injection: Injects ESO-managed secrets as environment variables into pods
- Non-intrusive: Works with existing applications without code changes
- Secure: Uses init containers to handle secret injection, keeping secrets isolated
- Flexible: Supports both environment variable and file-based secret injection
- When a pod is created with the annotation
secretless.externalsecrets.com/env-vars: "true"(orsecretless.externalsecrets.com/file-secrets: "true"), the webhook intercepts the creation request - The webhook injects an init container (or a sidecar container) that uses
esi-clito fetch secrets from ESO - The init container processes the secrets and injects them into the main container
- The main container starts with the secrets available as environment variables (or as files in a specific directory)
Kubernetes docs for reference:
Structure of a mutating webhook:
- MutatingWebhookConfiguration configuring the api server to know about the webhook
- ServiceAccount for the webhook
- ClusterRole and ClusterRoleBinding for the webhook to be able to access the ESO CRDs
- Deployment for the webhook
- Service for the webhook (exposing it so the k8s api server can reach it)
In this case we are intercepting pod creation requests but we could intercept any other requests if that was needed.
ASC2 art with the lifecycle of a request:
+-------------------+
| kubectl / API |
| Client CLI |
+-------------------+
|
v
+-------------------+
| Kubernetes API |
| Server (Validation|
| & Admission) |
+-------------------+
|
v
+---------------------------+
| Authentication & |
| Authorization Checks |
+---------------------------+
|
v
+---------------------------+
| Admission Controllers |
| (Invokes Webhooks) |
+---------------------------+
|
|-->+------------------------------+ <------our webhook
| | Mutating Admission Webhook |
| | (Modifies the request object |
| | before persistence) |
| +------------------------------+
|
v
+---------------------------+
| Validating Admission |
| Controllers (optional) |
+---------------------------+
|
v
+---------------------------+
| Persist to etcd |
| (Stores the object state) |
+---------------------------+
|
v
+------------------------------------------------------------+
| Kubernetes Scheduler + controllers |
| (if it's a Pod or other higher level resources request) |
+------------------------------------------------------------+
|
v
+----------------------------------+
| Kubelet on the Node |
| (Pulls image, starts Pod... etc) |
+----------------------------------+
- Kubernetes cluster (v1.16+)
- External Secrets Operator installed and configured (actually only the CRDS are needed)
- cert-manager for certificate management (optional - but easier to set up)
-
Clone the repository:
git clone https://github.com/external-secrets-inc/esi-pod-webhook.git cd esi-pod-webhook -
Clone the esi-cli repository (should be in the same parent directory as esi-pod-webhook):
cd .. git clone https://github.com/external-secrets-inc/esi-cli.git cd esi-pod-webhook
-
create a cluster
make cluster
-
setup vault and add secrets to it and configure it to use k8s sa auth
make setup-vault
-
install eso and have crds and stuff ready
make setup-eso
-
run to build everything and load images to kind
make deploy-webhook
-
then to prepare the initial test setup edit the k8s/test-pod.yaml to uncomment the env var annotation, comment the file secret annotation, uncomment the do-env command and comment the cat file command
secretless.externalsecrets.com/externalsecret: "test-app-secrets" secretless.externalsecrets.com/env-vars: "true" # secretless.externalsecrets.com/file-secrets: "true" [...] [...] command: ["/bin/sh", "-c", "while true; do env | grep API; sleep 10; done"] # command: ["/bin/sh", "-c", "while ! [ -f /secrets/secrets.json ]; do echo 'Waiting for /secrets/secrets.json...'; sleep 1; done; while true; do env | grep API; cat /secrets/secrets.json; sleep 10; done"]
-
run the makefile target for testing
make test-vault
-
check the logs out
kubectl logs -f test-pod -c app
-
Then invert the commented and uncommented lines in the previous file mentioned and force delete and reapply:
kubectl delete pod test-pod --force && kubectl apply -f k8s/test-pod.yaml -
and check the logs again
kubectl logs -f test-pod -c app
- Go 1.20+
- Docker
- kind (for local development)
├── cmd/webhook # Main entry point
├── pkg/
│ ├── admission/ # Admission webhook logic
│ ├── container/ # Container injection logic
│ ├── k8s/ # Kubernetes client wrappers
│ └── patch/ # JSON patch operations
└── k8s/ # Kubernetes manifests
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.