Initial commit

main
Lauri Võsandi 3 months ago
commit fbc6fa2f84
  1. 2
      .drone.yml
  2. 3
      Dockerfile
  3. 16
      README.md
  4. 43
      generated-secret-crd.yml
  5. 84
      generated-secret-operator.py

@ -0,0 +1,2 @@
kind: template
load: docker.yaml

@ -0,0 +1,3 @@
FROM harbor.k-space.ee/k-space/microservice-base
ADD generated-secret-operator.py /
ENTRYPOINT /generated-secret-operator.py

@ -0,0 +1,16 @@
# Generated secret operator
This operator can be used to provision secrets easily
To instantiate secret:
```
apiVersion: codemowers.io/v1alpha1
kind: GeneratedSecret
metadata:
name: my-secret
spec:
mapping:
- key: SECRET
value: "%(password)s"
```

@ -0,0 +1,43 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: generatedsecrets.codemowers.io
spec:
group: codemowers.io
names:
plural: generatedsecrets
singular: generatedsecret
kind: GeneratedSecret
shortNames:
- generatedsecret
scope: Namespaced
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
mapping:
type: array
items:
type: object
properties:
key:
type: string
description:
Secret key
value:
type: string
description:
Secret value with suitable placeholders
size:
default: 20
type: integer
description: Generated secret length
required: ["spec"]

@ -0,0 +1,84 @@
#!/usr/bin/env python3
import asyncio
import os
import prometheus_async
import random
import string
from prometheus_client import Counter, Gauge
from kubernetes_asyncio.client.api_client import ApiClient
from kubernetes_asyncio.client.exceptions import ApiException
from kubernetes_asyncio import client, config, watch
from time import time
counter_opened_watch_streams = Counter(
"meta_operator_opened_watch_streams",
"Count of watch streams opened")
gauge_watch_stream_begin_timestamp = Gauge(
"meta_operator_watch_stream_begin_timestamp",
"Timestamp of last watch stream open")
async def apply_changes(item, v1, apps_api, api_instance):
namespace = item["metadata"]["namespace"]
name = item["metadata"]["name"]
password = "".join([random.choice(string.ascii_letters + string.digits) for j in range(item["spec"]["size"])])
data = {}
for o in item["spec"]["mapping"]:
data[o["key"]] = o["value"] % {"password": password}
try:
await v1.create_namespaced_secret(namespace, body={
"metadata": {
"name": name,
"annotations": {},
"ownerReferences": [{
"apiVersion": "codemowers.io/v1alpha1",
"kind": "GeneratedSecret",
"uid": item["metadata"]["uid"],
"name": name
}]
},
"stringData": data
})
print("Generated secret %s/%s" % (namespace, name))
except ApiException as e:
if e.status == 409:
print("Secret %s/%s already generated" % (namespace, name))
else:
raise
async def main():
if os.getenv("KUBECONFIG"):
await config.load_kube_config()
else:
config.load_incluster_config()
async with ApiClient() as api:
v1 = client.CoreV1Api(api)
apps_api = client.AppsV1Api()
api_instance = client.CustomObjectsApi(api)
while True:
try:
gauge_watch_stream_begin_timestamp.set(time())
print("Subscribing to updates in every namespace")
w = watch.Watch()
counter_opened_watch_streams.inc()
flt = "codemowers.io", "v1alpha1", "", "generatedsecrets"
method = api_instance.list_namespaced_custom_object
async for event in w.stream(method, *flt):
if event["type"] == "ADDED":
await apply_changes(event["object"], v1, apps_api, api_instance)
except ApiException as e:
print("Caught exception: %s" % e)
if e.status == 410:
pass
else:
raise
except asyncio.exceptions.TimeoutError:
pass
if __name__ == "__main__":
loop = asyncio.new_event_loop()
loop.create_task(prometheus_async.aio.web.start_http_server(port=5000))
loop.run_until_complete(main())
loop.close()
Loading…
Cancel
Save