https://github.com/thejefflarson/whisperer
A kubernetes operator that syncs secrets across namespaces.
https://github.com/thejefflarson/whisperer
Last synced: 5 months ago
JSON representation
A kubernetes operator that syncs secrets across namespaces.
- Host: GitHub
- URL: https://github.com/thejefflarson/whisperer
- Owner: thejefflarson
- License: mit
- Created: 2025-01-25T03:40:08.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-12-29T00:37:41.000Z (6 months ago)
- Last Synced: 2025-12-31T18:42:55.375Z (6 months ago)
- Language: Rust
- Size: 353 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# whisperer
A mostly dumb way to make sure every k8s namespace has your pull secrets.
## Ok, what is all this?
**whisperer** is a kubernetes operator that whispers a secret to another namespaces.
It's 300 lines of core code in `src/controller.rs`, most of which is handling edgecases, I'd love to know if there are more I haven't thought of.
## Cool so how do I use it?
Whelp, right now, maybe hold off? I'm a few days away from CICD and a helm chart, but when that's ready, here's how it works.
Create some namespaces and a secret in a file called `sync.yaml`:
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: source
---
apiVersion: v1
kind: Namespace
metadata:
name: target
---
apiVersion: v1
kind: Namespace
metadata:
name: target2
---
apiVersion: v1
kind: Secret
metadata:
name: sync
namespace: source
labels:
whisperer.jeffl.es/sync: "true"
annotations:
whisperer.jeffl.es/namespaces: "target,target2,missing"
data:
secret: dG90YWxseSBhIHN1cGVyIGR1cGVyIHNlY3JldCB5b3Ugc2hvdWxkbid0IHRlbGwgYW55b25lCg==
```
Boot up a k3ds cluster:
```
$ k3d cluster create test
```
Start the operator:
```
$ cargo run
```
And run:
`kubectl apply -f sync.yaml`
Hot diggedy dog, your secrets are synced across namespaces!
Just Look at the `target` and `target2` namespaces! You have secrets that mirror the secret you created:
```
$ kubectl get secrets --all-namespaces
NAMESPACE NAME TYPE DATA AGE
kube-system k3d-test-server-0.node-password.k3s Opaque 1 23m
kube-system k3s-serving kubernetes.io/tls 2 23m
source sync Opaque 1 70s
target sync Opaque 1 26s
target2 sync Opaque 1 26s
```
NEAT-O! No more running `kubectl create secret github ...` in all your namespaces!
## Whelp, that's mildly interesting, how does it work?
I'm glad you asked, the trick is in the labels and annotations on the secret itself:
```yaml
labels:
whisperer.jeffl.es/sync: "true"
annotations:
whisperer.jeffl.es/namespaces: "target,target2,missing"
```
The label `whisperer.jeffl.es/sync` tells the operator to sync the secret to the comma separated namespaces in the annotation `whisperer.jeffl.es/namespaces`. (BTW, **whisperer** will complain about the `missing` namespace here, but if you create it, it'll eventually catch up, like in 300 seconds or so. That's a lot, but maybe that's on you for whispering to an imaginary friend? You do you.)
There are a couple other niceties as well. You can delete a synced secret and it'll come right back:
```
$ kubectl delete secret -n target sync
secret "sync" deleted
$ kubectl get secrets --all-namespaces
NAMESPACE NAME TYPE DATA AGE
kube-system k3d-test-server-0.node-password.k3s Opaque 1 29m
kube-system k3s-serving kubernetes.io/tls 2 30m
source sync Opaque 1 7m27s
target sync Opaque 1 26s
target2 sync Opaque 1 6m43s
```
You can also search for all your sources of synced secrets:
```
$ kubectl get secrets -l "whisperer.jeffl.es/sync=true" --all-namespaces
NAMESPACE NAME TYPE DATA AGE
source sync Opaque 1 10m
```
Or search for "whispered" secrets (haha, great pun jeff):
```
$ kubectl get secrets -l "whisperer.jeffl.es/whisper=true" --all-namespaces
NAMESPACE NAME TYPE DATA AGE
target sync Opaque 1 3m57s
target2 sync Opaque 1 10m
```
Or look for where a particular secret is whispered to:
```
$ kubectl get secrets -l "whisperer.jeffl.es/name=sync,whisperer.jeffl.es/namespace=source" --all-namespaces
NAMESPACE NAME TYPE DATA AGE
target sync Opaque 1 5m52s
target2 sync Opaque 1 12m
```
NEAT-O KEEN-O!
## Yeah, what's the monitoring sitch like?
Well, it has [tracing](https://docs.rs/tracing/latest/tracing/) so all the environment switches work there, and bonus: it also strives to have [opentelemetry](https://opentelemetry.io/) bells and whistles, and there's a prometheus endpoint if that's your jam, but honestly I only understand like 5% of that stuff.
## Ok, but like namespaces are supposed to be independent.
Yeah I know.
## Thanks, I hate it.
Cool! I really like you too! But if it isn't your thing, delete the source secret and everything is gone:
```
$ kubectl delete secret -n source sync
secret "sync" deleted
$ kubectl get secrets --all-namespaces
NAMESPACE NAME TYPE DATA AGE
kube-system k3d-test-server-0.node-password.k3s Opaque 1 43m
kube-system k3s-serving kubernetes.io/tls 2 43m
```
Have a wonderful day!
## One more thing: I feel like other folks have made this.
Sure, but this is how I wanted it to work. Maybe you do too?