Skip to content

feat: Management Access utilities - #1290

Open
labrenbe wants to merge 23 commits into
mainfrom
feat/platform-access
Open

labrenbe wants to merge 23 commits into
mainfrom
feat/platform-access

Conversation

@labrenbe

@labrenbe labrenbe commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Description

Adds shared utilities required for stackabletech/kafka-operator#1028.

  • labels and selectors for agents
  • new enum for platform access with TLS

Depends on https://github.com/stackabletech/decisions/issues/98 and https://github.com/stackabletech/decisions/issues/99.

Definition of Done Checklist

  • Not all of these items are applicable to all PRs, the author should update this template to only leave the boxes in that are relevant
  • Please make sure all these things are done and tick the boxes

Author

  • Changes are OpenShift compatible
  • CRD changes approved
  • CRD documentation for all fields, following the style guide.
  • Integration tests passed (for non trivial changes)
  • Changes need to be "offline" compatible

Reviewer

  • Code contains useful comments
  • Code contains useful logging statements
  • (Integration-)Test cases added
  • Documentation added or updated. Follows the style guide.
  • Changelog updated
  • Cargo.toml only contains references to git tags (not specific commits or branches)

Acceptance

  • Feature Tracker has been updated
  • Proper release label has been added

@labrenbe labrenbe self-assigned this Oct 1, 2026
@labrenbe
labrenbe force-pushed the feat/platform-access branch from c3e3121 to 3be4832 Compare October 1, 2026 12:09
@labrenbe
labrenbe force-pushed the feat/platform-access branch from 3be4832 to 7cb677e Compare October 1, 2026 12:12
Comment thread crates/stackable-agent/src/condition.rs
Comment thread crates/stackable-operator/src/crd/platform_access/tls/v1alpha1_impl.rs Outdated
Comment thread crates/stackable-operator/src/v2/kvp/label.rs Outdated
Comment thread crates/stackable-operator/src/commons/management_access/condition.rs Outdated
Comment thread crates/stackable-operator/src/crd/management_access/tls/v1alpha1_impl.rs Outdated
Comment thread crates/stackable-operator/src/commons/platform_access/ownership.rs Outdated
Comment thread crates/stackable-operator/src/commons/management_access/condition.rs Outdated
Comment thread crates/stackable-operator/src/commons/platform_access/ownership.rs Outdated
Comment thread crates/stackable-operator/src/commons/platform_access/ownership.rs Outdated
@labrenbe labrenbe changed the title feat: Platform Access utilities feat: Management Access utilities Oct 23, 2026
@labrenbe
labrenbe force-pushed the feat/platform-access branch from 586debd to 22536cd Compare October 23, 2026 16:06
@labrenbe
labrenbe marked this pull request as ready for review October 23, 2026 16:34
@labrenbe labrenbe moved this to Development: Waiting for Review in Stackable Engineering Oct 23, 2026
@labrenbe labrenbe moved this from Development: Waiting for Review to Development: In Review in Stackable Engineering Oct 23, 2026
Retain,

/// Delete the resource in the product.
Delete,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question regarding a specific scenario: I guess it would be possible for someone to create a KafkaTopic object with a Kafka topic they theoretically shouldn't have permissions for and then just delete that object, in turn deleting that Kafka topic in the cluster. Would that be covered with authorization somehow? That scenario would be relevant for different user groups managing different topics in the same cluster but I think Kafka has also some system topics?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I believe this is always a security risk with declarative resources in products.

For me the most important defense is definitely k8s RBAC on the KafkaCluster CRD preventing unauthorized users from taking creating KafkaTopics with arbitrary names. Also the principle used by the agent inside Kafka should have limitations on what it can and can't do.

Specifically for Kafka I'm also considering adding a validation on the topic name rejecting the prefix __ which is used by some internal topics.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have a topic per cluster, we could store the topic ID in the cluster resource? Only if these match (or is set) we know it is managed by us?

For the internal topics: We explicitly offer naming the topic different from the custom resource name. Why is that? E.g. with Trino catalogs, the name is the one of the resource (with options to tweak).
https://docs.stackable.tech/home/stable/trino/usage-guide/catalogs/#_catalog_name_tweaking

@xeniape

xeniape commented Oct 26, 2026

Copy link
Copy Markdown
Member

Claude noted down some possible lifecycle problems/decisions:

  • The managed object would need a finalizer on deletion, otherwise the object gets deleted right away and the agent might not have had enough time reading the specs of the object needed to execute deletion logic in the product. So the object might never get deleted. So the finalizer would be definitely needed.
  • BUT with the finalizer another problem pops up: the deletion process might get stuck if there is no one removing that finalizer again. This can happen in different scenarios, for example someone could delete the product cluster or namespace and if the agent gets removed because of that before the deletion process is done and the finalizer removed, there is no one to remove that finalizer so the namespace deletion is stuck. So either the agent needs to stay alive until everything is processed or someone else (operator?) needs to release the objects

Not sure if this is part of this PR or not, but it seemed general enough to mention it in the operator-rs changes, if this provides some mechanism for all the operators.

@labrenbe

Copy link
Copy Markdown
Member Author

Claude noted down some possible lifecycle problems/decisions:

* The managed object would need a finalizer on deletion, otherwise the object gets deleted right away and the agent might not have had enough time reading the specs of the object needed to execute deletion logic in the product. So the object might never get deleted. So the finalizer would be definitely needed.

