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

# Manage TLS Certificates for Confluent Platform Using Confluent for Kubernetes

This topic describes how to manage Transport Layer Security (TLS) certificates
for Confluent Platform using Confluent for Kubernetes (CFK).

## Requirements and considerations

* Plan rotation before certificate expiry.
* There should be an overlap window between new and old certificates during the
  renewal process.
* Test the rotation process first in a lower-tier, non-production environment.

## Rotate user-provided server certificates

In CFK, to rotate user-provided certificates that have been
provided as Kubernetes secrets, you can update the contents of the Kubernetes
secrets.

For example, to rotate the server certificates that you provided in `.pem`
files:

1. Update the `server.pem` certificate and `server-key.pem` certificate
   private key.
2. Update the Kubernetes secret using the following command:
   ```bash
   kubectl create secret generic component-tls \
   --from-file=fullchain.pem=server.pem \
   --from-file=cacerts.pem=ca.pem \
   --from-file=privkey.pem=server-key.pem \
   --save-config --dry-run=client -oyaml | \
   kubectl apply -f -
   ```

CFK watches for secret changes, detects that the content
has changed, and performs a rolling restart of the component to configure the new
server certificate.

Note that CFK only watches the secrets provided in the `.pem` format. This
feature is not supported for the secrets provided in the `.jks` format.

<a id="secret-updates-safe-roll"></a>

## Secret updates and safe rolling restarts

Confluent for Kubernetes (CFK) now treats secret updates for Kafka and KRaft
similarly to ConfigMap updates when deciding whether to roll brokers.

Previously, changes to secrets (for example, TLS certificates) caused the
Kubernetes StatefulSet controller to roll pods directly, without CFK’s
under-replicated partition (URP) safety checks. This could lead to URPs and
cluster instability during certificate rotation and other secret changes. CFK
now tracks referenced secrets and performs an operator-controlled roll with
URP checks when they change, providing the same safety guarantees as for
ConfigMap-triggered rolls.

### Approaches to updating secrets

There are two ways to update secrets in CFK:

**Create a new secret and update references**

Create a new secret with updated values and modify the Kafka or KRaft CR spec
to reference the new secret name. This is treated as a specification change, which
triggers a safe rolling restart with URP checks and proper wait conditions.

**Update existing secret content**

Update the content of an existing secret without changing its name. Prior to
version 3.2, this approach was unsafe because it caused the StatefulSet
controller to roll pods directly without CFK’s URP safety checks. Starting in
version 3.2, CFK now tracks secret content changes and performs an
operator-controlled roll with URP checks, providing the same safety guarantees
as specification-based changes.

Both approaches now trigger safe rolling restarts with URP checks.

### How secret tracking works

CFK automatically discovers all secrets referenced in the Kafka or KRaft
custom resource (CR) spec (for example, TLS, listener, and authentication
secrets) and tracks their Kubernetes `resourceVersion` values. When any
tracked secret changes:

* CFK detects the change during reconciliation.
* CFK marks a rolling restart as required and updates the StatefulSet
  template with a partitioned rolling strategy.
* The operator-controlled roll runs one broker at a time, with URP and
  cluster-health checks between pod restarts.

This ensures that certificate rotation and other secret updates follow the
same safe roll pattern as other configuration changes.

### Controlling which secrets are tracked

You can fine-tune which secrets trigger a rolling restart using annotations on
the Kafka or KRaft CR.

* `platform.confluent.io/additional-tracked-secrets`

  Add a comma-separated list of extra secret names to track, beyond those
  discovered automatically from the spec.
  ```yaml
  annotations:
    platform.confluent.io/additional-tracked-secrets: "custom-secret-1,custom-secret-2"
  ```

  Use this when additional secrets are mounted or consumed in ways that are
  not explicitly referenced in the CR spec but should still trigger a safe
  roll when they change.
* `platform.confluent.io/exclude-tracked-secrets`

  Add a comma-separated list of secret names that **should not** trigger a
  roll, even if they are referenced in the spec.
  ```yaml
  annotations:
    platform.confluent.io/exclude-tracked-secrets: "monitoring-creds,logging-secret"
  ```

  Use this for secrets that do not affect runtime broker behavior, change
  frequently, or are only used by components that do not require a pod
  restart.

