<a id="co-manage-authentication"></a>

# Manage Authentication for Confluent Platform Using Confluent for Kubernetes

This topic describes post-deployment tasks for managing authentication in Confluent Platform, specifically updating user credentials for Kafka, KRaft, and MDS.

The process to rotate a user credential differs based on the types of
users: internal client users and external client users.

* Internal users for authenticating between brokers and controllers
  1. Create secret for existing user to ensure old credentials remain valid for
     brokers not yet updated.
  2. Add new user/credentials to allow a gradual transition. Both
     credentials work during rolling update.
  3. Remove old user/secret only after all brokers can successfully use the new
     credentials.
* External client users for authenticating to Kafka

  Add new user/credentials.

This topic covers several common use cases for updating user credentials, but
you can apply the same high-level workflow for other authentication types and
use cases based on the type of user, internal users or external client users.

For the steps to configure credentials, see [Configure authentication to access Kafka and KRaft](co-authenticate-kafka.md#co-authenticate-kafka).

<a id="co-update-sasl-plain-users"></a>

## Update Kafka or KRaft SASL/PLAIN external client users

To update the external client-facing SASL/PLAIN user credentials for Kafka or
KRaft, follow the steps described below based on the method you use to
provide required credentials, namely `jaasConfig` or
`jaasConfigPassThrough`.

Starting with CFK 3.2.0, CFK hot-reloads SASL/PLAIN credential changes so
that broker restarts are no longer required for user management.

### Hot-reload scope and limitations

* Applies only to external SASL/PLAIN credentials on the server side. Do not
  use hot-reload for inter-broker SASL/PLAIN credentials or Confluent
  component authentication.
* Not supported for SASL/PLAIN with LDAP or when using `configOverrides`.
* Requires `FileBasedLoginModule`. This module is automatic with
  `jaasConfig`; you must configure it explicitly when using
  `jaasConfigPassthrough`.

### Update server-side SASL/PLAIN users

#### For jaasConfig

To add users to the authenticated users list, you need to update the list in the
text file and update the secret.

1. Fetch the user credentials defined under the key `plain-users.json` from
   the clusters secret using the following command:
   ```bash
   kubectl get secret -n <namespace> <NAME_OF_SECRET_FROM_JAAS_CONFIG> \
     --template="{{index .data \"plain-users.json\" | base64decode }}"
   ```

   * `<NAME_OF_SECRET_FROM_JAAS_CONFIG>` is the value corresponding to the
     secret referenced in the affected listener
     `spec.listeners.<listener-type>.authentication.jaasConfig.secretRef.name`
   * `<listener-type>` can be `external` or `custom` based on the listener
     type you use for the external client users.
2. Copy the contents of the output and save it in a new file called
   `creds-kafka-sasl-users.json`.
3. In the `creds-kafka-sasl-users.json` file, add the new user and its
   password.

   For example:
   ```json
   {
   "kafka_client": "kafka_client-secret",
   "c3": "c3-secret",
   "kafka": "kafka-secret",
   "new_user": "password"
   }
   ```
4. Update the Kubernetes secret.

   In the following command, you generate the YAML for the secret and apply it
   as an update to the existing secret, `credential`.

   For `--from-file`, you must use the `plain-users.json` key, as
   `--from-file=plain-users.json`.
   ```bash
   kubectl create secret generic credential \
     --from-file=plain-users.json=creds-kafka-sasl-users.json \
     --save-config --dry-run=client -oyaml | \
     kubectl apply -f -
   ```

You do not need to restart the Kafka brokers. The updated users list is picked up
by the services.

#### For jaasConfigPassThrough

To add users to the authenticated users list, you need to update the config file
in the secret and perform a rolling update of Kafka.

1. In `plain-jaas.conf`, add the new user and its password.

   For example:
   ```bash
   sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \
      username="admin" \
      password="admin-secret" \
      user_admin="admin-secret" \
      user_alice="alice-secret" \
      user_newuser="password";
   ```
2. Update the secret with the new file contents as described in the section
   above.
3. Update the Kubernetes secret.

   In the following command, you generate the YAML for the secret and apply it
   as an update to the existing secret, `credential`.

   For `--from-file`, you must use the `plain-jaas.conf` key, as
   `--from-file=plain-jaas.conf`.
   ```bash
   kubectl create secret generic credential \
     --from-file=plain-jaas.conf=plain-jaas.conf \
     --save-config --dry-run=client -oyaml | \
     kubectl apply -f -
   ```

You do not need to restart the Kafka brokers. The updated users list is picked up
by the services.

<a id="co-update-client-sasl-plain-users"></a>

### Update client-side SASL/PLAIN users using JAAS config

To update the user credentials, update the credentials in the text file and
update the secret:

1. In a text file, named `creds-kafka-sasl-users.txt`, update the following
   content:
   ```text
   username=<username>
   password=<password>
   ```
2. Create a Kubernetes secret.

   In the following command, you generate the YAML for the secret and apply it
   as an update to the existing secret, `credential`.

   For `--from-file`, you must use the `plain.txt` key, as `--from-file=plain.txt`.
   ```bash
   kubectl create secret generic credential \
     --from-file=plain.txt=creds-kafka-sasl-users.txt \
     --save-config --dry-run=client -oyaml | \
     kubectl apply -f -
   ```
3. Restart the Confluent Platform components that depends on the `plain.txt` key so that the
   updated user is picked up by the services.

<!-- _ co-update-sasl-oauth-users: -->

## Update Kafka or KRaft OAuth/OIDC users

Update the external-facing OAuth/OIDC client user credentials for Kafka or
KRaft by following the steps described in this section.

### Update server-side OAuth/OIDC users

1. Create a secret that contains the new OIDC client ID and the client secret
   for authorization and token request to the identity provider (IdP).

   The secret should contain two keys with their respective values, `clientId`
   and  `clientSecret` as follows:
   ```text
   clientId=<client-id>
   clientSecret=<client-secret>
   ```
2. Update the Kafka or KRaft CR to use the new secret and apply the changes.
   ```yaml
   kind: <Kafka or KRaftController>
   spec:
     listeners:
       internal / external:
         authentication:
           type: oauth
           jaasConfig/jaasConfigPassThrough:
             secretRef:
   ```

### Update client-side OAuth/OIDC users

#### IMPORTANT
The current/older OIDC client credential should be valid until the rotation
is completed and the component is rolled.

1. Create a secret that contains the new OIDC client ID and the client secret
   for authorization and token request to the identity provider (IdP).

   The secret should contain two keys with their respective values, `clientId`
   and  `clientSecret` as follows:
   ```text
   clientId=<client-id>
   clientSecret=<client-secret>
   ```
2. Update the client component CR to use the new secret and apply the changes.
   ```yaml
    kind: <Confluent component>
    spec:
      dependencies:
        kafka:
          authentication:
            type: oauth
            jaasConfig/jaasConfigPassThrough:
              secretRef:
   ```

<a id="co-update-mds-user"></a>

## Update MDS user

MDS uses a dedicated LDAP bind user, configured in
`spec.services.mds.provider.ldap`, to authenticate and search your LDAP
server. To rotate this credential, add a standby user and swap to it. Do not
change the password of the existing MDS bind user in place.

#### IMPORTANT
The current or older MDS user must remain valid until the new user is
confirmed working end-to-end. Changing the password of the existing MDS
bind user in place, instead of swapping to a new user, can leave brokers
unable to re-authenticate against MDS during the resulting rolling
restart.

To update the MDS user credentials:

1. Add a standby user (for example, `mds2`) to your LDAP server with a new
   password. Grant it the same bind and search access control lists (ACLs)
   as the existing MDS bind user.

   #### NOTE
   LDAP treats bind (authenticate) and search (query directory entries) as
   separate permissions. If the standby user has only bind rights, it
   authenticates successfully but fails when MDS searches the directory,
   with an error similar to `LDAP: error code 32 - No Such Object`.
   Confirm that the standby user has both bind and search ACLs before you
   continue.
2. Set the `platform.confluent.io/roll-delay-interval-seconds` annotation
   on the Kafka CR to increase the pacing between broker restarts, for
   example, to 300 seconds:
   ```yaml
   kind: Kafka
   metadata:
     annotations:
       platform.confluent.io/roll-delay-interval-seconds: "300"
   ```

   This gives the `_confluent-metadata-auth` topic and each broker’s
   authorizer time to stabilize before the next broker restarts. The default
   pacing is around 180 seconds.
3. Update the `.txt` file that contains the LDAP credentials with the
   standby user’s credentials, in the following format:
   ```text
   username=<bindDn_value>
   password=<bindPassword_value>
   ```

   For the password for `bindDn`, [escape](https://tools.ietf.org/html/rfc4514#section-2.4) any restricted LDAP
   characters. For best results, avoid characters that require escaping.
4. Create a **new** Secret with the expected key (`ldap.txt`) and the
   value file you created in the previous step, then update
   `spec.services.mds.provider.ldap.authentication.simple.secretRef` on
   the Kafka CR to point to the new Secret. Don’t patch the existing
   Secret’s content in place.
   ```bash
   kubectl create secret generic credential-mds2 \
     --from-file=ldap.txt=./ldap.txt
   ```

   ```yaml
   kind: Kafka
   spec:
     services:
       mds:
         provider:
           ldap:
             authentication:
               simple:
                 secretRef: credential-mds2
   ```

   #### IMPORTANT
   Patching an existing Secret’s content in place only gets CFK’s safe,
   paced rolling restart starting in CFK 3.2. On older operators, an
   in-place content edit can trigger a less-controlled restart, the
   exact behavior this procedure exists to avoid. Changing
   which Secret the CR’s `secretRef` field points to is a Kafka CR
   specification change, which has always gone through CFK’s paced,
   operator-controlled rolling restart, on every CFK version this
   procedure supports. For this reason, keep the MDS LDAP bind
   credential in its own dedicated Secret, separate from the Secret
   used for the Kafka/KRaft SASL/PLAIN listener authentication.

   For details on CFK’s secret-update behavior, see
   [Secret updates and safe rolling restarts](co-manage-certificates.md#secret-updates-safe-roll).
5. Before you decommission the old user, verify that the rotation succeeded:
   1. Confirm that all brokers reach the `Ready` state.
   2. Confirm that the `_confluent-metadata-auth` topic remains healthy and
      that port `9071` opens on each broker.
   3. Confirm that a produce or consume operation gated by a role binding
      succeeds for the standby user. Do not rely on pod status alone.
6. After verification succeeds, remove the old LDAP user from the LDAP
   server.

#### NOTE
Only the MDS bind user requires this standby-user swap. You can rotate
other server account passwords in place, using the same username, after
the MDS user rotation completes and the roll settles.
