]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/smb: add a new tls credential resource type
authorJohn Mulligan <jmulligan@redhat.com>
Wed, 2 Jul 2025 21:44:45 +0000 (17:44 -0400)
committerAdam King <adking@redhat.com>
Thu, 21 Aug 2025 18:13:55 +0000 (14:13 -0400)
Add a new TLS credential resource type that can currently store one
TLS certificate, TLS key, or TLS CA certificate. This is a new top-level
resource so that they can be use across clusters or managed
independently by different people and or private information can be kept
out a cluster resource stored in a file committed somewhere.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
(cherry picked from commit 173b538c2b520867dc2103be4ff91a66f0cbf76f)

src/pybind/mgr/smb/resources.py

index b00c20b9ca48eca57021279b7c2a2adeeaac5891..1320619650bf9a765a530639cbbf370f184aa09e 100644 (file)
@@ -1,6 +1,7 @@
 from typing import Dict, List, Optional, Tuple, Union, cast
 
 import base64
+import dataclasses
 import errno
 import json
 
@@ -24,6 +25,7 @@ from .enums import (
     LoginCategory,
     PasswordFilter,
     SMBClustering,
+    TLSCredentialType,
     UserGroupSourceType,
 )
 from .proto import Self, Simplified
@@ -623,6 +625,50 @@ class UsersAndGroups(_RBase):
         )
 
 
+@resourcelib.resource('ceph.smb.tls.credential')
+class TLSCredential(_RBase):
+    """Contains a TLS certificate or key that can be used to configure
+    SMB services that make use of TLS/SSL.
+    """
+
+    tls_credential_id: str
+    intent: Intent = Intent.PRESENT
+    credential_type: Optional[TLSCredentialType] = None
+    value: Optional[str] = None
+    # linked resources can only be used by the resource they are linked to
+    # and are automatically removed when the "parent" resource is removed
+    linked_to_cluster: Optional[str] = None
+
+    def validate(self) -> None:
+        if not self.tls_credential_id:
+            raise ValueError('tls_credential_id requires a value')
+        validation.check_id(self.tls_credential_id)
+        if self.linked_to_cluster is not None:
+            validation.check_id(self.linked_to_cluster)
+        if self.intent is Intent.PRESENT:
+            if self.credential_type is None:
+                raise ValueError('credential_type must be specified')
+            if not self.value:
+                raise ValueError('a value must be specified')
+
+    @resourcelib.customize
+    def _customize_resource(rc: resourcelib.Resource) -> resourcelib.Resource:
+        rc.value.wrapper_type = BigString
+        return rc
+
+    def convert(self, operation: ConversionOp) -> Self:
+        """When hiding sensitive data hide TLS/SSL certs too. However, the
+        BASE64 filter enum will act as a no-op. Our certs are already long
+        Base64 encoded strings that are resistant to casual shoulder-surfing.
+        """
+        if (
+            operation == (PasswordFilter.NONE, PasswordFilter.HIDDEN)
+            and self.value
+        ):
+            return dataclasses.replace(self, value=_MASKED)
+        return self
+
+
 # SMBResource is a union of all valid top-level smb resource types.
 SMBResource = Union[
     Cluster,
@@ -631,6 +677,7 @@ SMBResource = Union[
     RemovedShare,
     Share,
     UsersAndGroups,
+    TLSCredential,
 ]