Added custom secret type and attachment support for bitwardenSecret
This commit is contained in:
		| @@ -4,9 +4,9 @@ description: Deploy the Bitwarden CRD Operator | ||||
|  | ||||
| type: application | ||||
|  | ||||
| version: "v0.12.0" | ||||
| version: "v0.13.0" | ||||
|  | ||||
| appVersion: "0.11.0" | ||||
| appVersion: "0.12.0" | ||||
|  | ||||
| keywords: | ||||
|   - operator | ||||
| @@ -32,7 +32,7 @@ annotations: | ||||
|       url: https://github.com/Lerentis/bitwarden-crd-operator | ||||
|   artifacthub.io/crds: | | ||||
|     - kind: BitwardenSecret | ||||
|       version: v1beta6 | ||||
|       version: v1beta7 | ||||
|       name: bitwarden-secret | ||||
|       displayName: Bitwarden Secret | ||||
|       description: Management Object to create secrets from bitwarden | ||||
| @@ -47,8 +47,28 @@ annotations: | ||||
|       displayName: Bitwarden Template | ||||
|       description: Management Object to create secrets from a jinja template with a bitwarden lookup | ||||
|   artifacthub.io/crdsExamples: | | ||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta6 | ||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta7 | ||||
|       kind: BitwardenSecret | ||||
|       metadata: | ||||
|         name: test | ||||
|       spec: | ||||
|         content: | ||||
|           - element: | ||||
|               secretName: username | ||||
|               secretRef: nameofUser | ||||
|           - element: | ||||
|               secretName: password | ||||
|               secretRef: passwordOfUser | ||||
|         id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" | ||||
|         name: "test-secret" | ||||
|         secretType: Obaque | ||||
|         namespace: "default" | ||||
|         labels: | ||||
|           key: value | ||||
|         annotations: | ||||
|           key: value | ||||
|      - apiVersion: lerentis.uploadfilter24.eu/v1beta1 | ||||
|       kind: BitwardenTLSSecret | ||||
|       metadata: | ||||
|         name: test | ||||
|       spec: | ||||
| @@ -107,6 +127,8 @@ annotations: | ||||
|   artifacthub.io/operator: "true" | ||||
|   artifacthub.io/containsSecurityUpdates: "false" | ||||
|   artifacthub.io/changes: | | ||||
|     - kind: changed | ||||
|       description: "Allow custom type for generated secrets" | ||||
|     - kind: changed | ||||
|       description: "Update python to 3.11.9-r0" | ||||
|     - kind: changed | ||||
| @@ -125,4 +147,4 @@ annotations: | ||||
|       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.11.0 | ||||
|       image: ghcr.io/lerentis/bitwarden-crd-operator:0.12.0 | ||||
|   | ||||
| @@ -92,7 +92,8 @@ spec: | ||||
|                 - name | ||||
|     - name: v1beta6 | ||||
|       served: true | ||||
|       storage: true | ||||
|       storage: false | ||||
|       deprecated: true | ||||
|       schema: | ||||
|         openAPIV3Schema: | ||||
|           type: object | ||||
| @@ -128,6 +129,50 @@ spec: | ||||
|                 annotations: | ||||
|                   type: object | ||||
|                   x-kubernetes-preserve-unknown-fields: true | ||||
|               required: | ||||
|                 - id | ||||
|                 - namespace | ||||
|                 - name | ||||
|     - name: v1beta7 | ||||
|       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 | ||||
|                 secretType:  | ||||
|                   type: string | ||||
|                 labels: | ||||
|                   type: object | ||||
|                   x-kubernetes-preserve-unknown-fields: true | ||||
|                 annotations: | ||||
|                   type: object | ||||
|                   x-kubernetes-preserve-unknown-fields: true | ||||
|               required: | ||||
|                 - id | ||||
|                 - namespace | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| --- | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta6" | ||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||
| kind: BitwardenSecret | ||||
| metadata: | ||||
|   name: test | ||||
| @@ -16,6 +16,7 @@ spec: | ||||
|         secretScope: login | ||||
|   id: "88781348-c81c-4367-9801-550360c21295" | ||||
|   name: "test-secret" | ||||
|   secretType: Opaque | ||||
|   namespace: "default" | ||||
|   labels: | ||||
|     key: value | ||||
|   | ||||
| @@ -14,4 +14,4 @@ deploy: | ||||
|         chartPath: charts/bitwarden-crd-operator | ||||
|         valuesFiles: | ||||
|           - env/values.yaml | ||||
|         version: v0.7.4 | ||||
|         version: v0.13.0 | ||||
|   | ||||
							
								
								
									
										32
									
								
								src/kv.py
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/kv.py
									
									
									
									
									
								
							| @@ -3,10 +3,9 @@ import kubernetes | ||||
