Merge pull request #82 from Lerentis/feature/tt/ownership-and-annotations
Set Ownership and allow custom Annotations
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -36,7 +36,7 @@ jobs: | ||||
|           CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||||
|  | ||||
|       - name: Get app version from chart | ||||
|         uses: mikefarah/yq@v4.43.1 | ||||
|         uses: mikefarah/yq@v4.44.1 | ||||
|         id: app_version | ||||
|         with: | ||||
|           cmd: yq '.appVersion' charts/bitwarden-crd-operator/Chart.yaml | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| FROM alpine:3.19.0 | ||||
| FROM alpine:3.19.1 | ||||
|  | ||||
| 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.8-r0 | ||||
| ARG PYTHON_VERSION=3.11.9-r0 | ||||
| ARG PIP_VERSION=23.3.1-r0 | ||||
| ARG GCOMPAT_VERSION=1.1.0-r4 | ||||
| ARG LIBCRYPTO_VERSION=3.1.4-r2 | ||||
| ARG LIBCRYPTO_VERSION=3.1.4-r5 | ||||
| ARG BW_VERSION=2023.7.0 | ||||
| ARG NODE_VERSION=20.11.1-r0 | ||||
| ARG NODE_VERSION=20.12.1-r0 | ||||
|  | ||||
| COPY requirements.txt /requirements.txt | ||||
|  | ||||
|   | ||||
| @@ -4,9 +4,9 @@ description: Deploy the Bitwarden CRD Operator | ||||
|  | ||||
| type: application | ||||
|  | ||||
| version: "v0.11.3" | ||||
| version: "v0.12.0" | ||||
|  | ||||
| appVersion: "0.10.3" | ||||
| appVersion: "0.11.0" | ||||
|  | ||||
| keywords: | ||||
|   - operator | ||||
| @@ -32,22 +32,22 @@ annotations: | ||||
|       url: https://github.com/Lerentis/bitwarden-crd-operator | ||||
|   artifacthub.io/crds: | | ||||
|     - kind: BitwardenSecret | ||||
|       version: v1beta5 | ||||
|       version: v1beta6 | ||||
|       name: bitwarden-secret | ||||
|       displayName: Bitwarden Secret | ||||
|       description: Management Object to create secrets from bitwarden | ||||
|     - kind: RegistryCredential | ||||
|       version: v1beta5 | ||||
|       version: v1beta6 | ||||
|       name: registry-credential | ||||
|       displayName: Regestry Credentials | ||||
|       description: Management Object to create regestry secrets from bitwarden | ||||
|     - kind: BitwardenTemplate | ||||
|       version: v1beta5 | ||||
|       version: v1beta6 | ||||
|       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/v1beta5 | ||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta6 | ||||
|       kind: BitwardenSecret | ||||
|       metadata: | ||||
|         name: test | ||||
| @@ -64,7 +64,9 @@ annotations: | ||||
|         namespace: "default" | ||||
|         labels: | ||||
|           key: value | ||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta5 | ||||
|         annotations: | ||||
|           key: value | ||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta6 | ||||
|       kind: RegistryCredential | ||||
|       metadata: | ||||
|         name: test | ||||
| @@ -77,7 +79,9 @@ annotations: | ||||
|         namespace: "default" | ||||
|         labels: | ||||
|           key: value | ||||
|     - apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | ||||
|         annotations: | ||||
|           key: value | ||||
|     - apiVersion: "lerentis.uploadfilter24.eu/v1beta6" | ||||
|       kind: BitwardenTemplate | ||||
|       metadata: | ||||
|         name: test | ||||
| @@ -87,6 +91,8 @@ annotations: | ||||
|         namespace: "default" | ||||
|         labels: | ||||
|           key: value | ||||
|         annotations: | ||||
|           key: value | ||||
|         template: | | ||||
|           --- | ||||
|           api: | ||||
| @@ -102,11 +108,21 @@ annotations: | ||||
|   artifacthub.io/containsSecurityUpdates: "false" | ||||
|   artifacthub.io/changes: | | ||||
|     - kind: changed | ||||
|       description: "Update python to 3.11.8-r0" | ||||
|       description: "Update python to 3.11.9-r0" | ||||
|     - kind: changed | ||||
|       description: "Update Node to 20.11.1-r0" | ||||
|       description: "Update Node to 20.12.1-r0" | ||||
|     - kind: changed | ||||
|       description: "Unified bw cli installation methode" | ||||
|       description: "Update libcrypto3 to 3.1.4-r5" | ||||
|     - kind: changed | ||||
|       description: "Update alpine to 3.19.1" | ||||
|     - kind: changed | ||||
|       description: "Update kopf to 1.37.2" | ||||
|     - kind: changed | ||||
|       description: "Update jinja to 3.1.4" | ||||
|     - kind: added | ||||
|       description: "Allow custom annotations to generated secrets" | ||||
|     - kind: added | ||||
|       description: "Set ownership of generated secrets if CRD is in the same namespace" | ||||
|   artifacthub.io/images: | | ||||
|     - name: bitwarden-crd-operator | ||||
|       image: ghcr.io/lerentis/bitwarden-crd-operator:0.10.3 | ||||
|       image: ghcr.io/lerentis/bitwarden-crd-operator:0.11.0 | ||||
|   | ||||
| @@ -52,7 +52,8 @@ spec: | ||||
|                 - name | ||||
|     - name: v1beta5 | ||||
|       served: true | ||||
|       storage: true | ||||
|       storage: false | ||||
|       deprecated: true | ||||
|       schema: | ||||
|         openAPIV3Schema: | ||||
|           type: object | ||||
| @@ -89,3 +90,45 @@ spec: | ||||
|                 - id | ||||
|                 - namespace | ||||
|                 - name | ||||
|     - name: v1beta6 | ||||
|       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 | ||||
|                 annotations: | ||||
|                   type: object | ||||
|                   x-kubernetes-preserve-unknown-fields: true | ||||
|               required: | ||||
|                 - id | ||||
|                 - namespace | ||||
|                 - name | ||||
| @@ -39,7 +39,8 @@ spec: | ||||
|                 - name | ||||
|     - name: v1beta5 | ||||
|       served: true | ||||
|       storage: true | ||||
|       storage: false | ||||
|       deprecated: true | ||||
|       schema: | ||||
|         openAPIV3Schema: | ||||
|           type: object | ||||
| @@ -63,3 +64,32 @@ spec: | ||||
|                 - template | ||||
|                 - namespace | ||||
|                 - name | ||||
|     - name: v1beta6 | ||||
|       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 | ||||
|                 annotations: | ||||
|                   type: object | ||||
|                   x-kubernetes-preserve-unknown-fields: true | ||||
|               required: | ||||
|                 - filename | ||||
|                 - template | ||||
|                 - namespace | ||||
|                 - name | ||||
|   | ||||
| @@ -45,7 +45,8 @@ spec: | ||||
|                 - registry | ||||
|     - name: v1beta5 | ||||
|       served: true | ||||
|       storage: true | ||||
|       storage: false | ||||
|       deprecated: true | ||||
|       schema: | ||||
|         openAPIV3Schema: | ||||
|           type: object | ||||
| @@ -75,3 +76,38 @@ spec: | ||||
|                 - usernameRef | ||||
|                 - passwordRef | ||||
|                 - registry | ||||
|     - name: v1beta6 | ||||
|       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 | ||||
|                 annotations: | ||||
|                   type: object | ||||
|                   x-kubernetes-preserve-unknown-fields: true | ||||
|               required: | ||||
|                 - id | ||||
|                 - namespace | ||||
|                 - name | ||||
|                 - usernameRef | ||||
|                 - passwordRef | ||||
|                 - registry | ||||
|   | ||||
| @@ -8,6 +8,8 @@ spec: | ||||
|   {{- if not .Values.autoscaling.enabled }} | ||||
|   replicas: {{ .Values.replicaCount }} | ||||
|   {{- end }} | ||||
|   strategy:  | ||||
|     type: {{ .Values.deploymentStrategy }} | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       {{- include "bitwarden-crd-operator.selectorLabels" . | nindent 6 }} | ||||
|   | ||||
| @@ -14,6 +14,8 @@ imagePullSecrets: [] | ||||
| nameOverride: "" | ||||
| fullnameOverride: "" | ||||
|  | ||||
| deploymentStrategy: "Recreate" | ||||
|  | ||||
| # env: | ||||
| #   - name: BW_FORCE_SYNC | ||||
| #     value: "false" | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| --- | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta6" | ||||
| kind: BitwardenSecret | ||||
| metadata: | ||||
|   name: test | ||||
|   namespace: default | ||||
| spec: | ||||
|   content: | ||||
|     - element: | ||||
| @@ -19,8 +20,10 @@ spec: | ||||
|   labels: | ||||
|     key: value | ||||
|     app: example-app | ||||
|   annotations: | ||||
|     custom.annotation: is-used | ||||
| --- | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta6" | ||||
| kind: BitwardenSecret | ||||
| metadata: | ||||
|   name: test-scope | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta6" | ||||
| kind: RegistryCredential | ||||
| metadata: | ||||
|   name: test | ||||
| @@ -13,3 +13,5 @@ spec: | ||||
|   labels: | ||||
|     namespace: default | ||||
|     tenant: example-team | ||||
|   annotations: | ||||
|     custom.annotation: is-used | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta6" | ||||
| kind: BitwardenTemplate | ||||
| metadata: | ||||
|   name: test | ||||
| @@ -10,6 +10,8 @@ spec: | ||||
|   labels: | ||||
|     key: value | ||||
|     app: example-app | ||||
|   annotations: | ||||
|     custom.annotation: is-used | ||||
|   template: | | ||||
|     --- | ||||
|     api: | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| kopf==1.37.1 | ||||
| kopf==1.37.2 | ||||
| kubernetes==29.0.0 | ||||
| Jinja2==3.1.3 | ||||
| Jinja2==3.1.4 | ||||
| schedule==1.2.1 | ||||
| @@ -45,6 +45,7 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|  | ||||
|     unlock_bw(logger) | ||||
|     logger.info(f"Locking up secret with ID: {id}") | ||||
| @@ -57,6 +58,9 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): | ||||
|         "managedObject": f"{namespace}/{name}" | ||||
|     } | ||||
|  | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
| @@ -71,6 +75,11 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): | ||||
|         password_ref, | ||||
|         registry) | ||||
|      | ||||
|     # Garbage collection will delete the generated secret if the owner | ||||
|     # Is not in the same namespace as the generated secret | ||||
|     if secret_namespace == namespace: | ||||
|         kopf.append_owner_reference(secret) | ||||
|  | ||||
|     api.create_namespaced_secret( | ||||
|         secret_namespace, secret | ||||
|     ) | ||||
| @@ -97,6 +106,7 @@ def update_managed_registry_secret( | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|  | ||||
|     old_config = None | ||||
|     old_secret_name = None | ||||
| @@ -134,6 +144,9 @@ def update_managed_registry_secret( | ||||
|         "managedObject": f"{namespace}/{name}" | ||||
|     } | ||||
|  | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
| @@ -147,6 +160,12 @@ def update_managed_registry_secret( | ||||
|         username_ref, | ||||
|         password_ref, | ||||
|         registry) | ||||
|      | ||||
|     # Garbage collection will delete the generated secret if the owner | ||||
|     # Is not in the same namespace as the generated secret | ||||
|     if secret_namespace == namespace: | ||||
|         kopf.append_owner_reference(secret) | ||||
|  | ||||
|     try: | ||||
|         api.replace_namespaced_secret( | ||||
|             name=secret_name, | ||||
| @@ -154,9 +173,12 @@ def update_managed_registry_secret( | ||||
|             namespace="{}".format(secret_namespace)) | ||||
|         logger.info( | ||||
|             f"Secret {secret_namespace}/{secret_name} has been updated") | ||||
|     except BaseException: | ||||
|     except BaseException as e: | ||||
|         logger.warn( | ||||
|             f"Could not update secret {secret_namespace}/{secret_name}!") | ||||
|         logger.warn( | ||||
|             f"Exception: {e}" | ||||
|         ) | ||||
|  | ||||
|  | ||||
| @kopf.on.delete('registry-credential.lerentis.uploadfilter24.eu') | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/kv.py
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/kv.py
									
									
									
									
									
								
							| @@ -42,6 +42,7 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|  | ||||
|     unlock_bw(logger) | ||||
|     logger.info(f"Locking up secret with ID: {id}") | ||||
| @@ -54,6 +55,9 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|         "managedObject": f"{namespace}/{name}" | ||||
|     } | ||||
|  | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
| @@ -62,6 +66,11 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|         name=secret_name, annotations=annotations, labels=labels) | ||||
|     secret = create_kv(secret, secret_json_object, content_def) | ||||
|  | ||||
|     # Garbage collection will delete the generated secret if the owner | ||||
|     # Is not in the same namespace as the generated secret | ||||
|     if secret_namespace == namespace: | ||||
|         kopf.append_owner_reference(secret) | ||||
|  | ||||
|     api.create_namespaced_secret( | ||||
|         namespace="{}".format(secret_namespace), | ||||
|         body=secret | ||||
| @@ -94,6 +103,7 @@ def update_managed_secret( | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|  | ||||
|     if old_config is not None and ( | ||||
|             old_secret_name != secret_name or old_secret_namespace != secret_namespace): | ||||
| @@ -120,6 +130,9 @@ def update_managed_secret( | ||||
|         "managedObject": f"{namespace}/{name}" | ||||
|     } | ||||
|  | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
| @@ -128,6 +141,11 @@ def update_managed_secret( | ||||
|         name=secret_name, annotations=annotations, labels=labels) | ||||
|     secret = create_kv(secret, secret_json_object, content_def) | ||||
|  | ||||
|     # Garbage collection will delete the generated secret if the owner | ||||
|     # Is not in the same namespace as the generated secret | ||||
|     if secret_namespace == namespace: | ||||
|         kopf.append_owner_reference(secret) | ||||
|  | ||||
|     try: | ||||
|         api.replace_namespaced_secret( | ||||
|             name=secret_name, | ||||
| @@ -135,9 +153,12 @@ def update_managed_secret( | ||||
|             namespace="{}".format(secret_namespace)) | ||||
|         logger.info( | ||||
|             f"Secret {secret_namespace}/{secret_name} has been updated") | ||||
|     except BaseException: | ||||
|     except BaseException as e: | ||||
|         logger.warn( | ||||
|             f"Could not update secret {secret_namespace}/{secret_name}!") | ||||
|         logger.warn( | ||||
|             f"Exception: {e}" | ||||
|         ) | ||||
|  | ||||
|  | ||||
| @kopf.on.delete('bitwarden-secret.lerentis.uploadfilter24.eu') | ||||
|   | ||||
| @@ -34,6 +34,7 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|  | ||||
|     unlock_bw(logger) | ||||
|  | ||||
| @@ -44,6 +45,9 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|         "managedObject": f"{namespace}/{name}" | ||||
|     } | ||||
|  | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
| @@ -52,6 +56,11 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|         name=secret_name, annotations=annotations, labels=labels) | ||||
|     secret = create_template_secret(logger, secret, filename, template) | ||||
|  | ||||
|     # Garbage collection will delete the generated secret if the owner | ||||
|     # Is not in the same namespace as the generated secret | ||||
|     if secret_namespace == namespace: | ||||
|         kopf.append_owner_reference(secret) | ||||
|  | ||||
|     api.create_namespaced_secret( | ||||
|         secret_namespace, secret | ||||
|     ) | ||||
| @@ -75,6 +84,7 @@ def update_managed_secret( | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|  | ||||
|     old_config = None | ||||
|     old_secret_name = None | ||||
| @@ -110,6 +120,9 @@ def update_managed_secret( | ||||
|         "managedObject": f"{namespace}/{name}" | ||||
|     } | ||||
|  | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
| @@ -118,6 +131,11 @@ def update_managed_secret( | ||||
|         name=secret_name, annotations=annotations, labels=labels) | ||||
|     secret = create_template_secret(logger, secret, filename, template) | ||||
|  | ||||
|     # Garbage collection will delete the generated secret if the owner | ||||
|     # Is not in the same namespace as the generated secret | ||||
|     if secret_namespace == namespace: | ||||
|         kopf.append_owner_reference(secret) | ||||
|  | ||||
|     try: | ||||
|         api.replace_namespaced_secret( | ||||
|             name=secret_name, | ||||
| @@ -125,9 +143,12 @@ def update_managed_secret( | ||||
|             namespace="{}".format(secret_namespace)) | ||||
|         logger.info( | ||||
|             f"Secret {secret_namespace}/{secret_name} has been updated") | ||||
|     except BaseException: | ||||
|     except BaseException as e: | ||||
|         logger.warn( | ||||
|             f"Could not update secret {secret_namespace}/{secret_name}!") | ||||
|         logger.warn( | ||||
|             f"Exception: {e}" | ||||
|         ) | ||||
|  | ||||
|  | ||||
| @kopf.on.delete('bitwarden-template.lerentis.uploadfilter24.eu') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user