A customer recently requested the integration of PostgreSQL with LDAP. I had successfully implemented similar solutions in previous projects using ldap2pg. However, this project was slightly different: PostgreSQL was deployed on Kubernetes using CloudNativePG (CNPG). This provided an interesting opportunity to combine LDAP synchronization with a modern Kubernetes-native PostgreSQL operator.

Prerequisites

I had no access to a Kubernetes cluster to test and play around, so I used Minikube on my Fedora Linux. The installation is basically a one-liner.

Copy to Clipboard
The installation is followed by starting the cluster.
Copy to Clipboard

Openldap

First, we need a source for synchronizing roles into PostgreSQL. For this test, I chose OpenLDAP. I started by creating a namespace called ldap and switching the context to this namespace.

Copy to Clipboard

Since I had no reference implementation of OpenLDAP on Kubernetes at hand, I searched and found a Helm chart that looked simple enough to run OpenLDAP. The repository can be added quickly with the helm repo add command.

Copy to Clipboard

The next step took a little longer: I created an overrides.yaml file with a basic configuration for OpenLDAP and some custom data to synchronize with ldap2pg.

There are two groups, pgusers and pgadmins, and two users, dirk and slonik. User dirk is member of the pgadmins group and user slonik belongs to the pgusers group.

Copy to Clipboard

After several iterations – adding missing parameters and fixing syntax issues โ€” the configuration worked when installed with the helm upgrade --install command.

Copy to Clipboard

OpenLDAP is now up and running!

The next step was to validate the data that ldap2pg and PostgreSQL would later query. To do this, I connected to the OpenLDAP pod and opened a shell.

Copy to Clipboard

The container includes ldapsearch, which is a very handy tool for querying OpenLDAP. The key parameters in this case were:

  • -vvv: increases verbosity for detailed output
  • -h openldap-0 -p 389: connects to the OpenLDAP pod on port 389
  • -x: uses simple authentication
  • -D 'cn=admin,dc=ldap,dc=demo,dc=lab': specifies the bind DN (here, the OpenLDAP admin account)
  • -b 'cn=dirk,ou=users,dc=ldap,dc=demo,dc=lab': sets the base DN, in this case pointing directly to user dirk
  • -s 'base': defines the search scope
  • -w: prompts for the bind userโ€™s password

The query returned the expected result.

The container includes ldapsearch, which is a very handy tool for querying OpenLDAP. The key parameters in this case were:

  • -vvv: increases verbosity for detailed output
  • -h openldap-0 -p 389: connects to the OpenLDAP pod on port 389
  • -x: uses simple authentication
  • -D 'cn=admin,dc=ldap,dc=demo,dc=lab': specifies the bind DN (here, the OpenLDAP admin account)
  • -b 'cn=dirk,ou=users,dc=ldap,dc=demo,dc=lab': sets the base DN, in this case pointing directly to user dirk
  • -s 'base': defines the search scope
  • -w: prompts for the bind userโ€™s password

The query returned the expected result.

Copy to Clipboard

CloudNativePG

To simplify work with CNPG, I installed the CNPG Plugin for kubectl. The installation is just a one-liner.

Copy to Clipboard

Next, the CNPG operator was installed by applying the operator manifest.

Copy to Clipboard
The operator becomes available within seconds. I verified the rollout with the following command:
Copy to Clipboard

With the operator ready, the next step was to create a new namespace pg and switch the context.

Copy to Clipboard

From there, I took the basic small-cluster template and added the following definitions:

  • an ldap section containing connection details for OpenLDAP, essentially the same as used in the ldapsearch test
  • a custom pg_hba.conf entry for the user ldap2pg
  • a managed role ldap2pg used by ldap2pg
  • a Kubernetes secret ldap2pg-pw holding the password for the managed role
Copy to Clipboard

After applying the manifest, the PostgreSQL cluster cluster-demo was created and became available within a minute.

Copy to Clipboard
A quick check confirmed that all pods were running.
Copy to Clipboard
Let’s check out Postgres.
Copy to Clipboard

Connecting to PostgreSQL with psql showed the expected LDAP configuration in pg_hba.conf, but no LDAP-synced roles yet.

Copy to Clipboard
Only the default roles are available, yet.
Copy to Clipboard

ldap2pg

It was time to deploy ldap2pg. This required a ConfigMap containing the ldap2pg.yml file, plus the necessary secrets for connecting to both OpenLDAP and PostgreSQL. ldap2pg would run periodically as a Kubernetes CronJob.

The secret ldapbindpw was created for the OpenLDAP admin password.

Copy to Clipboard

The ldap2pg.yml was kept deliberately simple: it defines two static roles (pgadmins and pgusers) and synchronizes users from LDAP groups into PostgreSQL with the LOGIN attribute, assigning them to their respective groups.

Copy to Clipboard

The CronJob configuration then defined how ldap2pg would run.

Note: Running ldap2pg without the --real flag performs only a dry run, displaying planned changes without applying them. This is particularly useful while fine-tuning synchronization rules.

Copy to Clipboard
Both resources were created in the cluster:
Copy to Clipboard

Authentication Example

With all components in place, I performed a final authentication test. I forwarded my local port 55432 to the PostgreSQL clusterโ€™s read/write service on port 5432.

Copy to Clipboard

Using the LDAP user dirk, authentication with PostgreSQLโ€™s psql CLI worked flawlessly.

Copy to Clipboard

Conclusion

This small project demonstrated how easily CloudNativePG can integrate with LDAP authentication, while ldap2pg provides the flexibility to synchronize LDAP groups and users directly into PostgreSQL. The combination offers a lightweight yet powerful solution for role and privilege management in Kubernetes-based PostgreSQL environments.

Although this article covered only the essentials – without addressing security hardening or enterprise-grade requirements – it establishes a solid foundation for more advanced setups. With CNPG and ldap2pg working together, organizations can align their PostgreSQL role management seamlessly with existing LDAP directory structures.

Dirk Aumueller

Dirk Aumueller works as an Associate Partner for Proventa AG. His technological focus is on database architectures with PostgreSQL as well as data management solutions using Pentaho. In addition to his database transformation project assignments, he regularly works as a PostgreSQL trainer and supervises students during their thesis projects. His professional experience spans the telecommunications and financial services industries.