|
1 | 1 | # Doppler Kubernetes Controller
|
2 | 2 |
|
3 |
| -A custom Kubernetes Controller which polls Doppler's servers and updates environment variables automatically. |
| 3 | +A custom Kubernetes Controller which polls Doppler's secrets API to automatically create and update a native Kubernetes secret using the `spec.serviceToken` and `spec.secretName` fields from the `dopplersecrets.doppler.com` custom resource. |
4 | 4 |
|
5 |
| -## Motivation |
| 5 | +The Kubernetes secret created by the controller is just a regular secret with some Doppler specific labels and annoations. |
6 | 6 |
|
7 |
| -Doppler is a universal secrets manager which offers ease of use to our team in development. However, they don't have a native Kubernetes integration which automatically updates environment variables. |
| 7 | +The secret is then used by a deployment to expose the secrets as environment variables using `envFrom:`. |
8 | 8 |
|
9 |
| -This tool aims to solve that issue and to allow secrets editing directly in Doppler. |
| 9 | +In essence, a `DopplerSecret` is just a mechanism to create a Kubernetes secret that is used by Deployments, saving the developer from habing to manually do that themselves. |
10 | 10 |
|
11 |
| -## Installing on a Kubernetes Cluster |
| 11 | +## Installation |
12 | 12 |
|
13 |
| -After downloading this repo, edit the refresh rate as needed in `k8s/manifest.yml` and simply run: |
| 13 | +Apply the manifest in `manivests/crd.yml` by running: |
14 | 14 |
|
15 | 15 | ```bash
|
16 | 16 | kubectl apply -f ./k8s/manifest.yml
|
17 | 17 | ```
|
18 | 18 |
|
19 |
| -An example of a `DopplerSecret` deployment can be found at `k8s/example.yml`. |
| 19 | +NOTE: The `crd.yml` defines an environment variables `SYNC_INTERVAL` which can be customized if required (default is once every 5 seconds). This is also the maximum delay between a `DopplerSecret` and the associated Kube secret being created. |
20 | 20 |
|
21 |
| -## Local Development |
| 21 | +## Kubernetes dashboard on Docker for Desktop for viewing resources |
22 | 22 |
|
23 |
| -Assuming you have a local Kubernetes Cluster (I used Docker Desktop) and [Tilt](https://tilt.dev/), you can simply run this command: |
| 23 | +The Kubernetes dashboard is handy for inspecting the state of various resources such as the CRD itself and the logs of the Controller Pod so here is how you can access it if using Docker for Desktop: |
24 | 24 |
|
25 |
| -```bash |
26 |
| -tilt up |
| 25 | +Install the Dashboard resources: |
| 26 | + |
| 27 | +```sh |
| 28 | +kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml |
| 29 | +``` |
| 30 | + |
| 31 | +Run Kube proxy in order to reach the dashboard: |
| 32 | + |
| 33 | +```sh |
| 34 | +kubectl proxy |
| 35 | +``` |
| 36 | + |
| 37 | +Use `kubectl` to get the token value from the Kube secret that was created when the dashboard was installed and copy it to your clipboard: |
| 38 | + |
| 39 | +```sh |
| 40 | +kubectl get secret $(kubectl get secret --namespace kubernetes-dashboard | grep kubernetes-dashboard-token | awk '{print $1}') --namespace ${KUBE_DASHBOARD_NAMESPACE} --template={{.data.token}} | base64 -D | pbcopy |
| 41 | +``` |
| 42 | + |
| 43 | +Open the dashboard - http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ |
| 44 | + |
| 45 | +Paste in your token and you should be good to go! |
| 46 | + |
| 47 | +## Usage |
| 48 | + |
| 49 | +NOTE: The `envsubst` binary is required and can be installed in macOS by running: |
| 50 | + |
| 51 | +```sh |
| 52 | +brew install gettext |
| 53 | +``` |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +To create a `DopplerSecret`, run the following which will substitute the srevice token value and feed the stdout into the `kubectl`: |
| 58 | + |
| 59 | +```sh |
| 60 | +# Avoids hard-coding the service token in the manifest and it touching the file system |
| 61 | +kubectl apply -f <(SERVICE_TOKEN="XXXXXX" envsubst < example/dopplersecret.yml) |
| 62 | +``` |
| 63 | + |
| 64 | +Now create the deployment which uses the secret created by the Controller. The `secretName` in the `DopplerSecret` spec is the name of the sercret the controller will create, which will be referenced by the `envFrom.secretRef.name` property. |
| 65 | + |
| 66 | +```sh |
| 67 | +kubectl apply -f example/deployment.yml |
| 68 | +``` |
| 69 | + |
| 70 | +Then in order to test that the deployment Pod had secrets supplied as env vars correctly, run the following which should be the names of all env vars: |
| 71 | + |
| 72 | +```sh |
| 73 | +kubectl logs -lapp=doppler-secret-test |
27 | 74 | ```
|
| 75 | + |
| 76 | +### Clean up |
| 77 | + |
| 78 | +To remove all resources create, run: |
| 79 | + |
| 80 | +```sh |
| 81 | +kubectl delete -f example/deployment.yml |
| 82 | +kubectl delete -f example/dopplersecret.yml |
| 83 | +kubectl delete secrets doppler-app-secret |
| 84 | +``` |
| 85 | + |
| 86 | +## Learnings |
| 87 | + |
| 88 | +- Revise deployment strategy. Need to have at least two nodes. Careful of single point of failure, then no secrets will be created. |
| 89 | +- Automatically triggering a new deployment when variables is change is a cool idea, but not sure everyone will want that. |
| 90 | +- What should happen if a service token is invalidated? Generally speaking, what's our approach to error handling. |
| 91 | +- Probably best written in Go |
| 92 | +- Max delay of `SYNC_INTERVAL` between `DopplerSecret` created and Kube secret created is the max delay that a deployment will be invalid if deployment is created when `DopplerSecret` is. |
| 93 | + |
| 94 | +## To Do |
| 95 | + |
| 96 | +- Tests! |
| 97 | +- Handle case when invalid service token is supplied initially, as secret will not be created |
| 98 | +- Use labels and selectors to have a `DopplerSecret` as the owner of the Kube secret |
| 99 | +- Add a grace period and a finalizer to `DopplerSecret` so the controller can detect deleted state, remove associated secret, then remove finalizer to have Kube clean it up |
0 commit comments