Certificates
============

EDB Postgres for Kubernetes was designed to natively support TLS
certificates. To set up a cluster, the operator requires:

- A server certification authority (CA) certificate

- A server TLS certificate signed by the server CA

- A client CA certificate

- A streaming replication client certificate generated by the client CA

..  Note::
   You can find all the secrets used by the cluster and their expiration dates in the cluster's status.

EDB Postgres for Kubernetes is very flexible when it comes to TLS
certificates. It primarily operates in two modes:

1. :ref:`Operator-Managed Mode <Operator-Managed Mode>`  – Certificates are internally managed by the operator
   in a fully automated way and signed using a CA created by EDB
   Postgres for Kubernetes.

2. :ref:`User-provided certificates mode <User-provided certificates mode>`  – Certificates are generated outside the operator and
   imported in the cluster definition as secrets. EDB Postgres for
   Kubernetes integrates itself with `cert-manager <https://cert-manager.io/>`_ 

(See :ref:`Cert-manager example <Cert-manager example>`  .)

You can also choose a hybrid approach, where only part of the
certificates is generated outside CNP.

..  Note::
   The operator and instances verify server certificates against the CA only, disregarding the DNS name. This approach is due to the typical absence of DNS names in user-provided certificates for the `<cluster>-rw`  service used for communication within the cluster.

Operator-Managed Mode
---------------------

By default, the operator automatically generates a single Certificate
Authority (CA) to issue both client and server certificates. These
certificates are managed continuously by the operator, with automatic
renewal 7 days before expiration (within a 90-day validity period).

..  Note::
   You can adjust this default behavior by configuring the `CERTIFICATE_DURATION`  and `EXPIRING_CHECK_THRESHOLD`  environment variables. For detailed guidance, refer to the  :ref:`Operator configuration <Operator configuration>`  .

..  Important::
   Certificate renewal does not cause any downtime for the PostgreSQL server, as a simple reload operation is sufficient. However, any user-managed certificates not controlled by EDB Postgres for Kubernetes must be re-issued following the renewal process.

Server certificates
^^^^^^^^^^^^^^^^^^^

Server CA secret
^^^^^^^^^^^^^^^^

The operator generates a self-signed CA and stores it in a generic
secret containing the following keys:

- ``ca.crt`` – CA certificate used to validate the server certificate,
  used as ``sslrootcert`` in clients’ connection strings.

- ``ca.key`` – The key used to sign the server SSL certificate
  automatically.

Server TLS secret
^^^^^^^^^^^^^^^^^

The operator uses the generated self-signed CA to sign a server TLS
certificate. It’s stored in a secret of type ``kubernetes.io/tls`` and
configured to be used as ``ssl_cert_file`` and ``ssl_key_file`` by the
instances. This approach enables clients to verify their identity and
connect securely.

Server alternative DNS names
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In addition to the default ones, you can specify DNS server alternative
names as part of the generated server TLS secret.

Client certificates
^^^^^^^^^^^^^^^^^^^

Client CA secret
^^^^^^^^^^^^^^^^

By default, the same self-signed CA as the server CA is used. The public
part is passed as ``ssl_ca_file`` to all the instances so it can verify
client certificates it signed. The private key is stored in the same
secret and used to sign client certificates generated by the
``kubectl cnp`` plugin.

Client ``streaming_replica`` certificate
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The operator uses the generated self-signed CA to sign a client
certificate for the user ``streaming_replica`` , storing it in a secret
of type ``kubernetes.io/tls`` . To allow secure connection to the
primary instance, this certificate is passed as ``sslcert`` and
``sslkey`` in the replicas’ connection strings.

User-provided certificates mode
-------------------------------

.. _server-certificates-1:

Server certificates
^^^^^^^^^^^^^^^^^^^

If required, you can also provide the two server certificates,
generating them using a separate component such as `cert-manager <https://cert-manager.io/>`_  . To
use a custom server TLS certificate for a cluster, you must specify the
following parameters:

- ``serverTLSSecret`` – The name of a secret of type
  ``kubernetes.io/tls`` containing the server TLS certificate. It must
  contain both the standard ``tls.crt`` and ``tls.key`` keys.

- ``serverCASecret`` – The name of a secret containing the ``ca.crt``
  key.

..  Note::
   The operator still creates and manages the two secrets related to client certificates.

..  Note::
   The operator and instances verify server certificates against the CA only, disregarding the DNS name. This approach is due to the typical absence of DNS names in user-provided certificates for the `<cluster>-rw`  service used for communication within the cluster.

