Monedula
monedula-gitops docs menu

Manage Confluent RBAC role bindings

Declare Confluent MDS role bindings with KafkaRoleBinding, or let topic access compile to role bindings on RBAC-backed clusters.

How-to guides 9 of 18

5 min read

Updated 9 October 2026

Markdown

On this page

Before you start

  • Confluent Platform with the Metadata Service (MDS). Role bindings do not work on Apache Kafka or Confluent Cloud, as Supported platforms and versions explains.
  • An MDS user that may manage role bindings at the scopes you bind, typically one with the UserAdmin or SecurityAdmin role, depending on your Confluent Platform version.
  • The Kafka cluster ID, plus the Schema Registry, Connect or ksqlDB cluster ID if you bind roles on those scopes.

Steps

1. Connect to MDS

Add an authorization.mds block to the KafkaCluster. This cluster config for the CLI connects to the brokers with SCRAM over TLS and to MDS with HTTP basic auth. Save it as clusters/prod.yaml:

apiVersion: gitops.monedula.dev/v1alpha1
kind: KafkaCluster
metadata:
  name: prod
spec:
  bootstrapServers: broker1:9093
  tls:
    enabled: true
  auth:
    mechanism: SCRAM-SHA-512
    scram:
      username: { valueFrom: { env: KAFKA_USER } }
      password: { valueFrom: { env: KAFKA_PASSWORD } }
  authorization:
    mds:
      endpoint: "https://mds.example.com:8090"
      auth:
        type: basic
        username: { valueFrom: { env: MDS_USER } }
        password: { valueFrom: { env: MDS_PASSWORD } }
      clusters:
        kafkaCluster: "abc123"

endpoint and clusters.kafkaCluster (the Kafka cluster ID) are required. Connect to a secured Kafka cluster covers the other auth types and the cluster IDs for other scopes. With the operator, read the MDS credentials from a Secret, as in the accessBackends example below.

2. Declare the role binding

This binding grants User:svc-checkout the DeveloperWrite role on the topic payments.orders. Save it as rbac/checkout-writer.yaml:

apiVersion: gitops.monedula.dev/v1alpha1
kind: KafkaRoleBinding
metadata:
  name: checkout-writer
spec:
  clusterRef:
    name: prod
  principal: User:svc-checkout
  role: DeveloperWrite
  scope:
    type: kafka
  resources:
    - type: Topic
      name: payments.orders
      patternType: literal
  • principal takes the form User:<name> or Group:<name>.
  • role is a Confluent role. Cluster-scoped roles, such as SystemAdmin, ClusterAdmin, UserAdmin, Operator, SecurityAdmin and AuditAdmin, bind to the whole scope and take no resources. Resource-scoped roles, ResourceOwner, DeveloperRead, DeveloperWrite and DeveloperManage, need at least one. An unknown role is accepted with a warning.
  • scope.type is kafka, schema-registry, connect or ksql, and picks the matching cluster ID from authorization.mds.clusters.
  • Each entry in resources has a type, a name and a patternType, literal by default or prefixed. The kafka scope takes Topic, Group, Cluster and TransactionalId; schema-registry takes Subject and Cluster; connect takes Connector and Cluster; ksql takes KsqlCluster and Cluster.

Use patternType: prefixed to bind a family of resources, such as every topic whose name starts with payments.. clusterRef, principal, role and scope.type cannot change after creation; resources can.

3. Preview and apply

# validate
monedula-gitops validate -f ./rbac --cluster-config-file ./clusters/prod.yaml

# preview
monedula-gitops diff -f ./rbac --cluster-config-file ./clusters/prod.yaml

# apply (role binding removal also requires --prune)
monedula-gitops apply -f ./rbac --cluster-config-file ./clusters/prod.yaml
kubectl apply -f rbac/

The plan shows an AddRoleBinding operation for the new binding. You can load KafkaRoleBinding manifests together with topics and access policies in the same -f run.

4. Remove a role binding

To remove a binding that is in scope, such as a resource you dropped from resources, apply with --prune (CLI) or set spec.prune: true on the KafkaRoleBinding (operator); until then it is PruneDisabled and stays in MDS. Bindings compiled from topic access share this scope. A binding whose principal, role and scope no manifest declares is out of scope: the CLI neither reports nor removes it, and with the operator you delete the KafkaRoleBinding resource.

Compile topic access to role bindings

Instead of writing producer and consumer bindings by hand, you can let the topics’ access blocks compile to them: add accessBackends next to mds in the cluster’s spec.authorization. This block, from a KafkaCluster for the operator, reads the MDS credentials from a Secret and emits both ACLs and role bindings:

authorization:
  mds:
    endpoint: https://kafka-mds.kafka.svc:8090
    auth:
      type: basic
      username:
        valueFrom:
          secretKeyRef:
            name: kafka-admin-credentials
            key: username
      password:
        valueFrom:
          secretKeyRef:
            name: kafka-admin-credentials
            key: password
    clusters:
      kafkaCluster: abc123
  accessBackends:
    - acl
    - rbac

rbac requires authorization.mds:

accessBackends ACLs MDS role bindings
unset or [acl] (default) yes no
[rbac] no yes
[acl, rbac] yes yes

Producers become DeveloperWrite on the topic; consumers become DeveloperRead on the topic and on the group. RBAC roles are coarse and have no host, so an entry with a non-* host or a custom operation list still gets its binding, without that refinement: the topic gets the condition RBACCoarsened=True and the CLI warns. For host-scoped grants on an RBAC-backed cluster, use a KafkaAccessPolicy.

With [acl, rbac], ACLs and role bindings authorize independently, so a principal keeps access through whichever backend still grants it. Use the dual setting as a temporary step while you move a cluster from ACLs to RBAC or back. Before you count access as revoked, check that diff shows both an ACL removal and a role-binding removal.

Turning a backend off, for example from [acl, rbac] to [acl], leaves that backend’s existing grants live. Topic access stops declaring them, so unless another manifest keeps them in the managed scope, neither runtime reports or prunes them. To remove them, delete them outside monedula-gitops, with Kafka’s kafka-acls tool for ACLs or the Confluent CLI for role bindings.

Check it worked

monedula-gitops verify -f ./rbac --cluster-config-file ./clusters/prod.yaml
kubectl wait kafkarolebinding/checkout-writer --for=condition=RoleBindingSynced --timeout=120s

verify reads the current bindings from MDS, exits 0 and prints No changes. when they match the manifests. With the operator, the KafkaRoleBinding reports the conditions Ready, RoleBindingSynced and MDSReachable with the status True. A KafkaTopic on a cluster with the rbac backend reports RoleBindingSynced and MDSReachable for its derived bindings.