Skip to content

Rate this page
Thanks for your feedback
Thank you! The feedback has been submitted.

Get free database assistance or contact our experts for personalized support.

Configure TLS security with the Operator using cert-manager

Starting with version 2.9.0, the Percona Operator for PostgreSQL integrates with cert-manager for TLS certificate management.

When the Operator creates a database cluster, it checks if the cert-manager is installed and if you haven’t provided custom TLS secrets. If these conditions are met, the Operator creates the self-signed Issuer resource within the cert-manager and requests a certificate from it. The cert-manager generates certificates and stores them in Kubernetes Secrets. The Operator uses these Secrets for TLS in the cluster. The cert-manager manages the certificate lifecycle.

The Percona Operator self-signed issuer is local to the Operator namespace. This self-signed issuer is created because Percona Distribution for PostgreSQL requires all certificates issued by the same CA (Certificate authority).

If cert-manager is not installed or not ready, the Operator falls back to its built-in certificate generation.

This approach gives you:

  • Automatic renewal – cert-manager renews certificates before they expire (by default, 30 days before expiry)
  • Configurable validity – you can set certificate and CA validity durations via Custom Resource options
  • Centralized management – use cert-manager’s tooling and policies for all TLS certificates in the cluster

Certificate lifecycle management

The cert-manager handles:

  • Issuance – creates certificates when the cluster is created
  • Renewal – renews certificates before expiry (default: 30 days before). You can configure the certificate duration in the Custom Resource
  • Rotation – updates Secrets when certificates are renewed

The Operator does not renew certificates when using cert-manager; cert-manager does. You do not need to restart the cluster when certificates are renewed.

Prerequisites

To use cert-manager with the Operator, ensure the following:

  1. You have deployed the Operator. Check if it runs with kubectl get deploy -n <namespace> command.
  2. Your Custom Resource does not include these options:

    • secrets.customTLSSecret
    • secrets.customReplicationTLSSecret
    • secrets.customRootCATLSSecret

    If you provide any of these, the Operator uses your custom certificates and does not create cert-manager resources.

Install cert-manager

Install cert-manager before deploying the Operator and cluster. You can use either kubectl or Helm.

By default the cert-manager is installed in the cert-manager namespace.

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.20.0/cert-manager.yaml 

??? example “Expected output”

 ```{.text .no-copy}
 namespace/cert-manager created
 customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
 customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
 customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
 customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
 customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
 customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
 serviceaccount/cert-manager-cainjector created
 serviceaccount/cert-manager created
 serviceaccount/cert-manager-webhook created
 clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
 clusterrole.rbac.authorization.k8s.io/cert-manager-cluster-view created
 clusterrole.rbac.authorization.k8s.io/cert-manager-view created
 clusterrole.rbac.authorization.k8s.io/cert-manager-edit created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
 clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
 clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
 clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
 role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
 role.rbac.authorization.k8s.io/cert-manager:leaderelection created
 role.rbac.authorization.k8s.io/cert-manager-tokenrequest created
 role.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
 rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
 rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created
 rolebinding.rbac.authorization.k8s.io/cert-manager-cert-manager-tokenrequest created
 rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
 service/cert-manager-cainjector created
 service/cert-manager created
 service/cert-manager-webhook created
 deployment.apps/cert-manager-cainjector created
 deployment.apps/cert-manager created
 deployment.apps/cert-manager-webhook created
 mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
 validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
 ```
  1. Add the Helm chart and update the repositories

    helm repo add jetstack https://charts.jetstack.io --force-update
    helm repo update
    
  2. Install cert-manager with default parameters:

    helm install cert-manager jetstack/cert-manager \
      --namespace cert-manager \
      --create-namespace \
      --version v1.20.0 \
      --set crds.enabled=true
    
    Expected output
    Pulled: quay.io/jetstack/charts/cert-manager:v1.19.4
    Digest: sha256:135b97727e98ab0af229c2dceaf2e2c3c074a7b83495c6e09a1697c85e5ef6c7
    NAME: cert-manager
    LAST DEPLOYED: Wed Feb 25 16:43:23 2026
    NAMESPACE: cert-manager
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    

    You can customize the Helm installation by passing the TLS options via values.yaml or --set. See the percona-helm-charts repository for the available parameters.

Verify that cert-manager is running:

kubectl get pods -n cert-manager
Expected output
cert-manager-548f7cf98c-kjrvx             1/1     Running   0          22s
cert-manager-cainjector-8798f647f-kv9j4   1/1     Running   0          23s
cert-manager-webhook-6c8678dc46-whmxp     1/1     Running   0          22s

Configure the certificate validity

  1. Add the tls section to your Custom Resource to set certificate validity durations. These options apply only when cert-manager is used.

    spec:
      tls:
        certValidityDuration: 2160h   # 90 days for TLS certificates (default: 8760h / 1 year)
        caValidityDuration: 26280h    # 3 years for the CA certificate (default: 8760h / 1 year)
        pgBackRestCertValidityDuration: 2160H # 90 days for TLS certificates 
    

    Use Go duration format (e.g. 2160h, 8760h).

  2. Deploy the cluster:

    kubectl apply -f deploy/cr.yaml -n <namespace>
    

Once you create the database with the Operator, it will automatically trigger the cert-manager to create certificates. Whenever you check certificates for expiration, you will find that they are valid and short-term.

Verify cert-manager resources

After the cluster is created, you can inspect the cert-manager resources:

# List Issuers
kubectl get issuers -n <namespace>

# List Certificates
kubectl get certificates -n <namespace>

# Check certificate status
kubectl get certificate <cluster-name>-cluster-ca-cert -n <namespace> -o yaml

The Operator creates Issuers and Certificates in the same namespace as the cluster. Secrets created by cert-manager follow the same naming as with built-in certificate generation (e.g. <cluster-name>-cluster-ca-cert, <cluster-name>-cluster-cert, <cluster-name>-replication-cert).


Last update: March 26, 2026
Created: March 26, 2026