..  Note::
   If you want ConfigMaps and secrets to be reloaded by instances, you can add a label with the key `k8s.enterprisedb.io/reload`  to it. Otherwise you must reload the instances using the `kubectl cnp reload`  subcommand.

Example
^^^^^^^

Given the following files:

- ``server-ca.crt`` – The certificate of the CA that signed the server
  TLS certificate.

- ``server.crt`` – The certificate of the server TLS certificate.

- ``server.key`` – The private key of the server TLS certificate.

Create a secret containing the CA certificate:

.. code:: sh

   kubectl create secret generic my-postgresql-server-ca \
     --from-file=ca.crt=./server-ca.crt

Create a secret with the TLS certificate:

.. code:: sh

   kubectl create secret tls my-postgresql-server \
     --cert=./server.crt --key=./server.key

Create a PostgreSQL cluster referencing those secrets:

.. code:: bash

   kubectl apply -f - <<EOF
   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example
   spec:
     instances: 3
     certificates:
       serverCASecret: my-postgresql-server-ca
       serverTLSSecret: my-postgresql-server
     storage:
       storageClass: standard
       size: 1Gi
   EOF

The new cluster uses the provided server certificates for TLS
connections.

Cert-manager example
^^^^^^^^^^^^^^^^^^^^

This simple example shows how to use `cert-manager <https://cert-manager.io/>`_ 

to set up a self-signed CA and generate the needed TLS server
certificate:

.. code:: yaml

   - --
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: selfsigned-issuer
   spec:
     selfSigned: {}
   - --
   apiVersion: v1
   kind: Secret
   metadata:
     name: my-postgres-server-cert
     labels:
       k8s.enterprisedb.io/reload: ""
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: my-postgres-server-cert
   spec:
     secretName: my-postgres-server-cert
     usages:
       - server auth
     dnsNames:
       - cluster-example-lb.internal.mydomain.net
       - cluster-example-rw
       - cluster-example-rw.default
       - cluster-example-rw.default.svc
       - cluster-example-r
       - cluster-example-r.default
       - cluster-example-r.default.svc
       - cluster-example-ro
       - cluster-example-ro.default
       - cluster-example-ro.default.svc
     issuerRef:
       name: selfsigned-issuer
       kind: Issuer
       group: cert-manager.io

Cert-manager creates a secret named ``my-postgres-server-cert`` . It
contains all the needed files and can be referenced from a cluster as
follows:

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example
   spec:
     instances: 3
     certificates:
       serverTLSSecret: my-postgres-server-cert
       serverCASecret: my-postgres-server-cert
     storage:
       size: 1Gi

You can find a complete example using cert-manager to manage both server
and client CA and certificates in the deployment manifest.

::

   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: selfsigned-issuer
   spec:
     selfSigned: {}
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: server-ca
   spec:
     isCA: true
     commonName: my-selfsigned-server-ca
     secretName: server-ca-key-pair
     privateKey:
       algorithm: ECDSA
       size: 256
     issuerRef:
       name: selfsigned-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: server-ca-issuer
   spec:
     ca:
       secretName: server-ca-key-pair
   - --
   apiVersion: v1
   kind: Secret
   metadata:
     name: my-postgres-server-cert
     labels:
       k8s.enterprisedb.io/reload: ""
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: my-postgres-server-cert
   spec:
     secretName: my-postgres-server-cert
     usages:
       - server auth
     dnsNames:
       - cluster-example-lb.internal.mydomain.net
       - cluster-example-rw
       - cluster-example-rw.default
       - cluster-example-rw.default.svc
       - cluster-example-r
       - cluster-example-r.default
       - cluster-example-r.default.svc
       - cluster-example-ro
       - cluster-example-ro.default
       - cluster-example-ro.default.svc
     issuerRef:
       name: server-ca-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: client-ca
   spec:
     isCA: true
     commonName: my-selfsigned-client-ca
     secretName: client-ca-key-pair
     privateKey:
       algorithm: ECDSA
       size: 256
     issuerRef:
       name: selfsigned-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: client-ca-issuer
   spec:
     ca:
       secretName: client-ca-key-pair
   - --
   apiVersion: v1
   kind: Secret
   metadata:
     name: my-postgres-client-cert
     labels:
       k8s.enterprisedb.io/reload: ""
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: my-postgres-client-cert
   spec:
     secretName: my-postgres-client-cert
     usages:
       - client auth
     commonName: streaming_replica
     issuerRef:
       name: client-ca-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example
   spec:
     instances: 3
     certificates:
       serverTLSSecret: my-postgres-server-cert
       serverCASecret: my-postgres-server-cert
       clientCASecret: my-postgres-client-cert
       replicationTLSSecret: my-postgres-client-cert
     storage:
       size: 1Gi

