Installation and upgrades v1.30.0-rc1

OpenShift

For instructions on how to install Cloud Native PostgreSQL on Red Hat OpenShift Container Platform, please refer to the "OpenShift" section.

Warning

OLM (via operatorhub.io is no longer supported as an installation method for EDB Postgres® AI for CloudNativePG™ Cluster.

Installation on Kubernetes

Obtaining an EDB subscription token

Important

You must obtain an EDB subscription token to install EDB Postgres® AI for CloudNativePG™ Cluster. Without a token, you will not be able to access the EDB private software repositories.

Installing EDB Postgres Distributed for Kubernetes requires an EDB Repos 2.0 token to gain access to the EDB private software repositories. For instructions on obtaining this token, see: Get your token.

Then set the Repos 2.0 token as an environment variable EDB_SUBSCRIPTION_TOKEN:

EDB_SUBSCRIPTION_TOKEN=<your-token>
Warning

The token is sensitive information. Please ensure that you don't expose it to unauthorized users.

You can now proceed with the installation.

Using the Helm Chart

The operator can be installed using the provided Helm chart.

Directly using the operator manifest

Install the EDB pull secret

Before installing EDB Postgres® AI for CloudNativePG™ Cluster, you need to create a pull secret for EDB software in the postgresql-operator-system namespace.

The pull secret needs to be saved in the namespace where the operator will reside. Create the postgresql-operator-system namespace using this command:

kubectl create namespace postgresql-operator-system

To create the pull secret itself, run the following command:

kubectl create secret -n postgresql-operator-system docker-registry edb-pull-secret \
  --docker-server=docker.enterprisedb.com \
  --docker-username=k8s \
  --docker-password="$EDB_SUBSCRIPTION_TOKEN"

Install the operator

Now that the pull-secret has been added to the namespace, the operator can be installed like any other resource in Kubernetes, through a YAML manifest applied via kubectl.

You can install the latest operator manifest for this minor release as follows:

kubectl apply --server-side -f \
  https://get.enterprisedb.io/pg4k/pg4k-1.30.0-rc1.yaml

You can verify that with:

kubectl rollout status deployment \
  -n postgresql-operator-system postgresql-operator-controller-manager

Using the cnp plugin for kubectl

You can use the cnp plugin to override the default configuration options that are in the static manifests.

For example, to generate the default latest manifest but change the watch namespaces to only be a specific namespace, you could run:

kubectl cnp install generate \
  --watch-namespace "specific-namespace" \
  > cnp_for_specific_namespace.yaml

Please refer to "cnp plugin" documentation for a more comprehensive example.

Warning

If you are deploying EDB Postgres® AI for CloudNativePG™ Cluster on GKE and get an error (... failed to call webhook...), be aware that by default traffic between worker nodes and control plane is blocked by the firewall except for a few specific ports, as explained in the official docs and by this issue. You'll need to either change the targetPort in the webhook service, to be one of the allowed ones, or open the webhooks' port (9443) on the firewall.

Details about the deployment

In Kubernetes, the operator is by default installed in the postgresql-operator-system namespace as a Kubernetes Deployment. The name of this deployment depends on the installation method. When installed through the manifest or the cnp plugin, by default, it is called postgresql-operator-controller-manager. When installed via Helm, by default, the deployment name is derived from the helm release name, appended with the suffix -edb-postgres-for-kubernetes (e.g., <name>-edb-postgres-for-kubernetes).

Note

With Helm you can customize the name of the deployment via the fullnameOverride field in the "values.yaml" file.

You can get more information using the describe command in kubectl:

$ kubectl get deployments -n postgresql-operator-system
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
<deployment-name>   1/1     1            1           18m
kubectl describe deploy \
  -n postgresql-operator-system \
  <deployment-name>

As with any Deployment, it sits on top of a ReplicaSet and supports rolling upgrades. The default configuration of the EDB Postgres® AI for CloudNativePG™ Cluster operator comes with a Deployment of a single replica, which is suitable for most installations. In case the node where the pod is running is not reachable anymore, the pod will be rescheduled on another node.

If you require high availability at the operator level, it is possible to specify multiple replicas in the Deployment configuration - given that the operator supports leader election. Also, you can take advantage of taints and tolerations to make sure that the operator does not run on the same nodes where the actual PostgreSQL clusters are running (this might even include the control plane for self-managed Kubernetes installations).

Operator configuration

You can change the default behavior of the operator by overriding some default options. For more information, please refer to the "Operator configuration" section.

Upgrades

CRITICAL WARNING: UPGRADING OPERATORS

OpenShift users, or any customer attempting an operator upgrade, MUST configure the new unified repository pull secret (docker.enterprisedb.com/k8s) before running the upgrade. If the old, deprecated repository path is still in use during the upgrade process, image pull failure will occur, leading to deployment failure and potential downtime. Follow the Central Migration Guide first.

Important

Please carefully read the release notes before performing an upgrade as some versions might require extra steps.

Upgrading EDB Postgres® AI for CloudNativePG™ Cluster operator is a two-step process:

  1. upgrade the controller and the related Kubernetes resources
  2. upgrade the instance manager running in every PostgreSQL pod

Unless differently stated in the release notes, the first step is normally done by applying the manifest of the newer version for plain Kubernetes installations, or using the native package manager of the used distribution (please follow the instructions in the above sections).

The second step is automatically triggered after updating the controller. By default, this initiates a rolling update of every deployed PostgreSQL cluster, upgrading one instance at a time to use the new instance manager. The rolling update concludes with a switchover, which is governed by the primaryUpdateStrategy option. The default value, unsupervised, completes the switchover automatically. If set to supervised, the user must manually promote the new primary instance using the cnp plugin for kubectl.

Rolling updates

This process is discussed in-depth on the Rolling Updates page.

Important

In case primaryUpdateStrategy is set to the default value of unsupervised, an upgrade of the operator will trigger a switchover on your PostgreSQL cluster, causing a (normally negligible) downtime. If your PostgreSQL Cluster has only one instance, the instance will be automatically restarted as supervised value is not supported for primaryUpdateStrategy. In either case, your applications will have to reconnect to PostgreSQL.

The default rolling update behavior can be replaced with in-place updates of the instance manager. This approach does not require a restart of the PostgreSQL instance, thereby avoiding a switchover within the cluster. This feature, which is disabled by default, is described in detail below.

Spread Upgrades

By default, all PostgreSQL clusters are rolled out simultaneously, which may lead to a spike in resource usage, especially when managing multiple clusters. EDB Postgres® AI for CloudNativePG™ Cluster provides two configuration options at the operator level that allow you to introduce delays between cluster roll-outs or even between instances within the same cluster, helping to distribute resource usage over time:

  • CLUSTERS_ROLLOUT_DELAY: Defines the number of seconds to wait between roll-outs of different PostgreSQL clusters (default: 0).
  • INSTANCES_ROLLOUT_DELAY: Defines the number of seconds to wait between roll-outs of individual instances within the same PostgreSQL cluster (default: 0).

In-place updates of the instance manager

By default, EDB Postgres® AI for CloudNativePG™ Cluster issues a rolling update of the cluster every time the operator is updated. The new instance manager shipped with the operator is added to each PostgreSQL pod via an init container.

However, this behavior can be changed via configuration to enable in-place updates of the instance manager, which is the PID 1 process that keeps the container alive.

Internally, each instance manager in EDB Postgres® AI for CloudNativePG™ Cluster supports the injection of a new executable that replaces the existing one after successfully completing an integrity verification phase and gracefully terminating all internal processes. Upon restarting with the new binary, the instance manager seamlessly adopts the already running postmaster.

As a result, the PostgreSQL process is unaffected by the update, refraining from the need to perform a switchover. The other side of the coin, is that the Pod is changed after the start, breaking the pure concept of immutability.

You can enable this feature by setting the ENABLE_INSTANCE_MANAGER_INPLACE_UPDATES environment variable to 'true' in the operator configuration.

The in-place upgrade process will not change the init container image inside the Pods. Therefore, the Pod definition will not reflect the current version of the operator.

Compatibility among versions

EDB Postgres® AI for CloudNativePG™ Cluster follows semantic versioning. Every release of the operator within the same API version is compatible with the previous one. The current API version is v1, corresponding to versions 1.x.y of the operator.

In addition to new features, new versions of the operator contain bug fixes and stability enhancements. Because of this, we strongly encourage users to upgrade to the latest version of the operator, as each version is released in order to maintain the most secure and stable Postgres environment.

EDB Postgres® AI for CloudNativePG™ Cluster currently releases new versions of the operator at least monthly. If you are unable to apply updates as each version becomes available, we recommend upgrading through each version in sequential order to come current periodically and not skipping versions.

The release notes page contains a detailed list of the changes introduced in every released version of EDB Postgres® AI for CloudNativePG™ Cluster, and it must be read before upgrading to a newer version of the software.

Most versions are directly upgradable and in that case, applying the newer manifest for plain Kubernetes installations or using the native package manager of the chosen distribution is enough.

When versions are not directly upgradable, the old version needs to be removed before installing the new one. This won't affect user data but only the operator itself.

Upgrading to 1.30.0, 1.29.2, or 1.28.4

Important

We strongly recommend that all EDB Postgres® AI for CloudNativePG™ Cluster users upgrade to version 1.30.0, or at least to the latest stable version of your current minor release (e.g., 1.29.2 or 1.28.4).

These releases introduce changes worth reviewing before you upgrade. Two are security changes that apply to 1.30.0, 1.29.2, and 1.28.4: operator-side password encoding and search_path hardening. The other three are new in 1.30.0 only: the DatabaseRole resource for declarative role management, safe primary election via a per-cluster Lease, and operator-to-instance authentication on the instance manager's status port. In addition, if you are upgrading from a release older than 1.29.1, 1.28.3, or 1.25.8, the metrics-exporter privilege separation from CVE-2026-44477 also applies. Each is covered in its own subsection below.

Operator-side password encoding

Starting from versions 1.30.0, 1.29.2, and 1.28.4, for security reasons, EDB Postgres® AI for CloudNativePG™ Cluster SCRAM-SHA-256 encodes role passwords operator-side (client-side from PostgreSQL's point of view) before issuing CREATE/ALTER ROLE statements. As a result, the literal that reaches the PostgreSQL parser (and that extensions such as pg_stat_statements or pgaudit may observe) is the same hash that ends up in pg_authid.rolpassword, never the cleartext secret. The encoding is applied to every basic-auth Secret the operator consumes: the postgres superuser secret, the application-user secret, and any managed-role password secret. Passwords already supplied in MD5 or SCRAM-SHA-256 shadow form are passed through unchanged.

Since PostgreSQL 14, password_encryption defaults to scram-sha-256, so we do not expect existing installations to be affected by this change.

If your cluster has explicitly overridden password_encryption to a value other than scram-sha-256 (for example, md5) and you want PostgreSQL (not the operator) to decide how the password is hashed, opt out by setting the annotation k8s.enterprisedb.io/passwordPassthrough: "enabled" on each basic-auth Secret the operator consumes. The operator will then forward the password value verbatim, and PostgreSQL will encode it according to its own password_encryption GUC.

Warning

The k8s.enterprisedb.io/passwordPassthrough annotation must be set on the basic-auth Secret itself, not on the Cluster resource. Placing it on the Cluster has no effect, and the operator will continue to apply SCRAM-SHA-256 encoding to the password before sending it to PostgreSQL.

Warning

With k8s.enterprisedb.io/passwordPassthrough: "enabled" the operator forwards the Secret's password value verbatim. If that value is cleartext, as is common on password_encryption = md5 clusters, extensions such as pg_stat_statements or pgaudit will observe it.

See "Opting out of operator-side encoding" for details.

search_path hardening

Also starting from versions 1.30.0, 1.29.2, and 1.28.4, for security reasons, EDB Postgres® AI for CloudNativePG™ Cluster pins the search_path to a fixed pg_catalog, public, pg_temp on every connection it opens to PostgreSQL, so that a tenant-controlled ALTER DATABASE/ALTER ROLE setting can no longer influence how operator-issued queries resolve unqualified object names. The SECURITY DEFINER lookup function used by the PgBouncer integration is recreated automatically with its own pinned search_path during the first reconciliation after the upgrade. See Schema resolution and search_path hardening for the rationale.

This change also affects custom monitoring queries, which now run inside a transaction whose search_path is pinned to pg_catalog, public, pg_temp. If any of your custom metrics reference objects that live in other user-defined schemas through an unqualified name, schema-qualify them (for example myschema.mytable) so they keep resolving after the upgrade. User-authored bootstrap (postInit*) and logical-import post-import SQL are unaffected: they continue to run with the standard "$user", public resolution.

Declarative role management with the DatabaseRole resource

Starting from version 1.30.0, you can also manage a PostgreSQL role as a standalone DatabaseRole resource instead of declaring it inline in the Cluster's .spec.managed.roles stanza. This is an opt-in enhancement and requires no action on upgrade: existing inline roles keep working unchanged, and the inline managed.roles method remains fully supported.

To move an existing inline role under a DatabaseRole without disruption, create the DatabaseRole first and only then remove the matching entry from .spec.managed.roles. While both exist the Cluster spec always takes precedence, so management is handed over only once the inline entry is gone. See Migrating from inline managed roles for the full procedure.

A DatabaseRole does not support ensure: absent: where the inline managed.roles stanza drops a role by setting ensure: absent, a DatabaseRole instead relies on the databaseRoleReclaimPolicy field. Delete the resource with databaseRoleReclaimPolicy: delete to drop the role from PostgreSQL, or keep the default retain to leave the role in place.

Safe primary election

Starting from version 1.30.0, EDB Postgres® AI for CloudNativePG™ Cluster coordinates primary promotion through a per-cluster Kubernetes Lease, ensuring that at most one instance promotes itself at any given time. The behavior is enabled automatically and requires no configuration; the lease timings can optionally be tuned via .spec.primaryLease (see "Safe primary election").

Warning

This feature requires the operator to manage Lease objects in the coordination.k8s.io API group. The bundled operator manifest and the Helm chart grant the required permissions automatically. If you manage the operator's RBAC yourself, you must add the create, get, list, update and watch verbs on leases in the coordination.k8s.io API group before upgrading, otherwise primaries will be unable to promote.

Operator-to-instance authentication

Starting from version 1.30.0, the operator authenticates its calls to the sensitive endpoints of the instance manager's status port (backup, pg_controldata, partial WAL archive, and instance-manager upgrade) by pinning an in-memory client certificate. This is enabled automatically and requires no configuration. Status, health, and probe endpoints remain unauthenticated. See Operator-to-instance authentication for details.

Warning

This protection has a hard requirement: the status port must be served over TLS, which has been the default since v1.24. Instances created by an operator older than v1.24 serve the status port over plain HTTP; once their instance manager is upgraded to 1.30.0 the operator can no longer authenticate to them and every call to the protected endpoints is permanently rejected with 401 Unauthorized. If you still run such instances, perform a rolling update so their Pods are recreated with a TLS-enabled status port. Instances created by v1.24 or later are unaffected.

Metrics exporter privilege separation (CVE-2026-44477)

This applies only if you are upgrading from a release older than 1.29.1, 1.28.3, or 1.25.8 (for example 1.29.0, 1.28.2, 1.25.7, or any earlier version); installations already on 1.29.1, 1.28.3, 1.25.8, or later already have this change.

The fix for CVE-2026-44477 / GHSA-423p-g724-fr39 makes the metrics exporter authenticate as a dedicated cnp_metrics_exporter role with pg_monitor privileges only, instead of the postgres superuser.

Custom monitoring queries that read user-owned tables, or use target_databases: '*' against databases where PUBLIC CONNECT has been revoked, need explicit GRANT statements to cnp_metrics_exporter. See "Custom query privileges and safety" and "Manually creating the metrics exporter role" in the monitoring documentation.