This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new e5e1466d docs(k8s): define certificate provider contract (#1645)
e5e1466d is described below
commit e5e1466d85aad114cded37373ef916c21131b750
Author: aias00 <[email protected]>
AuthorDate: Tue Aug 11 20:43:44 2026 +0800
docs(k8s): define certificate provider contract (#1645)
---
docs/kubernetes-certificate-provider.md | 177 ++++++++++++++++++++++++++++++++
1 file changed, 177 insertions(+)
diff --git a/docs/kubernetes-certificate-provider.md
b/docs/kubernetes-certificate-provider.md
new file mode 100644
index 00000000..541e7461
--- /dev/null
+++ b/docs/kubernetes-certificate-provider.md
@@ -0,0 +1,177 @@
+# Kubernetes Certificate Provider Design
+
+## Status
+
+Proposed implementation contract for
[#1314](https://github.com/apache/rocketmq-dashboard/issues/1314).
+
+## Context
+
+The existing K8s certificate page stores Studio-local metadata. Those records
are not an inventory of
+Kubernetes Secrets or cert-manager `Certificate` resources, and create, renew,
or delete requests do
+not change a Kubernetes cluster. Studio must not represent that local metadata
as applied runtime
+state.
+
+This document defines the boundary required before adding a Kubernetes-backed
certificate view.
+
+## Goals
+
+- Resolve certificate inventory through the selected managed instance, never
through a process-global
+ Kubernetes client.
+- Support a read-only inventory phase before exposing certificate lifecycle
actions.
+- Keep Kubernetes credentials in the existing credential store as references;
never return kubeconfig,
+ bearer tokens, client private keys, or Secret data to the browser.
+- Make unsupported capability and provider failures distinguishable from an
empty certificate list.
+- Define least-privilege RBAC for each release phase.
+
+## Non-goals
+
+- Infer a Kubernetes cluster from a RocketMQ NameServer or Proxy endpoint.
+- Treat Studio-local `rmq_k8s_certificate` records as Kubernetes resources.
+- Create, renew, or delete certificates before a provider can prove that it is
operating against the
+ selected Kubernetes context.
+- Add a general-purpose Kubernetes resource browser.
+
+## Instance Model
+
+A Kubernetes certificate source is associated with one managed Studio
instance. The instance must
+reference a Kubernetes credential and an explicit Kubernetes target:
+
+| Field | Meaning |
+| --- | --- |
+| `instanceId` | Studio instance that owns the operational context. |
+| `credentialId` | Reference to an encrypted Kubernetes credential; the
credential value is never returned by the API. |
+| `kubernetesContext` | Named kubeconfig context or in-cluster identity
selector. |
+| `namespaceScope` | Optional allow-list of namespaces. An omitted value means
the provider's configured default, not all namespaces. |
+| `certificateSource` | `CERT_MANAGER`, `TLS_SECRET`, or both when a provider
explicitly supports both inventories. |
+
+Existing RocketMQ instance endpoints remain RocketMQ connection endpoints.
They are not Kubernetes
+credentials and must not be reused to construct a Kubernetes API URL.
+
+## Provider Contract
+
+The server owns provider resolution. A provider is selected by the instance
vendor/capability and a
+validated Kubernetes credential reference.
+
+```java
+public interface KubernetesCertificateProvider {
+ KubernetesCertificateCapabilities capabilities(String instanceId);
+
+ KubernetesCertificateInventory listCertificates(
+ String instanceId, KubernetesCertificateQuery query);
+
+ default KubernetesCertificate renewCertificate(
+ String instanceId, KubernetesCertificateRef certificate) {
+ throw new UnsupportedOperationException("Certificate renewal is not
supported");
+ }
+
+ default void deleteCertificate(
+ String instanceId, KubernetesCertificateRef certificate) {
+ throw new UnsupportedOperationException("Certificate deletion is not
supported");
+ }
+}
+```
+
+`KubernetesCertificateProviderRegistry` resolves this interface. It must
reject an instance with no
+Kubernetes binding rather than silently selecting a default context.
+
+`KubernetesCertificateInventory` contains:
+
+- `items`: certificates from the requested source;
+- `source`: `CERT_MANAGER` or `TLS_SECRET`;
+- `observedAt`: provider observation timestamp;
+- `capabilities`: supported read/write operations;
+- `partialFailures`: namespace/source failures that did not invalidate the
whole response.
+
+An empty `items` list means a successful observation with no matching
resources. A missing provider,
+invalid credential, RBAC denial, or API failure is an explicit structured
error and must not be
+converted to an empty inventory.
+
+## API Shape
+
+The first external API is read-only:
+
+```
+GET /api/instances/{instanceId}/kubernetes/certificates
+ ?namespace=<optional>
+ &source=CERT_MANAGER|TLS_SECRET
+```
+
+The response includes the selected instance ID and source so cached UI data
cannot be reused for a
+different instance. The request must validate that `namespace`, when supplied,
is inside the instance
+namespace scope.
+
+The existing `/api/k8s-certs` endpoints remain explicitly Studio-local until
they are removed or
+migrated. They must not be mixed with provider inventory results in one table
without a visible
+source label.
+
+Future mutation endpoints use resource references, not Studio-local record IDs:
+
+```
+POST
/api/instances/{instanceId}/kubernetes/certificates/{namespace}/{name}/renew
+DELETE /api/instances/{instanceId}/kubernetes/certificates/{namespace}/{name}
+```
+
+Mutations require an advertised provider capability and create an audit entry
containing the Studio
+user, instance ID, namespace, resource name, provider source, and result. They
must never log token,
+kubeconfig, Secret value, or certificate private key material.
+
+## Credentials and RBAC
+
+Phase 1 supports either a ServiceAccount token reference or a kubeconfig
secret reference stored by
+the server. The browser only receives the credential display name and
non-sensitive metadata.
+
+Read-only cert-manager inventory requires:
+
+```yaml
+apiGroups: ["cert-manager.io"]
+resources: ["certificates"]
+verbs: ["get", "list", "watch"]
+```
+
+Read-only TLS Secret inventory requires:
+
+```yaml
+apiGroups: [""]
+resources: ["secrets"]
+verbs: ["get", "list"]
+```
+
+The TLS Secret provider returns metadata only: namespace, name, type, creation
time, and parsed
+certificate expiry. It never returns `data.tls.crt` or `data.tls.key`.
+
+Renewal requires cert-manager `patch` permission on `certificates` and must
define the exact renewal
+mechanism before implementation. Deletion is a separate high-risk capability
and requires a
+confirmation workflow plus `delete` permission.
+
+## Delivery Phases
+
+1. **Provider foundation:** introduce the provider registry, Kubernetes
credential reference model,
+ capability endpoint, and a provider-unavailable response. No mutation UI.
+2. **Read-only cert-manager inventory:** list `Certificate` resources for one
selected instance and
+ namespace scope, including Ready condition and expiry data.
+3. **Read-only TLS Secret inventory:** optional source for clusters without
cert-manager, metadata
+ only.
+4. **Renewal:** add only after a cert-manager-compatible renewal operation and
audit contract are
+ tested against a real cluster.
+5. **Deletion:** explicit opt-in, confirmation, audit, and post-condition
verification.
+
+Each phase is independently deployable. A missing Kubernetes provider must
leave the rest of Studio
+operational and show a capability-unavailable state rather than fabricated
certificate data.
+
+## Test Matrix
+
+- provider registry rejects an instance without Kubernetes binding;
+- selected instance A cannot read inventory using instance B
credentials/context;
+- empty inventory is distinct from RBAC denial and transport failure;
+- namespace scope is enforced before a Kubernetes client call;
+- TLS Secret results never serialize Secret data or private-key fields;
+- cert-manager resources with missing status are rendered as unknown, not
valid;
+- write endpoints reject missing capability and produce audit records only
after the provider call is
+ attempted.
+
+## Migration
+
+Studio-local certificate records remain available only in the current
local-metadata view during the
+transition. They are not automatically migrated because their `cluster` field
does not identify a
+Kubernetes API context, credential, or authoritative resource name. Operators
explicitly bind an
+instance to a Kubernetes provider, then use the provider inventory as the
runtime source of truth.