| import base64 | ||||
| import json | ||||
|  | ||||
| from utils.utils import unlock_bw, get_secret_from_bitwarden, parse_login_scope, parse_fields_scope, bw_sync_interval | ||||
| from utils.utils import unlock_bw, get_secret_from_bitwarden, parse_login_scope, parse_fields_scope, get_attachment, bw_sync_interval | ||||
|  | ||||
| def create_kv(secret, secret_json, content_def): | ||||
|     secret.type = "Opaque" | ||||
| def create_kv(logger, id, secret, secret_json, content_def): | ||||
|     secret.data = {} | ||||
|     for eleml in content_def: | ||||
|         for k, elem in eleml.items(): | ||||
| @@ -31,6 +30,13 @@ def create_kv(secret, secret_json, content_def): | ||||
|                         f"Field {_secret_key} has no value in bitwarden secret") | ||||
|                 secret.data[_secret_ref] = str(base64.b64encode( | ||||
|                     value.encode("utf-8")), "utf-8") | ||||
|             if _secret_scope == "attachment": | ||||
|                 value = get_attachment(logger, id, _secret_key) | ||||
|                 if value is None: | ||||
|                     raise Exception( | ||||
|                         f"Attachment {_secret_key} has no value in bitwarden secret") | ||||
|                 secret.data[_secret_ref] = str(base64.b64encode( | ||||
|                     value.encode("utf-8")), "utf-8") | ||||
|     return secret | ||||
|  | ||||
|  | ||||
| @@ -43,6 +49,7 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|     custom_secret_type = spec.get('secretType') | ||||
|  | ||||
|     unlock_bw(logger) | ||||
|     logger.info(f"Locking up secret with ID: {id}") | ||||
| @@ -58,13 +65,17 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | ||||
|     if custom_annotations: | ||||
|         annotations.update(custom_annotations) | ||||
|  | ||||
|     if not custom_secret_type: | ||||
|         custom_secret_type = 'Opaque' | ||||
|  | ||||
|     if not labels: | ||||
|         labels = {} | ||||
|  | ||||
|     secret = kubernetes.client.V1Secret() | ||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||
|         name=secret_name, annotations=annotations, labels=labels) | ||||
|     secret = create_kv(secret, secret_json_object, content_def) | ||||
|     secret.type = custom_secret_type | ||||
|     secret = create_kv(logger, id, 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 | ||||
| @@ -95,21 +106,27 @@ def update_managed_secret( | ||||
|     old_config = None | ||||
|     old_secret_name = None | ||||
|     old_secret_namespace = None | ||||
|     old_secret_type = None | ||||
|     if 'kopf.zalando.org/last-handled-configuration' in body.metadata.annotations: | ||||
|         old_config = json.loads( | ||||
|             body.metadata.annotations['kopf.zalando.org/last-handled-configuration']) | ||||
|         old_secret_name = old_config['spec'].get('name') | ||||
|         old_secret_namespace = old_config['spec'].get('namespace') | ||||
|         old_secret_type = old_config['spec'].get('type') | ||||
|     secret_name = spec.get('name') | ||||
|     secret_namespace = spec.get('namespace') | ||||
|     labels = spec.get('labels') | ||||
|     custom_annotations = spec.get('annotations') | ||||
|     custom_secret_type = spec.get('secretType') | ||||
|  | ||||
|     if not custom_secret_type: | ||||
|         custom_secret_type = 'Opaque' | ||||
|  | ||||
|     if old_config is not None and ( | ||||
|             old_secret_name != secret_name or old_secret_namespace != secret_namespace): | ||||
|             old_secret_name != secret_name or old_secret_namespace != secret_namespace or old_secret_type != custom_secret_type): | ||||
|         # If the name of the secret or the namespace of the secret is different | ||||
|         # We have to delete the secret an recreate it | ||||
|         logger.info("Secret name or namespace changed, let's recreate it") | ||||
|         logger.info("Secret name, namespace or type changed, let's recreate it") | ||||
|         delete_managed_secret( | ||||
|             old_config['spec'], | ||||
|             name, | ||||
| @@ -139,7 +156,8 @@ def update_managed_secret( | ||||
|     secret = kubernetes.client.V1Secret() | ||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||
|         name=secret_name, annotations=annotations, labels=labels) | ||||
|     secret = create_kv(secret, secret_json_object, content_def) | ||||
|     secret.type = custom_secret_type | ||||
|     secret = create_kv(logger, id, 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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user