How to Rotate a Certificate

This guide shows you how to replace the certificate a component uses, both when cert-manager issues it and when the certificate is signed elsewhere and managed by hand, and how to confirm the component picked up the replacement.

Type

How-to guide

Goal

Replace the certificate in a Secret and get the component using the new one.

Audience

Platform Operator who can delete and edit Secrets, and restart pods, in the target namespace.

When to use

Use this guide when a certificate is approaching expiry, or when it has been reissued by an authority the platform already trusts.

Replacing the authority itself is a different job, because every component and every client application has to trust the new authority before anything presents a certificate from it. How to Replace the Root Certificate Authority covers that migration.

Prerequisites

Confirm the following before you begin.

Access and permissions required

You need the following access and permissions:

  • Permission to get, edit and delete Secrets in the namespace the component runs in.

  • Permission to delete pods, or to trigger a rollout, for the components that mount the Secret.

Tools and versions required

You need the following tools:

  • kubectl >= 1.28, with access to the target namespace.

  • base64, for the manual path only.

Resources that must exist before starting

The following must already exist:

  • The Secret the component currently reads, in one of the shapes described in Secret formats.

  • A cert-manager Certificate resource requesting the certificate, for the cert-manager path. Without it, deleting the Secret leaves nothing to recreate it.

  • The replacement certificate and private key, for the manual path.

Rotate a certificate cert-manager issued

cert-manager issues a replacement on its own once renewalTime passes, writing new tls.crt and tls.key values into the target Secret. Follow the steps below to force that rotation early, or to recover a Secret whose contents are wrong.

A renewed Secret can look untouched, because its creation timestamp does not change. Compare the data, not the metadata.
Replace every <VALUE> placeholder with your own value before running a command.
  1. Confirm the Certificate resource exists, so cert-manager has an instruction to act on.

    kubectl get certificate <CERTIFICATE_NAME> --namespace <NAMESPACE>
  2. Copy the current Secret to a local file, so the old certificate is recoverable if the new one is wrong.

    kubectl get secret <SECRET_NAME> --namespace <NAMESPACE> -o yaml > <SECRET_NAME>-backup.yaml
  3. Delete the Secret. cert-manager recreates it immediately with a freshly issued certificate.

    kubectl delete secret <SECRET_NAME> --namespace <NAMESPACE>
  4. Restart every component that mounts the Secret. Without a restart the component keeps serving the certificate it loaded at startup.

    kubectl rollout restart deployment/<DEPLOYMENT_NAME> --namespace <NAMESPACE>
    Install Reloader to have this restart happen automatically on every renewal, and skip this step from then on.

Rotate a manually managed certificate

Follow these steps for a certificate signed outside the cluster, where no Certificate resource exists to reissue it.

  1. Copy the current Secret to a local file, as above. This is the only copy of the old data once you overwrite it.

    kubectl get secret <SECRET_NAME> --namespace <NAMESPACE> -o yaml > <SECRET_NAME>-backup.yaml
  2. Base64 encode the new certificate and private key. Kubernetes Secrets hold base64 encoded data, and an unencoded value fails at mount time.

    base64 -i <CERTIFICATE_FILE>.pem
    base64 -i <PRIVATE_KEY_FILE>.pem
  3. Replace the values in the Secret, keeping the existing data field names.

    kubectl edit secret <SECRET_NAME> --namespace <NAMESPACE>
    Reuse the field names already in the Secret, such as tls.crt and tls.key. The component reads fixed field names, so a renamed field is an absent field. The names each shape uses are listed in Secret formats.
  4. Restart every component that mounts the Secret, with the same command as the cert-manager path.

Confirm the component uses the new certificate

Read the certificate back off the live endpoint rather than out of the Secret, because that is the only check that proves the component reloaded.

openssl s_client -connect <HOST>:<PORT> -showcerts

The notAfter date in the output is the new one when rotation succeeded, and the old one when the pod has not restarted. How to Inspect a Certificate covers the other ways to read the same values.

Then confirm the component is serving traffic, and that its logs hold no TLS handshake failures. A certificate the component trusts but its peers do not produces a working pod and failing connections.