From 40f76a8bdb8da813408ee47fa4aec0d3debfd0f4 Mon Sep 17 00:00:00 2001 From: Tobias Trabelsi Date: Mon, 26 Dec 2022 16:29:14 +0100 Subject: [PATCH] update and retry handler --- Dockerfile | 2 +- charts/bitwarden-crd-operator/Chart.yaml | 14 +++--- src/dockerlogin.py | 35 +++++++++++++- src/kv.py | 61 ++++++++++++++++++++---- src/template.py | 38 +++++++++++---- 5 files changed, 122 insertions(+), 28 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6d1d4d2..0380275 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,5 +30,5 @@ COPY --chown=bw-operator:bw-operator src /home/bw-operator USER bw-operator -ENTRYPOINT [ "kopf", "run", "--all-namespaces", "--liveness=http://0.0.0.0:8080/healthz" ] +ENTRYPOINT [ "kopf", "run", "--log-format=json", "--all-namespaces", "--liveness=http://0.0.0.0:8080/healthz" ] CMD [ "/home/bw-operator/bitwardenCrdOperator.py", "/home/bw-operator/kv.py", "/home/bw-operator/dockerlogin.py", "/home/bw-operator/template.py"] diff --git a/charts/bitwarden-crd-operator/Chart.yaml b/charts/bitwarden-crd-operator/Chart.yaml index eca83ac..bda8355 100644 --- a/charts/bitwarden-crd-operator/Chart.yaml +++ b/charts/bitwarden-crd-operator/Chart.yaml @@ -4,9 +4,9 @@ description: Deploy the Bitwarden CRD Operator type: application -version: "v0.4.3" +version: "v0.5.0" -appVersion: "0.4.2" +appVersion: "0.5.0" keywords: - operator @@ -94,10 +94,12 @@ annotations: artifacthub.io/license: MIT artifacthub.io/operator: "true" artifacthub.io/changes: | - - kind: fixed - description: "Updated Dependencies to fix CVEs" - kind: added - description: "Upload SBOM to GitHub Release" + description: "Implemented update handling" + - kind: changed + description: "Changed default logging structure to json logging" + - kind: changed + description: "Secrets are periodically updated every 15 minutes" artifacthub.io/images: | - name: bitwarden-crd-operator - image: lerentis/bitwarden-crd-operator:0.4.2 + image: lerentis/bitwarden-crd-operator:0.5.0 diff --git a/src/dockerlogin.py b/src/dockerlogin.py index 095d322..bdc876b 100644 --- a/src/dockerlogin.py +++ b/src/dockerlogin.py @@ -53,8 +53,39 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): logger.info(f"Registry Secret {secret_namespace}/{secret_name} has been created") @kopf.on.update('registry-credential.lerentis.uploadfilter24.eu') -def my_handler(spec, old, new, diff, **_): - pass +@kopf.timer('registry-credential.lerentis.uploadfilter24.eu', interval=900) +def update_managed_registry_secret(spec, status, name, namespace, logger, body, **kwargs): + + username_ref = spec.get('usernameRef') + password_ref = spec.get('passwordRef') + registry = spec.get('registry') + id = spec.get('id') + secret_name = spec.get('name') + secret_namespace = spec.get('namespace') + + unlock_bw(logger) + logger.info(f"Locking up secret with ID: {id}") + secret_json_object = json.loads(get_secret_from_bitwarden(id)) + + api = kubernetes.client.CoreV1Api() + + annotations = { + "managed": "registry-credential.lerentis.uploadfilter24.eu", + "managedObject": f"{namespace}/{name}" + } + secret = kubernetes.client.V1Secret() + secret.metadata = kubernetes.client.V1ObjectMeta(name=secret_name, annotations=annotations) + secret = create_dockerlogin(logger, secret, secret_json_object, username_ref, password_ref, registry) + try: + obj = api.replace_namespaced_secret( + name=secret_name, + body=secret, + namespace="{}".format(secret_namespace)) + logger.info(f"Secret {secret_namespace}/{secret_name} has been updated") + except: + logger.warn( + f"Could not update secret {secret_namespace}/{secret_name}!") + @kopf.on.delete('registry-credential.lerentis.uploadfilter24.eu') def delete_managed_secret(spec, name, namespace, logger, **kwargs): diff --git a/src/kv.py b/src/kv.py index 598d3d6..1de6c9a 100644 --- a/src/kv.py +++ b/src/kv.py @@ -5,12 +5,13 @@ import json from utils.utils import unlock_bw, get_secret_from_bitwarden, parse_login_scope, parse_fields_scope + def create_kv(secret, secret_json, content_def): secret.type = "Opaque" secret.data = {} for eleml in content_def: for k, elem in eleml.items(): - for key,value in elem.items(): + for key, value in elem.items(): if key == "secretName": _secret_key = value if key == "secretRef": @@ -18,11 +19,14 @@ def create_kv(secret, secret_json, content_def): if key == "secretScope": _secret_scope = value if _secret_scope == "login": - secret.data[_secret_ref] = str(base64.b64encode(parse_login_scope(secret_json, _secret_key).encode("utf-8")), "utf-8") + secret.data[_secret_ref] = str(base64.b64encode( + parse_login_scope(secret_json, _secret_key).encode("utf-8")), "utf-8") if _secret_scope == "fields": - secret.data[_secret_ref] = str(base64.b64encode(parse_fields_scope(secret_json, _secret_key).encode("utf-8")), "utf-8") + secret.data[_secret_ref] = str(base64.b64encode( + parse_fields_scope(secret_json, _secret_key).encode("utf-8")), "utf-8") return secret + @kopf.on.create('bitwarden-secret.lerentis.uploadfilter24.eu') def create_managed_secret(spec, name, namespace, logger, body, **kwargs): @@ -42,18 +46,53 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): "managedObject": f"{namespace}/{name}" } secret = kubernetes.client.V1Secret() - secret.metadata = kubernetes.client.V1ObjectMeta(name=secret_name, annotations=annotations) - secret = create_kv(secret, secret_json_object, content_def) + secret.metadata = kubernetes.client.V1ObjectMeta( + name=secret_name, annotations=annotations) + secret = create_kv(secret, secret_json_object, content_def) obj = api.create_namespaced_secret( - secret_namespace, secret + namespace="{}".format(secret_namespace), + body=secret ) logger.info(f"Secret {secret_namespace}/{secret_name} has been created") + @kopf.on.update('bitwarden-secret.lerentis.uploadfilter24.eu') -def my_handler(spec, old, new, diff, **_): - pass +@kopf.timer('bitwarden-secret.lerentis.uploadfilter24.eu', interval=900) +def update_managed_secret(spec, status, name, namespace, logger, body, **kwargs): + + content_def = body['spec']['content'] + id = spec.get('id') + secret_name = spec.get('name') + secret_namespace = spec.get('namespace') + + unlock_bw(logger) + logger.info(f"Locking up secret with ID: {id}") + secret_json_object = json.loads(get_secret_from_bitwarden(id)) + + api = kubernetes.client.CoreV1Api() + + annotations = { + "managed": "bitwarden-secret.lerentis.uploadfilter24.eu", + "managedObject": f"{namespace}/{name}" + } + + secret = kubernetes.client.V1Secret() + secret.metadata = kubernetes.client.V1ObjectMeta( + name=secret_name, annotations=annotations) + secret = create_kv(secret, secret_json_object, content_def) + + try: + obj = api.replace_namespaced_secret( + name=secret_name, + body=secret, + namespace="{}".format(secret_namespace)) + logger.info(f"Secret {secret_namespace}/{secret_name} has been updated") + except: + logger.warn( + f"Could not update secret {secret_namespace}/{secret_name}!") + @kopf.on.delete('bitwarden-secret.lerentis.uploadfilter24.eu') def delete_managed_secret(spec, name, namespace, logger, **kwargs): @@ -63,6 +102,8 @@ def delete_managed_secret(spec, name, namespace, logger, **kwargs): try: api.delete_namespaced_secret(secret_name, secret_namespace) - logger.info(f"Secret {secret_namespace}/{secret_name} has been deleted") + logger.info( + f"Secret {secret_namespace}/{secret_name} has been deleted") except: - logger.warn(f"Could not delete secret {secret_namespace}/{secret_name}!") \ No newline at end of file + logger.warn( + f"Could not delete secret {secret_namespace}/{secret_name}!") diff --git a/src/template.py b/src/template.py index e3abcb9..e34e73c 100644 --- a/src/template.py +++ b/src/template.py @@ -49,8 +49,35 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): logger.info(f"Secret {secret_namespace}/{secret_name} has been created") @kopf.on.update('bitwarden-template.lerentis.uploadfilter24.eu') -def my_handler(spec, old, new, diff, **_): - pass +@kopf.timer('bitwarden-template.lerentis.uploadfilter24.eu', interval=900) +def update_managed_secret(spec, status, name, namespace, logger, body, **kwargs): + + template = spec.get('template') + filename = spec.get('filename') + secret_name = spec.get('name') + secret_namespace = spec.get('namespace') + + unlock_bw(logger) + + api = kubernetes.client.CoreV1Api() + + annotations = { + "managed": "bitwarden-template.lerentis.uploadfilter24.eu", + "managedObject": f"{namespace}/{name}" + } + secret = kubernetes.client.V1Secret() + secret.metadata = kubernetes.client.V1ObjectMeta(name=secret_name, annotations=annotations) + secret = create_template_secret(secret, filename, template) + + try: + obj = api.replace_namespaced_secret( + name=secret_name, + body=secret, + namespace="{}".format(secret_namespace)) + logger.info(f"Secret {secret_namespace}/{secret_name} has been updated") + except: + logger.warn( + f"Could not update secret {secret_namespace}/{secret_name}!") @kopf.on.delete('bitwarden-template.lerentis.uploadfilter24.eu') def delete_managed_secret(spec, name, namespace, logger, **kwargs): @@ -63,10 +90,3 @@ def delete_managed_secret(spec, name, namespace, logger, **kwargs): logger.info(f"Secret {secret_namespace}/{secret_name} has been deleted") except: logger.warn(f"Could not delete secret {secret_namespace}/{secret_name}!") - -#if __name__ == '__main__': -# tpl = """ -# Calling the 'bitwarden_lookup' function: -# {{ bitwarden_lookup(2, 2) }} -# """ -# print(render_template(tpl)) \ No newline at end of file