| 🔴 YouTube Recording, 🎓️ Slides (backup) |
|---|
On 30 June 2022, Antoine Le Squéren and Maël Valais presented "Hack your Kubernetes controller in Bash in 10 minutes!" at Kubernetetes Community Days Berlin. The rest of this document shows how to run the "one-liner controller" we talked about in the presentation.
In the presentation, we show a controller that takes for form of a "one-liner" that you can copy-paste in your terminal.
kubectl get externalsecret --watch -ojson \
| jq 'select(.status.conditions[]?.reason == "SecretSyncedError")' --unbuffered \
| jq '.spec.data[0].remoteRef | "\(.key) \(.property)"' -r --unbuffered \
| while read key property; do
vault kv put $key $property=somerandomvalue
doneThe file controller.sh contains the above command.
To try this controller, you will need to install the following tools:
dockerwhich you can get withcolimaon M1 and Intel Macs (instead of Docker Desktop for Mac).kubectl1.24 or above (required for--subresource),k3d.
Then, run the following command. The command creates a K3s cluster
and installs Vault and external-secrets, as well as an ExternalSecret
object called postgres for demonstration purposes:
./setup.shRun the following long-running command (this is an optional step):
$ kubectl get externalsecret --watch
NAME KEY PROPERTY READY REASON MESSAGE
postgres secret/dev-1/postgres password True SecretSynced Secret was synced
postgres secret/dev-1/postgres password True SecretSynced Secret was syncedOpen a second shell session to create a tunnel to Vault with the following command:
kubectl port-forward -n vault vault-0 8200In a third shell session, run the controller with the command:
export VAULT_ADDR=http://localhost:8200 VAULT_TOKEN=root
./controller.shLooking at the first shell session (the one with kubectl get externalsecret --watch)
you will see the postgres external secret going from SecretSyncedError to
SecretSynced:
NAME KEY PROPERTY READY REASON MESSAGE
postgres secret/dev-1/postgres password False SecretSyncedError could not get secret data from provider
postgres secret/dev-1/postgres password True SecretSynced Secret was synced
The controller's output isn't great. It just shows what vault put shows
when an external secret is processed.
$ ./controller.sh
======= Secret Path =======
secret/data/dev-1/postgres
======= Metadata =======
Key Value
--- -----
created_time 2022-06-27T15:41:59.346502796Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1(Optional) You can now run the controller in a Pod. Run the following two commands to build the container and
docker buildx build . -t controller:local -o type=docker,dest=img.tar && k3d images import img.tar
kubectl apply -f ./deploy.yaml
⁉️ docker buildvs.docker buildx build: In the above command, we use thebuildxsubcommand, also called BuildKit. Unlike the traditionaldocker buildcommand, with BuildKit, it is possible to save the Docker-compatible image tarball directly to disk using-o type=docker,dest=img.tar.
Check that the controller is running:
$ kubectl logs -f deployment/controller
======= Secret Path =======
secret/data/dev-1/postgres
======= Metadata =======
Key Value
--- -----
created_time 2022-06-27T15:41:59.346502796Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 2To see if the controller is working, you can run the following command:
vault kv metadata delete secret/dev-1/postgresIn the first shell session where kubectl get externalsecret --watch is running,
you will see the external secret from SecretSynced to SecretSyncedError
and back to SecretSyncedError:
NAME KEY PROPERTY READY REASON MESSAGE
postgres secret/dev-1/postgres password False SecretSyncedError could not get secret data from provider
postgres secret/dev-1/postgres password True SecretSynced Secret was synced
postgres secret/dev-1/postgres password True SecretSynced Secret was synced
postgres secret/dev-1/postgres password True SecretSynced Secret was synced
postgres secret/dev-1/postgres password False SecretSyncedError could not get secret data from provider
postgres secret/dev-1/postgres password True SecretSynced Secret was synced
As we demonstrated during the presentation, one-liner controller.sh has a
very uninformative logs.
On top of poor logs, controller.sh does not inform Kubernetes users why a
particular ExternalSecret object does not seem to be picked up by the
controller. Nothing shows in the status, and nothing shows in events.
The file controller-with-conditions.sh is similar to controller.sh, except
for three aspects:
- The user is now alerted of problems with the condition
Created. - The user now has to set the annotation
create: trueto enable the auto-generation of the secret in Vault. - The logs are now well structured.
In a first shell session, turn on port-forwarding to Vault with the command:
kubectl port-forward -n vault vault-0 8200In a second shell session, run the controller with the command:
export VAULT_ADDR=http://localhost:8200 VAULT_TOKEN=root
./controller-with-conditions.shYou can now "enable" the behavior on the external secret postgres with the
following command:
kubectl annotate externalsecret postgres create=trueThe logs should look like this:
$ ./controller-with-conditions.sh
info: started watching ExternalSecrets.
postgres: the ExternalSecret is Ready=False, let us create a random password and put it in Vault.
postgres: the Vault secret was created.
postgres: inconsistency: Created is True but SecretSyncedError is False. Attempting to recreate the secret in Vault to fix this issue.
postgres: the ExternalSecret is Ready=False, let us create a random password and put it in Vault.
postgres: the Vault secret was created.