#### WARNING
Updating the `platform.confluent.io/additional-tracked-secrets` or
`platform.confluent.io/exclude-tracked-secrets` annotations on an
existing cluster changes the tracked secret set and triggers a rolling
restart. Configure these annotations when you create the cluster to avoid
unnecessary rolls.

**Viewing tracked secrets**

The final list of secrets currently being tracked and their versions is
available in the `platform.confluent.io/tracked-secrets-versions` annotation
on the Kafka or KRaft CR. This annotation is automatically maintained by CFK
and shows the resource version of each tracked secret.

## Rotate certificate authority for user-provided certificates

You can rotate the certificate authority (CA) that you provided as Kubernetes
secrets using the steps described in this section.

The examples use the `.pem` files for providing certificates.

### Step 1. Append new certificate authority

1. Append the new intermediate/root CA to the `ca.pem` file. It co-exists
   with the old intermediate/root CA.
   ```bash
   file name: ca.pem
   content:
   -----BEGIN CERTIFICATE-----
   <old root CA certificate>
   -----END CERTIFICATE-----
   -----BEGIN CERTIFICATE-----
   <new root CA certificate>
   -----END CERTIFICATE-----
   ```
2. Update the secret:
   ```bash
   kubectl create secret generic component-tls \
   --from-file=fullchain.pem=server.pem \
   --from-file=cacerts.pem=ca.pem \
   --from-file=privkey.pem=server-key.pem \
   --save-config --dry-run=client -oyaml | \
   kubectl apply -f -
   ```

CFK watches for secret changes, detects that the content
has changed, and performs a rolling restart for the component to configure the new
root CA for use alongside the old root CA.

