Skip to content

Operator Secret access

The cluster-bound mcp-runtime-operator-role has no Secret rules. The separately maintained mcp-runtime-operator-managed-secrets ClusterRole grants direct get/create/update/patch/delete and is bound by RoleBindings in managed MCPServer namespaces. Secret reads bypass the controller-runtime cache; no Secret list or watch permission is needed. Keep the scoped role separate from generated RBAC.

Supported setup backfills existing server namespaces and platform-managed empty namespaces before removing the old cluster-wide Secret rule. Runtime API provisioning grants access for new managed namespaces. Infrastructure namespaces, including the platform, observability, and collector namespaces, cannot receive this tenant binding. The direct installation bundle creates the default mcp-servers namespace and its binding; administrators installing tenant manifests directly must arrange the corresponding namespace-local binding.

If MCP_DEFAULT_INGRESS_TLS_SECRET_NAMESPACE is configured, setup preserves or pre-creates mcp-adapter-client-ca there. This contains public trust material. The operator gets named get/update/patch through a separate Role and RoleBinding. The installer creates the object because Kubernetes cannot restrict Secret create by resourceNames. Cert-manager, operator and Kubernetes system namespaces cannot be configured for this trust bundle. Direct customized installations must pre-provision the bundle and equivalent named RoleBinding; removing the Secret requires rerunning setup before reconciliation can restore it.

Indirect routes are scoped the same way. Deployment, ServiceAccount and Certificate create/update/patch/delete (the ways to mount or issue into a Secret) are granted by the mcp-runtime-operator-managed-workloads ClusterRole, bound only through the same namespace-local RoleBindings. The cluster-bound role keeps get/list/watch on them for informers. The operator therefore cannot create a Deployment in cert-manager to mount the workload CA key, nor read it directly. Runtime API holds bind on the role for provisioning.

Remaining gaps: other mutating verbs (Services, ConfigMaps, Ingresses, NetworkPolicies, Traefik resources, pods patch) stay cluster-wide, and real API-server authorization (kubectl auth can-i for cert-manager/mcp-runtime-ca) plus Staging E2E have not been exercised. Do not treat this change as closing the CA-key isolation issue until that is done.