// Module included in the following assemblies:
//
// assembly-security.adoc

[id='proc-replacing-your-own-private-keys-{context}']
= Renewing or replacing CA certificates and private keys with your own

[role="_abstract"]
If you are using your own CA certificates and private keys, you need to renew them manually.
The Cluster Operator will not renew them automatically.
Renew the CA certificates in the renewal period before they expire.
You can also use the same procedure to replace the CA certificates and private keys generated by the Strimzi operators with your own.

Perform the steps in this procedure when you are renewing or replacing CA certificates and private keys.
If you are only renewing your own CA certificates, see xref:renewing-your-own-ca-certificates-{context}[]. 

The procedure describes the renewal of CA certificates and private keys in PEM format.

Before going through the following steps, make sure that the CN (Common Name) of the new CA certificate is different from the current one.
For example, when the Cluster Operator renews certificates automatically it adds a _v<version_number>_ suffix to identify a version.
Do the same with your own CA certificate by adding a different suffix on each renewal.
By using a different key to generate a new CA certificate, you retain the current CA certificate stored in the `Secret`.

.Prerequisites

* The Cluster Operator is running.
* You have new cluster or clients X.509 certificates and keys in PEM format.

.Procedure

. Pause the reconciliation of the `Kafka` custom resource.
+
.. Annotate the custom resource in Kubernetes, setting the `pause-reconciliation` annotation to `true`:
+
[source,shell,subs="+quotes"]
----
kubectl annotate Kafka _<name_of_custom_resource>_ strimzi.io/pause-reconciliation="true"
----
+
For example, for a `Kafka` custom resource named `my-cluster`:
+
[source,shell,subs="+quotes"]
----
kubectl annotate Kafka my-cluster strimzi.io/pause-reconciliation="true"
----
.. Check that the status conditions of the custom resource show a change to `ReconciliationPaused`:
+
[source,shell,subs="+quotes"]
----
kubectl describe Kafka _<name_of_custom_resource>_
----
+
The `type` condition changes to `ReconciliationPaused` at the `lastTransitionTime`.

. Update the `Secret` for the CA certificate.

.. Edit the existing secret to add the new CA certificate and update the certificate generation annotation value.
+
[source,shell,subs="+quotes"]
kubectl edit secret _<ca_certificate_secret_name>_
+
_<ca_certificate_secret_name>_ is the name of the `Secret`, which is `_KAFKA-CLUSTER-NAME_-cluster-ca-cert` for the cluster CA certificate and `_KAFKA-CLUSTER-NAME_-clients-ca-cert` for the clients CA certificate.
+
The following example shows a secret for a cluster CA certificate that's associated with a Kafka cluster named `my-cluster`.
+
.Example secret configuration for a cluster CA certificate
[source,yaml,subs=attributes+]
----
apiVersion: v1
kind: Secret
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0F... # <1>
metadata:
  annotations:
    strimzi.io/ca-cert-generation: "0" # <2>
  labels:
    strimzi.io/cluster: my-cluster
    strimzi.io/kind: Kafka
  name: my-cluster-cluster-ca-cert
  #...
type: Opaque
----
<1> Current base64-encoded CA certificate
<2> Current CA certificate generation annotation value

.. Rename the current CA certificate to retain it.
+
Rename the current `ca.crt` property under `data` as `ca-__<date>__.crt`, where _<date>_ is the certificate expiry date in the format _YEAR-MONTH-DAYTHOUR-MINUTE-SECONDZ_.
For example `ca-2023-01-26T17-32-00Z.crt:`.
Leave the value for the property as it is to retain the current CA certificate.

.. Encode your new CA certificate into base64.
+
[source,shell,subs="+quotes"]
cat _<path_to_new_certificate>_ | base64

.. Update the CA certificate.
+
Create a new `ca.crt` property under `data` and copy the base64-encoded CA certificate from the previous step as the value for `ca.crt` property.
+
.. Increase the value of the CA certificate generation annotation.
+
Update the `strimzi.io/ca-cert-generation` annotation with a higher incremental value.
For example, change `strimzi.io/ca-cert-generation=0` to `strimzi.io/ca-cert-generation=1`.
If the `Secret` is missing the annotation, the value is treated as `0`, so add the annotation with a value of `1`.
+
When Strimzi generates certificates, the certificate generation annotation is automatically incremented by the Cluster Operator.
For your own CA certificates, set the annotations with a higher incremental value.
The annotation needs a higher value than the one from the current secret so that the Cluster Operator can roll the pods and update the certificates.
The `strimzi.io/ca-cert-generation` has to be incremented on each CA certificate renewal.

.. Save the secret with the new CA certificate and certificate generation annotation value.
+
.Example secret configuration updated with a new CA certificate
[source,yaml,subs=attributes+]
----
apiVersion: v1
kind: Secret
data:
  ca.crt: GCa6LS3RTHeKFiFDGBOUDYFAZ0F... # <1>
  ca-2023-01-26T17-32-00Z.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0F... # <2>