Client certificate
^^^^^^^^^^^^^^^^^^

If required, you can also provide the two client certificates,
generating them using a separate component such as `cert-manager <https://cert-manager.io/>`_  or
`HashiCorp vault <https://www.vaultproject.io/docs/secrets/pki>`_  . To use a custom CA to verify client certificates for a
cluster, you must specify the following parameters:

- ``replicationTLSSecret`` – The name of a secret of type
  ``kubernetes.io/tls`` containing the client certificate for user
  ``streaming_replica`` . It must contain both the standard ``tls.crt``
  and ``tls.key`` keys.

- ``clientCASecret`` – The name of a secret containing the ``ca.crt``
  key of the CA to use to verify client certificate.

..  Note::
   The operator still creates and manages the two secrets related to server certificates.

..  Note::
   As the cluster isn't in control of the client CA secret key, you can no longer generate client certificates using `kubectl cnp certificate` .

..  Note::
   If you want ConfigMaps and secrets to be automatically reloaded by instances, you can add a label with the key `k8s.enterprisedb.io/reload`  to it. Otherwise, you must reload the instances using the `kubectl cnp reload`  subcommand.

.. _cert-manager-example-1:

Cert-manager example
^^^^^^^^^^^^^^^^^^^^

This simple example shows how to use `cert-manager <https://cert-manager.io/>`_ 

to set up a self-signed CA and generate the needed TLS server
certificate:

.. code:: yaml

   - --
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: selfsigned-issuer
   spec:
     selfSigned: {}
   - --
   apiVersion: v1
   kind: Secret
   metadata:
     name: my-postgres-client-cert
     labels:
       k8s.enterprisedb.io/reload: ""
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: my-postgres-client-cert
   spec:
     secretName: my-postgres-client-cert
     usages:
       - client auth
     commonName: streaming_replica
     issuerRef:
       name: selfsigned-issuer
       kind: Issuer
       group: cert-manager.io

Cert-manager creates a secret named ``my-postgres-client-cert`` that
contains all the needed files. You can reference it from a cluster as
follows:

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example
   spec:
     instances: 3
     certificates:
       clientCASecret: my-postgres-client-cert
       replicationTLSSecret: my-postgres-client-cert
     storage:
       size: 1Gi

You can find a complete example using cert-manager to manage both server
and client CA and certificates in the deployment manifest.

::

   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: selfsigned-issuer
   spec:
     selfSigned: {}
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: server-ca
   spec:
     isCA: true
     commonName: my-selfsigned-server-ca
     secretName: server-ca-key-pair
     privateKey:
       algorithm: ECDSA
       size: 256
     issuerRef:
       name: selfsigned-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: server-ca-issuer
   spec:
     ca:
       secretName: server-ca-key-pair
   - --
   apiVersion: v1
   kind: Secret
   metadata:
     name: my-postgres-server-cert
     labels:
       k8s.enterprisedb.io/reload: ""
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: my-postgres-server-cert
   spec:
     secretName: my-postgres-server-cert
     usages:
       - server auth
     dnsNames:
       - cluster-example-lb.internal.mydomain.net
       - cluster-example-rw
       - cluster-example-rw.default
       - cluster-example-rw.default.svc
       - cluster-example-r
       - cluster-example-r.default
       - cluster-example-r.default.svc
       - cluster-example-ro
       - cluster-example-ro.default
       - cluster-example-ro.default.svc
     issuerRef:
       name: server-ca-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: client-ca
   spec:
     isCA: true
     commonName: my-selfsigned-client-ca
     secretName: client-ca-key-pair
     privateKey:
       algorithm: ECDSA
       size: 256
     issuerRef:
       name: selfsigned-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: cert-manager.io/v1
   kind: Issuer
   metadata:
     name: client-ca-issuer
   spec:
     ca:
       secretName: client-ca-key-pair
   - --
   apiVersion: v1
   kind: Secret
   metadata:
     name: my-postgres-client-cert
     labels:
       k8s.enterprisedb.io/reload: ""
   - --
   apiVersion: cert-manager.io/v1
   kind: Certificate
   metadata:
     name: my-postgres-client-cert
   spec:
     secretName: my-postgres-client-cert
     usages:
       - client auth
     commonName: streaming_replica
     issuerRef:
       name: client-ca-issuer
       kind: Issuer
       group: cert-manager.io
   - --
   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example
   spec:
     instances: 3
     certificates:
       serverTLSSecret: my-postgres-server-cert
       serverCASecret: my-postgres-server-cert
       clientCASecret: my-postgres-client-cert
       replicationTLSSecret: my-postgres-client-cert
     storage:
       size: 1Gi
