diff --git a/operator/bitwardensyncconfig.py b/operator/bitwardensyncconfig.py index 9646734..68ad2ce 100644 --- a/operator/bitwardensyncconfig.py +++ b/operator/bitwardensyncconfig.py @@ -55,6 +55,7 @@ def secrets(self): BitwardenSyncConfigSecret(item) for item in self.spec.get("secrets", []) ] + # DEPRECATED - The sync config label now uses uid to avoid name length issues. @property def sync_config_value(self): return f"{self.namespace}.{self.name}" diff --git a/operator/bitwardensyncsecret.py b/operator/bitwardensyncsecret.py index d879938..5e3bb84 100644 --- a/operator/bitwardensyncsecret.py +++ b/operator/bitwardensyncsecret.py @@ -79,6 +79,7 @@ def secret_labels(self): for key, value in self.spec.get('labels', {}).items() } + # DEPRECATED - The sync config label now uses uid to avoid name length issues. @property def sync_config_value(self): return f"{self.namespace}.{self.name}" @@ -87,35 +88,6 @@ def sync_config_value(self): def type(self): return self.spec.get('type', 'Opaque') - async def check_delete_secret(self): - secret = None - try: - secret = await K8sUtil.core_v1_api.read_namespaced_secret( - name = self.name, - namespace = self.namespace, - ) - except kubernetes_asyncio.client.rest.ApiException as err: - if err.status == 404: - return None, None - raise - - if ( - not secret.metadata.labels or - secret.metadata.labels['app.kubernetes.io/managed-by'] != 'bitwarden-k8s-secrets-manager' or - secret.metadata.labels[K8sUtil.sync_config_label] != self.sync_config_value - ): - return secret, False - - try: - secret = await K8sUtil.core_v1_api.delete_namespaced_secret( - name = self.name, - namespace = self.namespace, - ) - except kubernetes_asyncio.client.rest.ApiException as err: - if err.status != 404: - raise - return secret, True - async def handle_delete(self, logger): await check_delete_secret( managed_by=self, diff --git a/operator/bitwardensyncutil.py b/operator/bitwardensyncutil.py index e49b94b..6abf6ea 100644 --- a/operator/bitwardensyncutil.py +++ b/operator/bitwardensyncutil.py @@ -1,4 +1,5 @@ from base64 import b64encode +import json import kubernetes_asyncio @@ -27,12 +28,15 @@ async def check_delete_secret( if ( not secret.metadata.labels or secret.metadata.labels['app.kubernetes.io/managed-by'] != 'bitwarden-k8s-secrets-manager' or - secret.metadata.labels[K8sUtil.sync_config_label] != managed_by.sync_config_value + # DEPRECATED - sync_config_value, retain support for compatibility + ( + secret.metadata.labels[K8sUtil.sync_config_label] != managed_by.sync_config_value and + secret.metadata.labels[K8sUtil.sync_config_label] != managed_by.uid + ) ): logger.warning( f"Did not delete Secret {name} in {namespace} for {managed_by}: " - f"{K8sUtil.sync_config_label} label \"{secret.metadata.labels[K8sUtil.sync_config_label]}\" " - f"!= {managed_by.sync_config_value}" + f"{K8sUtil.sync_config_label} label value mismatch" ) return @@ -62,14 +66,21 @@ async def manage_secret( sources=secret_config.secret_data, projects=bitwarden_projects, ).items() } + annotations = bitwarden_secrets.get_values( sources=secret_config.secret_annotations, projects=bitwarden_projects, ) + annotations[K8sUtil.sync_config_label] = json.dumps({ + "kind": managed_by.kind, + "name": managed_by.name, + "namespace": managed_by.namespace, + }) + labels = bitwarden_secrets.get_values( sources=secret_config.secret_labels, projects=bitwarden_projects, ) labels['app.kubernetes.io/managed-by'] = 'bitwarden-k8s-secrets-manager' - labels[K8sUtil.sync_config_label] = managed_by.sync_config_value + labels[K8sUtil.sync_config_label] = managed_by.uid secret = None try: @@ -94,11 +105,14 @@ async def manage_secret( if ( secret.metadata.labels and K8sUtil.sync_config_label in secret.metadata.labels and - secret.metadata.labels[K8sUtil.sync_config_label] != managed_by.sync_config_value + # DEPRECATED - sync_config_value, retain support for compatibility + ( + secret.metadata.labels[K8sUtil.sync_config_label] != managed_by.sync_config_value and + secret.metadata.labels[K8sUtil.sync_config_label] != managed_by.uid + ) ): - managed_by_namespace, managed_by_name = secret.metadata.labels[K8sUtil.sync_config_label].split('.') raise BitwardenSyncError( - f"Secret {name} in {namespace} is managed by BitwardenSyncConfig {managed_by_name} in {managed_by_namespace}" + f"Secret {name} in {namespace} is managed by other BitwardenSyncConfig or BitwardenSyncSecret" ) if ( diff --git a/operator/k8sutil.py b/operator/k8sutil.py index 29c8dfd..29b1eea 100644 --- a/operator/k8sutil.py +++ b/operator/k8sutil.py @@ -51,7 +51,7 @@ class K8sObject: # Disable pylint warnings for properties which must be declared in subclass # pylint: disable=no-member - def __init__(self, annotations, labels, meta, name, namespace, spec, status, **_): + def __init__(self, annotations, labels, meta, name, namespace, spec, status, uid, **_): """ Initalize object from kopf keywords args """ @@ -62,6 +62,7 @@ def __init__(self, annotations, labels, meta, name, namespace, spec, status, **_ self.namespace = namespace self.spec = spec self.status = status + self.uid = uid def __str__(self): """ @@ -133,23 +134,15 @@ class CachedK8sObject(K8sObject): # Disable pylint warning for cache, which must be declared in subclass # pylint: disable=no-member - def __init__(self, annotations, labels, meta, name, namespace, spec, status, **_): + def __init__(self, **kwargs): """ Initalize object from kopf keywords args and add asyncio lock. """ - super().__init__( - annotations = annotations, - labels = labels, - meta = meta, - name = name, - namespace = namespace, - spec = spec, - status = status, - ) + super().__init__(**kwargs) self.lock = asyncio.Lock() @classmethod - def register(cls, annotations, labels, meta, name, namespace, spec, status, **_): + def register(cls, annotations, labels, meta, name, namespace, spec, status, uid, **_): """ Ceating object in cashe or updating existing from kopf keyword args """ @@ -169,6 +162,7 @@ def register(cls, annotations, labels, meta, name, namespace, spec, status, **_) namespace = namespace, spec = spec, status = status, + uid = uid, ) cls.cache[(namespace, name)] = obj return obj