If this CA is for Kafka and the [dynamic loading is
enabled](co-network-encryption.md#co-dynamic-certificates-update), the cluster does not roll.

### Step 2. Generate server certificates with new certificate authority

1. Generate the new server certificates with the new CA, and replace the
   `server.pem` certificate and the `server-key.pem` certificate private
   key.
2. Update the Kubernetes secret:
   ```bash
   kubectl create secret generic component-tls \
   --from-file=fullchain.pem=server.pem \
   --from-file=cacerts.pem=ca.pem \
   --from-file=privkey.pem=server-key.pem \
   --save-config --dry-run=client -oyaml | \
   kubectl apply -f -
   ```

CFK watches for secret changes, detects that the content
has changed, and performs a rolling restart for the component to configure the new
server certificate.

If this certificate is for Kafka and the [dynamic loading is enabled](co-network-encryption.md#co-dynamic-certificates-update), the cluster does not roll.

<a id="co-rotate-auto-generated-certificates-ca"></a>

## Rotate certificate authority used for auto-generated certificates

In CFK, you can provide a certificate authority (CA) for Confluent Platform components to use
for auto-generated certificates.

CA certificate rotation is a critical security operation that replaces an existing CA with a new one while maintaining service availability.

Follow the steps described in this section to renew the truststore and
auto-generated certificates. This process maintains service availability
throughout without downtime.

Wait for each step to complete before moving to the next step.

### Important considerations

* Do not apply both `force-managed-truststore-renewal` and
  `force-managed-cert-renewal` annotations simultaneously.
* Always renew truststores for all components before renewing certificates.
* Wait for each component’s rollout to complete before proceeding.
* Plan rotation before certificate expiry.
* Securely store and manage CA private keys.
* Test the rotation process in a non-production environment first.

### Step 1. Update CFK configuration

1. Prepare CA certificates.

   Identify your existing (old) CA certificate currently used by the cluster,
   and generate a new CA certificate to rotate to. If your cluster was not
   previously configured with an explicit `oldCaCertificate`, prepare the
   in-use CA so that it can be referenced as the old CA in the steps that
   follow.
2. Create Kubernetes or Vault secrets for the CA certificates.

   For example:
   ```bash
   # Create secret for new CA
   kubectl -n <namespace> create secret tls ca-pair-sslcerts-new \
     --cert=new/ca.pem --key=new/ca-key.pem
   ```
3. Update your CFK configuration to include both old and new CA
   certificates.

   `caCertificate` and `oldCaCertificate` support both `secretRef`
   (Kubernetes secret) and `directoryPathInContainer` (Vault directory path).
   When both are provided, `directoryPathInContainer` is used.

   For example:
   ```yaml
   managedCerts:
     enabled: true
     caCertificate:
       secretRef: ca-pair-sslcerts-new  # Your new CA secret
     oldCaCertificate:
       secretRef: ca-pair-sslcerts      # Your old CA secret
   ```
4. Apply the configuration.
   ```bash
   helm upgrade --install -f values.yaml operator confluent-for-kubernetes \
     --namespace <namespace>
   ```

### Step 2. Renew truststore

1. Apply the truststore renewal annotation to each Confluent Platform component.
   ```bash
   kubectl annotate <Component CR type> <Component CR name> platform.confluent.io/force-managed-truststore-renewal="true"
   ```
2. Verify that all components truststores now have dual CAs, both old and new
   CA.
   ```bash
   kubectl exec <pod-name> -- keytool -list \
     -keystore /mnt/sslcerts/truststore.jks \
     -storepass mystorepassword | grep -c "Certificate fingerprint"
   ```

   You should see two certificates in each truststore.

### Step 3. Renew certificates

1. Apply the certificate renewal annotation to each Confluent Platform component.
   ```bash
   kubectl annotate <Component CR type> <Component CR name> platform.confluent.io/force-managed-cert-renewal="true"
   ```
2. Verify that all certificates are now signed by the new CA:
   ```bash
   kubectl exec <pod-name> -- openssl x509 -in /mnt/sslcerts/tls.crt -text -noout | grep "Issuer:"
   ```

   The issuer should show your new CA.

<a id="co-manage-auto-generated-certificates"></a>

## Manage auto-generated certificates

To manage auto-generated certificates in Confluent for Kubernetes (CFK), use the following
annotations in the Confluent Platform component CRs.

* Force a renewal of auto-generated certificates:
  ```bash
  kubectl annotate <Component CR type> <Component CR name> \
    platform.confluent.io/force-managed-cert-renewal="true"
  ```

  The annotation triggers a reconciliation on the Confluent Platform component. The process causes
  the certificates to be renewed, and the component to be rolled.

  After the certificates are renewed, the annotation is reset to `false`.
* Add additional custom SAN for auto-generated certificates.
  This will be added to SANs defined at the global level in
  `managedCerts.sans` in the CFK Helm values
  (in [values.yaml](co-deploy-custom-values.md#co-values-file)).
  ```bash
  kubectl annotate secret ca-pair-sslcerts \
    platform.confluent.io/managed-cert-add-sans="<Comma separated list of SANs>"
  ```

  For example, the following annotation will add the SANs, `kafka.operator`,
  `kafka.operator.local`, to auto-generated certificates for Kafka:
  ```bash
  kubectl annotate secret ca-pair-sslcerts \
    platform.confluent.io/managed-cert-add-sans="kafka.operator, kafka.operator.local"
  ```

  After the annotation is set, use the
  `platform.confluent.io/force-managed-cert-renewal="true"` annotation to
  force a renewal of certificates. If not forced, SANs will be updated during
  the next reconciliation.
* Specify the Kubernetes secret name for the CA certificates at the CR level.
  This will override the global config defined in
  `managedCerts.caCertificate` in the CFK Helm values
  (in [values.yaml](co-deploy-custom-values.md#co-values-file)). This can be used even if
  `managedCerts.enable` is set to `false`.
  ```bash
  kubectl annotate <Component CR type> <Component CR name> \
    platform.confluent.io/managed-cert-ca-pair-secret=<Secret name>
  ```

  The secret should have `tls.crt` and `tls.key` with the CA certificate
  and key.
* Configure the optional settings for auto-generated certificates at the CR
  level:
  ```bash
  kubectl annotate <Component CR type> <Component CR name> \
    platform.confluent.io/managed-cert-duration-in-days=<Number of days>
  ```

  ```bash
  kubectl annotate <Component CR type> <Component CR name> \
    platform.confluent.io/managed-cert-renew-before-in-days=<Number of days>
  ```

  For example:
  ```bash
  kubectl annotate kafka kafka platform.confluent.io/managed-cert-duration-in-days=60

  kubectl annotate kafka kafka platform.confluent.io/managed-cert-renew-before-in-days=30
  ```

  After the annotations are set, use the
  `platform.confluent.io/force-managed-cert-renewal="true"` to force a renewal
  of certificates.