metadata:
  annotations:
    strimzi.io/ca-cert-generation: "1" # <3>
  labels:
    strimzi.io/cluster: my-cluster
    strimzi.io/kind: Kafka
  name: my-cluster-cluster-ca-cert
  #...
type: Opaque
----
<1> New base64-encoded CA certificate
<2> Old base64-encoded CA certificate
<3> New CA certificate generation annotation value

. Update the `Secret` for the CA key used to sign your new CA certificate.
+
.. Edit the existing secret to add the new CA key and update the key generation annotation value.
+
[source,shell,subs="+quotes"]
kubectl edit secret _<ca_key_name>_
+
_<ca_key_name>_ is the name of CA key, which is `_<kafka_cluster_name>_-cluster-ca` for the cluster CA key and `_<kafka_cluster_name>_-clients-ca` for the clients CA key.
+
The following example shows a secret for a cluster CA key that's associated with a Kafka cluster named `my-cluster`.
+
.Example secret configuration for a cluster CA key
[source,yaml,subs=attributes+]
----
apiVersion: v1
kind: Secret
data:
  ca.key: SA1cKF1GFDzOIiPOIUQBHDNFGDFS... # <1>
metadata:
  annotations:
    strimzi.io/ca-key-generation: "0" # <2>
  labels:
    strimzi.io/cluster: my-cluster
    strimzi.io/kind: Kafka
  name: my-cluster-cluster-ca
  #...
type: Opaque
----
<1> Current base64-encoded CA key
<2> Current CA key generation annotation value

.. Encode the CA key into base64.
+
[source,shell,subs="+quotes"]
cat _<path_to_new_key>_ | base64

.. Update the CA key.
+
Copy the base64-encoded CA key from the previous step as the value for the `ca.key` property under `data`.
+
.. Increase the value of the CA key generation annotation.
+
Update the `strimzi.io/ca-key-generation` annotation with a higher incremental value.
For example, change `strimzi.io/ca-key-generation=0` to `strimzi.io/ca-key-generation=1`.
If the `Secret` is missing the annotation, it is treated as `0`, so add the annotation with a value of `1`.
+
When Strimzi generates certificates, the key generation annotation is automatically incremented by the Cluster Operator.
For your own CA certificates together with a new CA key, set the annotation with a higher incremental value.
The annotation needs a higher value than the one from the current secret so that the Cluster Operator can roll the pods and update the certificates and keys.
The `strimzi.io/ca-key-generation` has to be incremented on each CA certificate renewal.

. Save the secret with the new CA key and key generation annotation value.
+
.Example secret configuration updated with a new CA key
[source,yaml,subs=attributes+]
----
apiVersion: v1
kind: Secret
data:
  ca.key: AB0cKF1GFDzOIiPOIUQWERZJQ0F... # <1>
metadata:
  annotations:
    strimzi.io/ca-key-generation: "1" # <2>
  labels:
    strimzi.io/cluster: my-cluster
    strimzi.io/kind: Kafka
  name: my-cluster-cluster-ca
  #...
type: Opaque
----
<1> New base64-encoded CA key
<2> New CA key generation annotation value

. Resume from the pause.
+
To resume the `Kafka` custom resource reconciliation, set the `pause-reconciliation` annotation to `false`.
+
[source,shell,subs="+quotes"]
----
kubectl annotate --overwrite Kafka _<name_of_custom_resource>_ strimzi.io/pause-reconciliation="false"
----
+
You can also do the same by removing the `pause-reconciliation` annotation.
+
[source,shell,subs="+quotes"]
----
kubectl annotate Kafka _<name_of_custom_resource>_ strimzi.io/pause-reconciliation-
----
+
On the next reconciliation, the Cluster Operator performs a rolling update of ZooKeeper, Kafka, and other components to trust the new CA certificate.
When the rolling update is complete, the Cluster Operator will start a new one to generate new server certificates signed by the new CA key.
+
If maintenance time windows are configured, the Cluster Operator will roll the pods at the first reconciliation within the next maintenance time window.

. Wait until the rolling updates to move to the new CA certificate are complete.

.  Remove any outdated certificates from the secret configuration to ensure that the cluster no longer trusts them.
+
[source,shell,subs="+quotes"]
kubectl edit secret _<ca_certificate_secret_name>_
+
.Example secret configuration with the old certificate removed
[source,yaml,subs=attributes+]
----
apiVersion: v1
kind: Secret
data:
  ca.crt: GCa6LS3RTHeKFiFDGBOUDYFAZ0F...
metadata:
  annotations:
    strimzi.io/ca-cert-generation: "1"
  labels:
    strimzi.io/cluster: my-cluster
    strimzi.io/kind: Kafka
  name: my-cluster-cluster-ca-cert
  #...
type: Opaque
----

. Start a manual rolling update of your cluster to pick up the changes made to the secret configuration.
+
See xref:assembly-rolling-updates-str[].