* BUT with the finalizer another problem pops up: the deletion process might get stuck if there is no one removing that finalizer again. This can happen in different scenarios, for example someone could delete the product cluster or namespace and if the agent gets removed because of that before the deletion process is done and the finalizer removed, there is no one to remove that finalizer so the namespace deletion is stuck. So either the agent needs to stay alive until everything is processed or someone else (operator?) needs to release the objects

Not sure if this is part of this PR or not, but it seemed general enough to mention it in the operator-rs changes, if this provides some mechanism for all the operators.

Yes, the idea is to have the operator clean up after a KafkaCluster (or the whole Namespace) has been deleted and there is no agent left to clean up finalizers. As the cluster is being deleted anyway the operator only has to remove finalizers and doesn't need to take action in Kafka.

For me this logic is a candidate to extract into operator-rs in the future.

Comment on lines +54 to +58
let status = match update.status {
ConditionStatus::True => "True",
ConditionStatus::False => "False",
ConditionStatus::Unknown => "Unknown",
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be done via strum and IntoStaticStr instead of explicitly writing it?

Retain,

/// Delete the resource in the product.
Delete,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have a topic per cluster, we could store the topic ID in the cluster resource? Only if these match (or is set) we know it is managed by us?

For the internal topics: We explicitly offer naming the topic different from the custom resource name. Why is that? E.g. with Trino catalogs, the name is the one of the resource (with options to tweak).
https://docs.stackable.tech/home/stable/trino/usage-guide/catalogs/#_catalog_name_tweaking

Comment on lines +11 to +16
pub struct ResourceOperation {
/// Stops the agent from changing the resource in the product. The status is still updated.
#[serde(default)]
pub reconciliation_paused: bool,
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this. We never really update anything in the custom resource except the status anyways? If i want to get rid of the agent for testing / upgrading etc, i think we can just set the enabled = false flag?

What is the purpose, and why dont we then also support the "stopped" (scale to 0, same as enabled = false) flag?

#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum TlsClientCredential {
/// An AutoTLS SecretClass used to provision the certificate.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't need to be autoTls, could also be a static TLS cert using k8sSearch

Suggested change
/// An AutoTLS SecretClass used to provision the certificate.
/// The name of the SecretClass providing the certificate used for authentication at the procuct.

@sbernauer

Copy link
Copy Markdown
Member

I was wondering what the CRD looks like, can we please add it to the CRD preview?

diff --git a/crates/stackable-operator/crds/DummyCluster.yaml b/crates/stackable-operator/crds/DummyCluster.yaml
index 0f3a9683..25acd2b8 100644
--- a/crates/stackable-operator/crds/DummyCluster.yaml
+++ b/crates/stackable-operator/crds/DummyCluster.yaml
@@ -416,6 +416,49 @@ spec:
               kerberosRealmName:
                 description: A validated kerberos realm name type, for use in CRDs.
                 type: string
+              managementAccess:
+                nullable: true
+                properties:
+                  authentication:
+                    oneOf:
+                    - required:
+                      - anonymous
+                    - required:
+                      - tls
+                    properties:
+                      anonymous:
+                        description: 'No credential: the product does not require authentication.'
+                        type: object
+                      tls:
+                        description: 'Source of a TLS client certificate: a secret-operator SecretClass or a static Secret.'
+                        oneOf:
+                        - required:
+                          - secretClassName
+                        - required:
+                          - secretName
+                        properties:
+                          secretClassName:
+                            description: An AutoTLS SecretClass used to provision the certificate.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          secretName:
+                            description: |-
+                              A static Secret holding the certificate in the keys `tls.crt` and `tls.key` (PEM), e.g. as
+                              a Secret of type `kubernetes.io/tls`.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                        type: object
+                    type: object
+                  enabled:
+                    type: boolean
+                required:
+                - authentication
+                - enabled
+                type: object
               nodes:
                 description: |-
                   This struct represents a role - e.g. HDFS datanodes or Trino workers. It has a key-value-map containing
diff --git a/crates/xtask/src/crd/dummy.rs b/crates/xtask/src/crd/dummy.rs
index 67cbbfe1..e2edf0f5 100644
--- a/crates/xtask/src/crd/dummy.rs
+++ b/crates/xtask/src/crd/dummy.rs
@@ -115,6 +115,7 @@ pub mod versioned {
         client_authentication_details: authentication::core::v1alpha1::ClientAuthenticationDetails<
             oidc::v1alpha1::ClientAuthenticationMethodOption,
         >,
+        management_access: Option<DummyManagementAccess>,
     }
 
     #[derive(Debug, Default, PartialEq, Fragment, JsonSchema)]
@@ -186,6 +187,22 @@ pub mod versioned {
     pub struct DummyClusterStatus {
         pub conditions: Vec<ClusterCondition>,
     }
+
+    #[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)]
+    #[serde(rename_all = "camelCase")]
+    #[schemars(crate = "stackable_operator::schemars")]
+    pub struct DummyManagementAccess {
+        enabled: bool,
+        authentication: DummyManagementAccessAuthentication,
+    }
+
+    #[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)]
+    #[serde(rename_all = "camelCase")]
+    #[schemars(crate = "stackable_operator::schemars")]
+    pub enum DummyManagementAccessAuthentication {
+        Anonymous(stackable_operator::crd::management_access::v1alpha1::Anonymous),
+        Tls(stackable_operator::crd::management_access::v1alpha1::TlsClientCredential)
+    }
 }
 
 #[cfg(test)]

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Development: In Review

Development

Successfully merging this pull request may close these issues.

5 participants