Deploy a Multi-Tenant Physical Kafka Cluster
Learn how to deploy a Physical Kafka Cluster (PKC) with Multi-Tenancy enabled using Confluent for Kubernetes (CFK). A platform operator completes this setup once per PKC before onboarding any tenants.
To move the topics of an existing cluster to Logical Kafka Clusters (LKCs), see the Migrate Existing Clusters to Multi-Tenant LKCs page.
Prerequisites
Before you begin, ensure you have the following:
A Kubernetes cluster with Confluent for Kubernetes (CFK) 3.4 or later installed. For installation instructions, see Deploy Confluent for Kubernetes.
Confluent Platform 8.4 or later.
The ability to create wildcard DNS records for the PKC’s domain. For more information, see Configure TLS Certificates and DNS for Multi-Tenant PKCs.
Familiarity with the Multi-Tenancy model. For an introduction, see Multi-Tenancy Overview.
A Confluent Private Cloud license. Without a license, you can use up to three LKCs for 30 days. For more information, see Manage Confluent Platform Licenses.
Requirements for a multi-tenant PKC
A multi-tenant PKC has the following requirements:
Brokers: At least three. Multi-Tenancy stores LKC metadata in an internal topic that requires three replicas.
Authorization: role-based access control (RBAC) authorization with Metadata Service (MDS) on the
KafkaandKRaftControllerCRs.Encryption: TLS on the internal and external listeners.
Routing: Server Name Indication (SNI) routing and wildcard DNS records for the LKC hostnames.
Deployment topology: A single-region PKC. Multi-Tenancy isn’t supported on multi-region clusters (MRCs) in this release.
For the Kafka CR settings that enforce these requirements, see
Step 3.
Step 1: Plan capacity
Before you deploy, establish a broker-capacity baseline from each broker’s JVM heap size. CFK sets the heap to half of the pod memory, up to 32 GiB. Use the baseline to size the broker memory in Step 3: Deploy the PKC with Multi-Tenancy enabled and as the resource ceiling when you calculate tenant quota allocations. The values are per broker:
Capacity dimension |
Calculation formula |
|---|---|
Producer byte rate |
|
Consumer byte rate |
|
Max connections |
|
Max connections per tenant |
|
For example, a broker configured with an 8 GiB JVM heap supports a baseline capacity of 50 MiB/s producer throughput, 150 MiB/s consumer throughput, 32,768 total connections, and 8,192 connections per tenant.
CFK also limits how many new connections per second each LKC and each tenant listener can open on a broker. These limits don’t scale linearly with heap size, so CFK sets them by heap size range:
Broker JVM heap |
Per LKC (new connections per second) |
Per tenant listener (new connections per second) |
|---|---|---|
4 GiB or less |
40 |
84 |
More than 4 GiB, up to 16 GiB |
50 |
250 |
More than 16 GiB |
63 |
750 |
Step 2: Deploy KRaft controllers
Deploy the KRaft controllers first. The Kafka custom resource (CR) that
provisions your PKC references the KRaftController CR, and CFK waits for
KRaft to be up before it starts Kafka.
Configure the KRaftController CR with RBAC authorization
with spec.authorization.type: rbac and an mdsKafkaCluster
dependency. Without RBAC, the controllers run as single-tenant and
can’t authorize topic creation in LKCs.
Create a manifest file named
kraftcontroller.yamlwith the following configuration:apiVersion: platform.confluent.io/v1beta1 kind: KRaftController metadata: name: <kraftcontroller-name> namespace: <your-namespace> spec: replicas: 3 image: application: confluentinc/cp-server:<cp-version> init: confluentinc/confluent-init-container:<cfk-version> dataVolumeCapacity: 10G configOverrides: server: - default.replication.factor=3 - min.insync.replicas=2 authorization: type: rbac superUsers: - User:<superuser-1> - User:<superuser-2> listeners: controller: tls: enabled: true authentication: type: plain jaasConfig: secretRef: <controller-credential-secret> tls: autoGeneratedCerts: true dependencies: mdsKafkaCluster: bootstrapEndpoint: <pkc-name>.<your-namespace>.svc.cluster.local:9071 authentication: type: plain jaasConfig: secretRef: <mds-kafka-credential-secret> tls: enabled: true
Replace the placeholders with your values:
<kraftcontroller-name>: The name of theKRaftControllerCR.<your-namespace>: Your Kubernetes namespace.<cp-version>: The Confluent Platform version to run, such as8.4.0.<cfk-version>: Theconfluent-init-containerversion that matches your CFK version.<superuser-1>and<superuser-2>: The principals that the controllers treat as super users.<controller-credential-secret>and<mds-kafka-credential-secret>: The names of the secrets that hold the credentials for the controller listener and for the connection to the Kafka cluster that hosts Metadata Service (MDS).<pkc-name>: The name that you give the PKC in the next step. The controllers connect to the PKC’s internal listener on port9071.
The controllers assign replicas to new topics, so set
default.replication.factorandmin.insync.replicasunderconfigOverrides.serveron theKRaftControllerCR. Without them, topics that clients create without a replication factor get a replication factor of1.This example uses
plainauthentication and auto-generated certificates. Adjust your authentication and TLS settings to match your Kafka configuration. For full configuration options, see Configure and Manage KRaft for Confluent Platform Using Confluent for Kubernetes.Apply the configuration:
kubectl apply -f kraftcontroller.yaml
Step 3: Deploy the PKC with Multi-Tenancy enabled
Enable Multi-Tenancy on the Kafka CR that provisions your PKC.
CFK rejects a Kafka CR with spec.multiTenant.enabled set to
true unless the CR also configures internal and external listener
TLS, Metadata Service (MDS), role-based access control (RBAC) authorization, and broker pod memory.
Configure these prerequisites on the same CR, alongside
multiTenant:Set
spec.listeners.internal.tls.enabledandspec.listeners.external.tls.enabledtotrue.Configure
spec.services.mds. For instructions, see Configure Authentication for Kafka, KRaft, and MDS in Confluent Platform Using Confluent for Kubernetes.Set
spec.authorization.typetorbac.Set
spec.podTemplate.resourcesto a memory request or limit. Multi-Tenancy derives its capacity-planning baseline from this value.
Ensure these
KafkaCR settings are also set. CFK accepts aKafkaCR that omits them, but then reports an error and doesn’t deploy the brokers:Configure
spec.dependencies.kafkaRest.authentication. Without it, the CR reports.spec.dependencies.kafkaRest.authentication must be configured.Configure
spec.tls. For example, useautoGeneratedCerts: true. Without it, a CR that enables TLS on a listener reportsmissing .spec.tls. in spec.
Create a manifest file named
kafka.yamlwith the following configuration:apiVersion: platform.confluent.io/v1beta1 kind: Kafka metadata: name: <pkc-name> namespace: <your-namespace> spec: replicas: 3 image: application: confluentinc/cp-server:<cp-version> init: confluentinc/confluent-init-container:<cfk-version> dataVolumeCapacity: 100Gi authorization: type: rbac tls: autoGeneratedCerts: true services: mds: tokenKeyPair: secretRef: <mds-token-secret> provider: ldap: address: <ldap-address> authentication: type: simple simple: secretRef: <ldap-credentials-secret> configurations: userNameAttribute: <user-name-attribute> userObjectClass: <user-object-class> userSearchBase: <user-search-base> groupSearchBase: <group-search-base> authentication: type: bearer listeners: internal: authentication: type: plain jaasConfig: secretRef: <internal-credential-secret> tls: enabled: true external: authentication: type: plain jaasConfig: secretRef: <external-credential-secret> externalAccess: type: loadBalancer loadBalancer: domain: <external-domain> tls: enabled: true podTemplate: resources: requests: memory: <broker-memory-request> multiTenant: enabled: true dependencies: kRaftController: clusterRef: name: <kraftcontroller-name> controllerListener: tls: enabled: true authentication: type: plain jaasConfig: secretRef: <controller-credential-secret> kafkaRest: authentication: type: bearer bearer: secretRef: <kafka-rest-credential-secret>
Replace the placeholders with your values:
<pkc-name>: The name of your PKC.<your-namespace>: Your Kubernetes namespace.<cp-version>: The Confluent Platform version to run, such as8.4.0.<cfk-version>: Theconfluent-init-containerversion that matches your CFK version.<broker-memory-request>: The memory request for each broker pod, such as8Gi. The broker’s JVM heap is smaller than this value. Use the JVM heap size, not the pod memory request, in the capacity-planning formulas in Step 1: Plan capacity.<kraftcontroller-name>: The name of theKRaftControllerCR you deployed in Step 2: Deploy KRaft controllers.<internal-credential-secret>: The name of the secret that holds the credentials for the internal listener. The controllers connect to this listener throughmdsKafkaCluster, so the secret must include the user that<mds-kafka-credential-secret>in Step 2: Deploy KRaft controllers uses.<external-credential-secret>: The name of the secret that holds the credentials for the external listener. Clients outside your Kubernetes cluster use these credentials to connect to an LKC’s bootstrap URL.<controller-credential-secret>: The name of the secret that holds the credentials for the controller listener. Use the same secret you set in Step 2: Deploy KRaft controllers.<mds-token-secret>: The name of the secret that holds the MDS token key pair.<kafka-rest-credential-secret>: The name of the secret that holds the bearer credentials for the Kafka REST API.<ldap-address>,<ldap-credentials-secret>,<user-name-attribute>,<user-object-class>,<user-search-base>, and<group-search-base>: The connection details and search settings for your LDAP directory. This example uses LDAP. To use a different identity provider, configureproviderfor that provider instead.The search settings must match your directory’s layout. If they don’t, Metadata Service (MDS) can’t search for groups or can’t find users. In that case, Metadata Service (MDS) doesn’t start, or it rejects logins, and the role bindings in Step 7: Configure the RBAC foundation and role hierarchy fail with
connection refusedor401errors. For the LDAP settings and their defaults, see Configure LDAP Group-Based Authorization.<external-domain>: The domain that LKC bootstrap hostnames use, such asmt.example.com.
clusterRefonly tells the brokers which controllers to use. ThecontrollerListenersection tells them how to connect to the controller listener, so it must match thelisteners.controllersettings on theKRaftControllerCR. Without it, CFK configures the brokers to connect to the controllers over plaintext with no authentication, and the brokers can’t register with the controllers that you configured for TLS andplainauthentication in Step 2: Deploy KRaft controllers.Without authentication on the external listener, clients outside the cluster can’t connect to an LKC’s bootstrap URL. The connection fails with
Unexpected handshake request with client mechanism PLAIN, enabled mechanisms are [].By default, CFK doesn’t create Services for LKC hostnames. Configure the DNS rewrite rules described in Configure TLS Certificates and DNS for Multi-Tenant PKCs. Set
spec.multiTenant.createTenantNameServicestotrueonly as a fallback when you can’t edit your cluster’s DNS. CFK then creates a Service for every broker of every LKC, which uses up the cluster’s Service IP range as you add LKCs and brokers. For an example of how quickly the number of Services grows, see Configure TLS Certificates and DNS for Multi-Tenant PKCs and Limitations.The preceding example is a starting point. Adjust the authentication, TLS certificate, and LDAP settings to match your environment. For full listener, authentication, and MDS configuration options, see Configure Network Encryption for Confluent Platform Using Confluent for Kubernetes and Manage RBAC for Confluent Platform Using Confluent for Kubernetes.
Apply the configuration:
kubectl apply -f kafka.yaml
Caution
Enable Multi-Tenancy when you first deploy the PKC. After any
LogicalKafkaCluster CR references this Kafka cluster, CFK prevents
you from disabling Multi-Tenancy. To disable it, first decommission every
tenant on the PKC.
Step 4: Configure PKC-level settings
Configure the following PKC-wide settings on the Kafka CR before
onboarding tenants. These settings are not specific to Multi-Tenancy.
Configure them by referring to the documentation that each setting links to:
Identity provider: All LKCs on the same PKC share a single identity provider, such as LDAP or OpenID Connect (OIDC). Plan for this shared identity-provider constraint before configuring authentication. For guidance on securing your identity provider, see Plan Security for Confluent for Kubernetes.
TLS certificates: Ensure every broker presents a TLS certificate valid for all hosted LKC hostnames. You provision these certificates as part of the TLS approach you choose. For more information, see Manage Certificates.
Storage capacity: Choose storage classes and size
spec.dataVolumeCapacityto accommodate the total storage footprint of all planned tenants. For more information, see Configure Storage for Confluent Components Using Confluent for Kubernetes.Broker defaults: Set cluster-wide broker configuration under
spec.configOverrides.serverfor the PKC.
Step 5: Configure a TLS approach
Clients reach each LKC through its own bootstrap URL, which SNI routes at the
TLS layer. Brokers advertise LKC hostnames with a
broker label, such as lkc-<id>-kafka.b0.<domain>. Every broker needs a
certificate that’s valid for the LKC hostnames it serves, and the required
Subject Alternative Names (SANs) depend on the TLS approach that you choose.
Before you onboard your first tenant, choose your TLS approach and complete its certificate setup. For guidance on choosing an approach and the SANs that each approach requires, see Configure TLS Certificates and DNS for Multi-Tenant PKCs.
The autoGeneratedCerts: true setting in the
Step 3: Deploy the PKC with Multi-Tenancy enabled example generates a certificate that
covers only in-cluster names. A client outside the cluster then fails the TLS
handshake with No subject alternative DNS name matching. To add the
wildcard names to the generated certificate, set the
platform.confluent.io/managed-cert-add-sans annotation on the Kafka CR
when you create it. For example,
"*.<external-domain>,*.b0.<external-domain>,*.b1.<external-domain>,*.b2.<external-domain>".
CFK reads this annotation from the Kafka CR only if managedCerts is
enabled in the CFK Helm values. Set managedCerts.enabled to true and
set managedCerts.caCertificate.secretRef to the secret that holds your
certificate authority (CA) certificate and key pair. With the default Helm
values, CFK doesn’t read the annotation. For more
details, see Manage auto-generated certificates.
Step 6: Verify Confluent Control Center’s auto-detection
If you deploy Confluent Control Center, it requires version 2.7 or later. Set
spec.authorization.type to rbac. For deployment instructions, see
Install Confluent Platform Using Confluent for Kubernetes.
CFK automatically configures Confluent Control Center for Multi-Tenancy based on the Kafka
CR that the ControlCenter CR references. The ControlCenter CR must
reference the PKC through spec.dependencies.kafka.discovery. An explicit
bootstrapEndpoint doesn’t enable Multi-Tenancy.
Verify that Confluent Control Center detects the PKC as multi-tenant:
kubectl get controlcenter <c3-name> -n <your-namespace> -o jsonpath='{.status.multiTenant}'
A multi-tenant PKC returns {"enabled":true}. If the command returns
an empty response, confirm the ControlCenter CR’s
Kafka dependency points to the PKC you
configured in Step 3: Deploy the PKC with Multi-Tenancy enabled, and that
its image is Confluent Control Center 2.7 or later. CFK doesn’t enable Multi-Tenancy on
earlier images. For more information, see
Multi-tenancy settings.
Step 7: Configure the RBAC foundation and role hierarchy
Multi-Tenancy divides RBAC access across three roles:
Platform operator, scoped to the whole PKC. Holds the
OrganizationAdminrole.TenantAdmin, scoped to one or more LKCs. Holds theTenantAdminrole, scoped to those LKCs.Developer, scoped to individual resources within an LKC. Holds a standard role, such as
DeveloperReadorDeveloperWrite, that theTenantAdmingrants.
For the full breakdown of responsibilities, see Roles and responsibilities.
This step sets up the PKC-wide OrganizationAdmin foundation. Grant
the TenantAdmin role to individual users during tenant onboarding.
The TenantAdmin then grants developer-level roles within their own
LKCs.
A
ConfluentRolebindingCR uses theKafkaRestClassCR thatspec.kafkaRestClassRefnames. If you don’t setspec.kafkaRestClassRef, it uses theKafkaRestClassCR nameddefault. Create aKafkaRestClassCR before you apply the role binding:apiVersion: platform.confluent.io/v1beta1 kind: KafkaRestClass metadata: name: default namespace: <your-namespace> spec: kafkaRest: authentication: type: bearer bearer: secretRef: <rest-credential-secret>
Replace
<rest-credential-secret>with the name of the secret that holds the bearer credentials for the Kafka REST API.Create a manifest file named
rolebinding.yamlto assign theOrganizationAdminrole:apiVersion: platform.confluent.io/v1beta1 kind: ConfluentRolebinding metadata: name: <platform-operator-binding-name> namespace: <your-namespace> spec: principal: type: user name: <platform-operator-identity> role: OrganizationAdmin clustersScopeByIds: kafkaClusterId: <pkc-cluster-id>
Replace the placeholders with your values:
<platform-operator-binding-name>: A name for theConfluentRolebindingCR.<platform-operator-identity>: The platform operator’s identity in your identity provider.<pkc-cluster-id>: The Kafka cluster ID of the PKC. For instructions on finding cluster IDs, see Cluster Identifiers in Confluent Platform.
Apply the configuration:
kubectl apply -f rolebinding.yaml
The identity that CFK uses to create LKCs, whether through a
KafkaRestClass or through a cluster reference with inline authentication
details, also needs the OrganizationAdmin role on the PKC. Grant the role
the same way as in the preceding example.
For general RBAC CR mechanics, see Manage RBAC for Confluent Platform Using Confluent for Kubernetes.
Verify your deployment
Confirm that all PKC custom resources report a healthy phase before onboarding tenants:
kubectl get kraftcontroller <kraftcontroller-name> -n <your-namespace>
kubectl get kafka <pkc-name> -n <your-namespace>
kubectl get controlcenter <c3-name> -n <your-namespace>
Verify that each command displays RUNNING in the STATUS column.
Confluent Control Center is also required to visualize a multi-tenant PKC’s brokers, LKCs,
and per-tenant quota usage, rather than only its CRs’ reconciliation
state. A principal with a PKC-scoped role binding, such as one for
OrganizationAdmin, can use the following pages:
Home page: A PKC-wide summary of resources, including LKCs, topics, partitions, Connect clusters, and ksqlDB clusters. On a newly deployed PKC with no tenants yet, the summary shows zero LKCs.
Quota Overview page: After you onboard tenants, quota usage for every LKC, including 95th-percentile (p95) production and consumption rates, active connection counts, partition counts, and quota configuration.