--- # Letting an application namespace read its own Kafka credentials. # # Strimzi writes a KafkaUser's SCRAM password into a Secret in *this* namespace, # and a Secret cannot be mounted across namespaces. The alternatives are to copy # the password by hand (it then drifts the first time the user is regenerated) # or to put it in Vault (a second copy of a credential the cluster already # owns, kept in sync by nobody). # # Instead External Secrets reads it here and materialises it there. The password # stays generated by, and rotatable by, Strimzi; the copy follows. # # The ServiceAccount below can read Secrets in this namespace ONLY, which # includes every KafkaUser's password. That is the trade: any namespace allowed # to create an ExternalSecret against this store can pull any Kafka account's # credentials. Acceptable in a lab with one operator; in a shared cluster, # narrow the Role with resourceNames and run one store per application. apiVersion: v1 kind: ServiceAccount metadata: name: kafka-credentials-reader namespace: kafka --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: kafka-credentials-reader namespace: kafka rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kafka-credentials-reader namespace: kafka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kafka-credentials-reader subjects: - kind: ServiceAccount name: kafka-credentials-reader namespace: kafka --- # External Secrets authenticates as that ServiceAccount rather than as itself, # so what the store can reach is bounded by the Role above and visible in RBAC # rather than in the operator's own permissions. apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: kafka-credentials spec: provider: kubernetes: remoteNamespace: kafka server: caProvider: type: ConfigMap name: kube-root-ca.crt key: ca.crt namespace: kafka auth: serviceAccount: name: kafka-credentials-reader namespace: kafka