diff --git a/Dockerfile b/Dockerfile index 5e98306..baefa68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ -FROM alpine:3.18.3 +FROM alpine:3.19.0 LABEL org.opencontainers.image.source=https://github.com/Lerentis/bitwarden-crd-operator LABEL org.opencontainers.image.description="Kubernetes Operator to create k8s secrets from bitwarden" LABEL org.opencontainers.image.licenses=MIT -ARG PYTHON_VERSION=3.11.6-r0 -ARG PIP_VERSION=23.1.2-r0 -ARG GCOMPAT_VERSION=1.1.0-r1 -ARG LIBCRYPTO_VERSION=3.1.2-r0 +ARG PYTHON_VERSION=3.11.6-r1 +ARG PIP_VERSION=23.3.1-r0 +ARG GCOMPAT_VERSION=1.1.0-r4 +ARG LIBCRYPTO_VERSION=3.1.4-r2 ARG BW_VERSION=2023.1.0 COPY requirements.txt /requirements.txt @@ -38,7 +38,7 @@ RUN set -eux; \ mkdir -p /home/bw-operator; \ chown -R bw-operator /home/bw-operator; \ apk add gcc musl-dev libstdc++ gcompat=${GCOMPAT_VERSION} python3=${PYTHON_VERSION} py3-pip=${PIP_VERSION} libcrypto3=${LIBCRYPTO_VERSION}; \ - pip install -r /requirements.txt --no-warn-script-location; \ + pip install -r /requirements.txt --no-warn-script-location --break-system-packages; \ rm /requirements.txt; \ apk del --purge gcc musl-dev libstdc++; diff --git a/README.md b/README.md index 192b44d..3837aa7 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ And you are set to create your first secret using this operator. For that you ne ```yaml --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: BitwardenSecret metadata: name: name-of-your-management-object @@ -73,6 +73,8 @@ spec: id: "A Secret ID from bitwarden" name: "Name of the secret to be created" namespace: "Namespace of the secret to be created" + labels: # Optional + key: value ``` The ID can be extracted from the browser when you open a item the ID is in the URL. The resulting secret looks something like this: @@ -87,6 +89,8 @@ metadata: annotations: managed: bitwarden-secrets.lerentis.uploadfilter24.eu managedObject: bw-operator/test + labels: + key: value name: name-of-your-management-object namespace: default type: Opaque @@ -98,7 +102,7 @@ For managing registry credentials, or pull secrets, you can create another kind ```yaml --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: RegistryCredential metadata: name: name-of-your-management-object @@ -109,6 +113,8 @@ spec: id: "A Secret ID from bitwarden" name: "Name of the secret to be created" namespace: "Namespace of the secret to be created" + labels: # Optional + key: value ``` The resulting secret looks something like this: @@ -122,6 +128,8 @@ metadata: annotations: managed: bitwarden-secrets.lerentis.uploadfilter24.eu managedObject: bw-operator/test + labels: + key: value name: name-of-your-management-object namespace: default type: dockerconfigjson @@ -133,7 +141,7 @@ One of the more freely defined types that can be used with this operator you can ```yaml --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: BitwardenTemplate metadata: name: name-of-your-management-object @@ -141,6 +149,8 @@ spec: filename: "Key of the secret to be created" name: "Name of the secret to be created" namespace: "Namespace of the secret to be created" + labels: # Optional + key: value template: | --- api: @@ -164,6 +174,8 @@ metadata: annotations: managed: bitwarden-template.lerentis.uploadfilter24.eu managedObject: namespace/name-of-your-management-object + labels: + key: value name: Name of the secret to be created namespace: Namespace of the secret to be created type: Opaque diff --git a/charts/bitwarden-crd-operator/Chart.yaml b/charts/bitwarden-crd-operator/Chart.yaml index 0698174..9b0e50e 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.10.1" +version: "v0.11.0" -appVersion: "0.9.1" +appVersion: "0.10.0" keywords: - operator @@ -32,22 +32,22 @@ annotations: url: https://github.com/Lerentis/bitwarden-crd-operator artifacthub.io/crds: | - kind: BitwardenSecret - version: v1beta4 + version: v1beta5 name: bitwarden-secret displayName: Bitwarden Secret description: Management Object to create secrets from bitwarden - kind: RegistryCredential - version: v1beta4 + version: v1beta5 name: registry-credential displayName: Regestry Credentials description: Management Object to create regestry secrets from bitwarden - kind: BitwardenTemplate - version: v1beta1 + version: v1beta5 name: bitwarden-template displayName: Bitwarden Template description: Management Object to create secrets from a jinja template with a bitwarden lookup artifacthub.io/crdsExamples: | - - apiVersion: lerentis.uploadfilter24.eu/v1beta4 + - apiVersion: lerentis.uploadfilter24.eu/v1beta5 kind: BitwardenSecret metadata: name: test @@ -62,7 +62,9 @@ annotations: id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" name: "test-secret" namespace: "default" - - apiVersion: lerentis.uploadfilter24.eu/v1beta4 + labels: + key: value + - apiVersion: lerentis.uploadfilter24.eu/v1beta5 kind: RegistryCredential metadata: name: test @@ -73,7 +75,9 @@ annotations: id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" name: "test-regcred" namespace: "default" - - apiVersion: "lerentis.uploadfilter24.eu/v1beta4" + labels: + key: value + - apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: BitwardenTemplate metadata: name: test @@ -81,6 +85,8 @@ annotations: filename: "config.yaml" name: "test-regcred" namespace: "default" + labels: + key: value template: | --- api: @@ -95,8 +101,18 @@ annotations: artifacthub.io/operator: "true" artifacthub.io/containsSecurityUpdates: "false" artifacthub.io/changes: | - - kind: fixed - description: "Fixed type and content of RegistryCredential" + - kind: changed + description: "Added the possibility to add labels to generated secrets" + - kind: changed + description: "Updated Alpine to 3.19.0" + - kind: changed + description: "Update Python to 3.11.6-r1" + - kind: changed + description: "Update pip to 23.3.1-r0" + - kind: changed + description: "Update gcompat to 1.1.0-r4" + - kind: changed + description: "Update libcrypto3 to 3.1.4-r2" artifacthub.io/images: | - name: bitwarden-crd-operator - image: ghcr.io/lerentis/bitwarden-crd-operator:0.9.1 + image: ghcr.io/lerentis/bitwarden-crd-operator:0.10.0 diff --git a/charts/bitwarden-crd-operator/crds/bitwarden-secrets.yaml b/charts/bitwarden-crd-operator/crds/bitwarden-secrets.yaml index 4e420c9..52eb23d 100644 --- a/charts/bitwarden-crd-operator/crds/bitwarden-secrets.yaml +++ b/charts/bitwarden-crd-operator/crds/bitwarden-secrets.yaml @@ -15,7 +15,8 @@ spec: versions: - name: v1beta4 served: true - storage: true + storage: false + deprecated: true schema: openAPIV3Schema: type: object @@ -49,3 +50,42 @@ spec: - id - namespace - name + - name: v1beta5 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + content: + type: array + items: + type: object + properties: + element: + type: object + properties: + secretName: + type: string + secretRef: + type: string + secretScope: + type: string + required: + - secretName + id: + type: string + namespace: + type: string + name: + type: string + labels: + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - id + - namespace + - name diff --git a/charts/bitwarden-crd-operator/crds/bitwarden-templates.yaml b/charts/bitwarden-crd-operator/crds/bitwarden-templates.yaml index fa2212c..c85bcc5 100644 --- a/charts/bitwarden-crd-operator/crds/bitwarden-templates.yaml +++ b/charts/bitwarden-crd-operator/crds/bitwarden-templates.yaml @@ -15,7 +15,8 @@ spec: versions: - name: v1beta4 served: true - storage: true + storage: false + deprecated: true schema: openAPIV3Schema: type: object @@ -36,3 +37,29 @@ spec: - template - namespace - name + - name: v1beta5 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + filename: + type: string + template: + type: string + namespace: + type: string + name: + type: string + labels: + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - filename + - template + - namespace + - name diff --git a/charts/bitwarden-crd-operator/crds/registry-credentials.yaml b/charts/bitwarden-crd-operator/crds/registry-credentials.yaml index c3f4ffb..80cf6dc 100644 --- a/charts/bitwarden-crd-operator/crds/registry-credentials.yaml +++ b/charts/bitwarden-crd-operator/crds/registry-credentials.yaml @@ -15,7 +15,8 @@ spec: versions: - name: v1beta4 served: true - storage: true + storage: false + deprecated: true schema: openAPIV3Schema: type: object @@ -42,3 +43,35 @@ spec: - usernameRef - passwordRef - registry + - name: v1beta5 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + usernameRef: + type: string + passwordRef: + type: string + registry: + type: string + id: + type: string + namespace: + type: string + name: + type: string + labels: + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - id + - namespace + - name + - usernameRef + - passwordRef + - registry diff --git a/example.yaml b/example.yaml index 77cc22b..3de4bd3 100644 --- a/example.yaml +++ b/example.yaml @@ -1,5 +1,5 @@ --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: BitwardenSecret metadata: name: test @@ -16,8 +16,11 @@ spec: id: "88781348-c81c-4367-9801-550360c21295" name: "test-secret" namespace: "default" + labels: + key: value + app: example-app --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: BitwardenSecret metadata: name: test-scope diff --git a/example_dockerlogin.yaml b/example_dockerlogin.yaml index f5f12d0..3df8a96 100644 --- a/example_dockerlogin.yaml +++ b/example_dockerlogin.yaml @@ -1,5 +1,5 @@ --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: RegistryCredential metadata: name: test @@ -9,4 +9,7 @@ spec: registry: "docker.io" id: "3b249ec7-9ce7-440a-9558-f34f3ab10680" name: "test-regcred" - namespace: "default" \ No newline at end of file + namespace: "default" + labels: + namespace: default + tenant: example-team \ No newline at end of file diff --git a/example_template.yaml b/example_template.yaml index 646dc4a..b159d32 100644 --- a/example_template.yaml +++ b/example_template.yaml @@ -1,5 +1,5 @@ --- -apiVersion: "lerentis.uploadfilter24.eu/v1beta4" +apiVersion: "lerentis.uploadfilter24.eu/v1beta5" kind: BitwardenTemplate metadata: name: test @@ -7,6 +7,9 @@ spec: filename: "config.yaml" name: "test-template" namespace: "default" + labels: + key: value + app: example-app template: | --- api: diff --git a/src/dockerlogin.py b/src/dockerlogin.py index 880b991..7adba42 100644 --- a/src/dockerlogin.py +++ b/src/dockerlogin.py @@ -44,6 +44,7 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): id = spec.get('id') secret_name = spec.get('name') secret_namespace = spec.get('namespace') + labels = spec.get('labels') unlock_bw(logger) logger.info(f"Locking up secret with ID: {id}") @@ -55,9 +56,13 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): "managed": "registry-credential.lerentis.uploadfilter24.eu", "managedObject": f"{namespace}/{name}" } + + if not labels: + labels = {} + secret = kubernetes.client.V1Secret() secret.metadata = kubernetes.client.V1ObjectMeta( - name=secret_name, annotations=annotations) + name=secret_name, annotations=annotations, labels=labels) secret = create_dockerlogin( logger, secret, @@ -66,7 +71,7 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): password_ref, registry) - obj = api.create_namespaced_secret( + api.create_namespaced_secret( secret_namespace, secret ) @@ -91,6 +96,7 @@ def update_managed_registry_secret( id = spec.get('id') secret_name = spec.get('name') secret_namespace = spec.get('namespace') + labels = spec.get('labels') old_config = None old_secret_name = None @@ -127,9 +133,13 @@ def update_managed_registry_secret( "managed": "registry-credential.lerentis.uploadfilter24.eu", "managedObject": f"{namespace}/{name}" } + + if not labels: + labels = {} + secret = kubernetes.client.V1Secret() secret.metadata = kubernetes.client.V1ObjectMeta( - name=secret_name, annotations=annotations) + name=secret_name, annotations=annotations, labels=labels) secret = create_dockerlogin( logger, secret, @@ -138,7 +148,7 @@ def update_managed_registry_secret( password_ref, registry) try: - obj = api.replace_namespaced_secret( + api.replace_namespaced_secret( name=secret_name, body=secret, namespace="{}".format(secret_namespace)) diff --git a/src/kv.py b/src/kv.py index 5e976a7..f299cde 100644 --- a/src/kv.py +++ b/src/kv.py @@ -41,6 +41,7 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): id = spec.get('id') secret_name = spec.get('name') secret_namespace = spec.get('namespace') + labels = spec.get('labels') unlock_bw(logger) logger.info(f"Locking up secret with ID: {id}") @@ -52,12 +53,16 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): "managed": "bitwarden-secret.lerentis.uploadfilter24.eu", "managedObject": f"{namespace}/{name}" } + + if not labels: + labels = {} + secret = kubernetes.client.V1Secret() secret.metadata = kubernetes.client.V1ObjectMeta( - name=secret_name, annotations=annotations) + name=secret_name, annotations=annotations, labels=labels) secret = create_kv(secret, secret_json_object, content_def) - obj = api.create_namespaced_secret( + api.create_namespaced_secret( namespace="{}".format(secret_namespace), body=secret ) @@ -88,6 +93,7 @@ def update_managed_secret( old_secret_namespace = old_config['spec'].get('namespace') secret_name = spec.get('name') secret_namespace = spec.get('namespace') + labels = spec.get('labels') if old_config is not None and ( old_secret_name != secret_name or old_secret_namespace != secret_namespace): @@ -114,13 +120,16 @@ def update_managed_secret( "managedObject": f"{namespace}/{name}" } + if not labels: + labels = {} + secret = kubernetes.client.V1Secret() secret.metadata = kubernetes.client.V1ObjectMeta( - name=secret_name, annotations=annotations) + name=secret_name, annotations=annotations, labels=labels) secret = create_kv(secret, secret_json_object, content_def) try: - obj = api.replace_namespaced_secret( + api.replace_namespaced_secret( name=secret_name, body=secret, namespace="{}".format(secret_namespace)) diff --git a/src/template.py b/src/template.py index ed9622c..2654f0c 100644 --- a/src/template.py +++ b/src/template.py @@ -33,6 +33,7 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): filename = spec.get('filename') secret_name = spec.get('name') secret_namespace = spec.get('namespace') + labels = spec.get('labels') unlock_bw(logger) @@ -42,12 +43,16 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): "managed": "bitwarden-template.lerentis.uploadfilter24.eu", "managedObject": f"{namespace}/{name}" } + + if not labels: + labels = {} + secret = kubernetes.client.V1Secret() secret.metadata = kubernetes.client.V1ObjectMeta( - name=secret_name, annotations=annotations) + name=secret_name, annotations=annotations, labels=labels) secret = create_template_secret(logger, secret, filename, template) - obj = api.create_namespaced_secret( + api.create_namespaced_secret( secret_namespace, secret ) @@ -69,6 +74,7 @@ def update_managed_secret( filename = spec.get('filename') secret_name = spec.get('name') secret_namespace = spec.get('namespace') + labels = spec.get('labels') old_config = None old_secret_name = None @@ -103,13 +109,17 @@ def update_managed_secret( "managed": "bitwarden-template.lerentis.uploadfilter24.eu", "managedObject": f"{namespace}/{name}" } + + if not labels: + labels = {} + secret = kubernetes.client.V1Secret() secret.metadata = kubernetes.client.V1ObjectMeta( - name=secret_name, annotations=annotations) + name=secret_name, annotations=annotations, labels=labels) secret = create_template_secret(logger, secret, filename, template) try: - obj = api.replace_namespaced_secret( + api.replace_namespaced_secret( name=secret_name, body=secret, namespace="{}".format(secret_namespace))