H.1. ldap2pg#
H.1. ldap2pg #
- H.1.1. About ldap2pg
- H.1.2. Features
- H.1.3. Installation
- H.1.4. Command Line Interface
- H.1.5. ldap2pg.yml file reference
- H.1.6. Inspecting Postgres cluster
- H.1.7. Managing roles
- H.1.8. Querying Directory with LDAP
- H.1.9. Managing Privileges
- H.1.10. Builtins Privileges
- H.1.11. Cookbook
- H.1.12. Hacking
- H.1.13. Support
- H.1.14. Authors
Postgres is able to check password of an existing role using the LDAP protocol out of the box. ldap2pg automates the creation, update and removal of PostgreSQL roles and users from an entreprise directory.
Managing roles is close to managing privileges as you expect roles to have proper default privileges. ldap2pg can grant and revoke privileges too.

H.1.2. Features #
Reads settings from an expressive YAML config file.
Creates, alters and drops PostgreSQL roles from LDAP searches.
Creates static roles from YAML to complete LDAP entries.
Manages role parents (alias groups).
Grants or revokes privileges statically or from LDAP entries.
Dry run, check mode.
Logs LDAP searches as
ldapsearch(1)
commands.Logs every SQL statements.
ldap2pg
is licensed under
PostgreSQL
license.
ldap2pg requires a
configuration file called ldap2pg.yaml
. Project
ships a
tested
ldap2pg.yml as a starting point.
ldap2pg
is reported to work with
OpenLDAP,
FreeIPA, Oracle
Internet Directory and Microsoft Active Directory.
H.1.3. Installation #
H.1.3.1. Requirements #
ldap2pg is released as a Go binary with no requirements.
On runtime, ldap2pg requires an unprivileged role with
CREATEDB
and CREATEROLE
options or a superuser access. ldap2pg does not require to run
on the same host as the synchronized PostgreSQL cluster.
With 2MiB of RAM and one vCPU, ldap2pg can synchronize several thousands of roles in seconds, depending on PostgreSQL instance and LDAP directory response time.
H.1.3.2. Installing binary #
Download binary for your target system and architecture from ldap2pg release page.
Move the binary to
/usr/local/bin
.Ensure it’s executable with
chmod 0755 /usr/local/bin/ldap2pg
.Test installation with
ldap2pg --version
.
H.1.3.3. Using yum/dnf #
On RHEL and compatible clone, Dalibo Labs YUM repository offer RPM package for ldap2pg.
For using Dalibo Labs packaging:
Install
ldap2pg
package with yum:yum install ldap2pg
H.1.4. Command Line Interface #
ldap2pg tries to be friendly regarding configuration and consistent with psql, OpenLDAP utils and 12 factors apps. ldap2pg reads its configuration from several sources, in the following order, first prevail:
command line arguments.
environment variables.
configuration file.
ldaprc, ldap.conf, etc.
The --help
switch shows regular online
documentation for CLI arguments. As of version 5.7, this looks
like:
$ ldap2pg --help usage: ldap2pg [OPTIONS] [dbname] --check Check mode: exits with 1 if Postgres instance is unsynchronized. --color Force color output. -c, --config string Path to YAML configuration file. Use - for stdin. -?, --help Show this help message and exit. (default true) -q, --quiet count Decrease log verbosity. -R, --real Real mode. Apply changes to Postgres instance. -P, --skip-privileges Turn off privilege synchronisation. -v, --verbose count Increase log verbosity. -V, --version Show version and exit. (default true) Optional argument dbname is alternatively the database name or a conninfo string or an URI. See man psql(1) for more information. By default, ldap2pg runs in dry mode. ldap2pg requires a configuration file to describe LDAP searches and mappings. See https://ldap2pg.readthedocs.io/en/latest/ for further details.
Arguments can be defined multiple times. On conflict, the last argument is used.
H.1.4.1. Environment variables #
ldap2pg has no CLI switch to configure Postgres connection.
However, ldap2pg supports libpq
PG* env vars.
See psql(1) for details on libpq env vars.
The same goes for LDAP, ldap2pg supports standard
LDAP*
env vars and ldaprc
files. See ldap.conf(5)
for further details
on how to configure. ldap2pg accepts one extra variable:
LDAPPASSWORD
.
ldap2pg loads .env
file in the lda2pg.yml’s
parent directory if exists.
Use true
or false
for
boolean values in environment.
e.g. LDAP2PG_SKIPPRIVILEGES=true
.
Tip
Test Postgres connexion using psql(1)
and LDAP
using ldapwhoami(1)
, ldap2pg will be okay
and it will be easier to debug the setup and the configuration later.
H.1.4.2. Logging setup #
ldap2pg have several levels of logging:
ERROR
: error details. When this happend, ldap2pg will crash.WARNING
: ldap2pg warns about choices you should be aware of.CHANGE
: only changes applied to Postgres cluster. (aka Magnus Hagander level).INFO
(default): tells what ldap2pg is doing, especially before long task.DEBUG
: everything, including raw SQL queries and LDAP searches and introspection details.
The --quiet
and --verbose
switches respectively decrease and increase verbosity.
You can select the highest level of verbosity with
LDAP2PG_VERBOSITY
envvar. For example:
$ LDAP2PG_VERBOSITY=DEBUG ldap2pg 12:23:45 INFO Starting ldap2pg version=v6.0-alpha5 runtime=go1.21.0 commit=<none> 12:23:45 WARN Running a prerelease! Use at your own risks! 12:23:45 DEBUG Searching configuration file in standard locations. 12:23:45 DEBUG Found configuration file. path=./ldap2pg.yml $
ldap2pg output varies whether it’s running with a TTY or not. If
standard error is a TTY, logging is colored and tweaked for
human reading. Otherwise, logging format is pure logfmt, for
machine processing. You can force human-readable output by using
--color
CLI switch.
H.1.5. ldap2pg.yml file reference #
ldap2pg requires a YAML configuration file usually named
ldap2pg.yml
and put in working directory.
Everything can be configured from the YAML file: Postgres inspect
queries, LDAP searches, privileges and synchronization map.
Warning
ldap2pg requires a config file where the synchronization map is described.
H.1.5.1. File Location #
ldap2pg searches for configuration file in the following order :
ldap2pg.yml
in current working directory.~/.config/ldap2pg.yml
./etc/ldap2pg.yml
./etc/ldap2pg/ldap2pg.yml
.
If LDAP2PG_CONFIG
or
--config
is set, ldap2pg skips searching the
standard file locations. You can specify -
to
read configuration from standard input. This is helpful to feed
ldap2pg with dynamic configuration.
H.1.5.2. File Structure #
ldap2pg.yml
is split in several sections :
postgres
: setup Postgres connexion and inspection queries.privileges
: the definition of privileges profiles.rules
: the list of LDAP searches and associated mapping to roles and grants.
The project provides a simple well commented ldap2pg.yml, tested on CI. If you don’t know how to begin, it is a good starting point.
Note
If you have trouble finding the right configuration for your needs, feel free to file an issue to get help.
H.1.5.2.1. About YAML #
YAML is a super-set of JSON. A JSON document is a valid YAML document. YAML is a very permissive format where indentation is meaningful.
In ldap2pg.yaml
file, you will likely use
wildcard for glob pattern and curly brace for LDAP attribute
injection. Take care of protecting these characters with
quotes.
H.1.5.3. Postgres Parameters #
The postgres
section defines custom SQL
queries for Postgres inspection.
The postgres
section contains several
*_query
parameters. These parameters can be
either a string containing an SQL query or a YAML list to return
a static list of values, skipping execution of a query on
PostgreSQL cluster.
H.1.5.3.1. databases_query
#
The SQL query to list databases names in the cluster. By default, ldap2pg searches databases it cans connect to and it can reassign objects to its owner. ldap2pg loops databases to reassign objects before dropping a role. ldap2pg manages privilege on each database.
postgres: databases_query: "SELECT datname FROM pg_catalog.pg_databases;" # OR databases_query: [mydb]
Note
Configuring a _query parameter with a YAML list skip querying the cluster for inspection and forces ldap2pg to use a static value.
H.1.5.3.2. fallback_owner
#
Name of the role accepting ownership of database of dropped role.
Before dropping a role, ldap2pg reassigns objects and purges ACL. ldap2pg starts by reassigning database owner by the targetted user. The new owner of the database is the fallback owner. Other objects are reassigned to each database owner.
H.1.5.3.3. managed_roles_query
#
The SQL query to list the name of managed roles.
ldap2pg restricts role deletion and privilege edition to
managed roles. Usualy, this query returns children of a
dedicated group like ldap_roles
. By
default, ldap2pg manages all roles it has access to.
public
is a special builtin role in
Postgres. If managed_roles_query
returns
public
role in the list, ldap2pg will
manage privileges on public
. By default,
ldap2pg manages public
privileges.
The following example tells ldap2pg to manage
public
role, ldap_roles
and any members of ldap_roles
:
postgres: managed_roles_query: | VALUES ('public'), ('ldap_roles') UNION SELECT DISTINCT role.rolname FROM pg_roles AS role JOIN pg_auth_members AS ms ON ms.member = role.oid JOIN pg_roles AS parent ON parent.rolname = 'ldap_roles' AND parent.oid = ms.roleid ORDER BY 1;
H.1.5.3.4. roles_blacklist_query
#
The SQL query returning name and glob pattern to blacklist
role from management. ldap2pg won’t touch anything on these
roles. Default value is [postgres, pg_*]
.
ldap2pg blacklist self user.
postgres: roles_blacklist_query: - postgres - "pg_*" - "rds_*"
Warning
Beware that *foo
is a YAML reference.
You must quote pattern beginning with *
.
H.1.5.3.5. schemas_query
#
The SQL query returning the name of managed schemas in a
database. ldap2pg executes this query on each databases
returned by databases_query
, only if
ldap2pg manages privileges. ldap2pg loops on objects in theses
schemas when inspecting GRANTs in the cluster.
postgres: schemas_query: | SELECT nspname FROM pg_catalog.pg_namespace
H.1.5.4. PostgreSQL Privileges Section #
The privileges
top level section is a mapping
defining privilege profiles, referenced later in Synchronisation
map’s grant rule. A privilege
profile is a list of either a reference to a privilege type in a
Postgres ACL or other profile. A privilege profile may include
another profile, recursively. See
Managing Privileges
for details.
privileges: reading: - default: global type: SELECT on: TABLES writing: - reading - default: global type: SELECT on: TABLES
A privilege profile whose name starts with _
is inactive unless included in an active profile.
H.1.5.4.1. default
#
Defines the scope of default privileges. Can be undefined or
either global
or schema
.
global
scope references default privileges
for any schemas, including future schemas.
schema
scope references default privileges
on specific schemas. Target schema is defined by
grant rule.
privileges: reading: - default: global type: SELECT on: TABLES
H.1.5.4.2. type
#
Type of privilege as described in Section 5.7 e.g. SELECT, REFERENCES, USAGE, etc.
privileges: reading: - type: USAGE on: SCHEMAS
H.1.5.4.3. on
#
Target ACL of privilege type. e.g. TABLES, SEQUENCES, SCHEMAS,
etc. Note the special cases ALL TABLES
,
ALL SEQUENCES
, etc. See
Managing Privileges
documentation for details.
privileges: reading: - type: SELECT on: ALL TABLES
H.1.5.5. Synchronisation rules #
The top level rules
section is a YAML list.
This is the only mandatory parameter in
ldap2pg.yaml
. Each item of
rules
is called a
mapping. A mapping is a YAML dict with any
of role
or grant
subsection. A mapping can optionnaly have a
description
field and a
ldapsearch
section.
rules: - description: "Define DBA roles" ldapsearch: base: ... roles: - name: "{cn}" options: LOGIN SUPERUSER
The ldapsearch
subsection is optional. You
can define roles and grants without querying a directory.
H.1.5.5.1. description
#
A free string used for logging. This parameter does not accepts mustache parameter injection.
H.1.5.5.2. ldapsearch
#
This directive defines LDAP search parameters. It is named after the ldapsearch CLI utility shipped by OpenLDAP project. It’s behaviour should be mostly the same.
Note
This documentation refers LDAP query as search while the word query is reserved for SQL query.
ldapsearch
directives allows and requires
LDAP attributes injection in role
and
grant
rules using curly braces. See
Searching directory for
details.
H.1.5.5.2.1. base
, scope
and
filter
#
These parameters have the same meaning, definition and default as searchbase, scope and filter arguments of ldapsearch CLI utility.
rules: - ldapsearch: base: ou=people,dc=acme,dc=tld scope: sub filter: > (& (member=*) (cn=group_*) )
H.1.5.5.2.2. joins
#
Customizes LDAP sub-searches. The joins
section is a dictionary with attribute name as key and LDAP
search parameters as value. LDAP search parameters are the
same as for top LDAP search.
rules: - ldapsearch: joins: member: filter: ... scope: ... role: - name: "{member.sAMAccountName}"
The search base of sub-search is the value of the
referencing attribute, e.g. each value of
member
. You can’t customize the
base
attribute of sub-search. Likewise,
ldap2pg infers attributes of sub-searches from
role
and grant
rules.
You can have only a single sub-search per top-level search.
You can’t do sub-sub-search.
See Searching directory for details.
Note
Executing a sub-search for each entry of a result set can be very heavy.
You may optimize the query by using special LDAP search filter like memberOf
.
Refer to your LDAP directory administrator and documentation for details.
H.1.5.5.3. role
#
Defines a rule to describe one or more roles wanted in the
target Postgres cluster. This includes name, options, config,
comment and membership. Plural form roles
is valid. The value can be either a single role rule or a list
of role rules.
rules: - role: name: dba options: SUPERUSER LOGIN - roles: - name: group0 options: NOLOGIN - name: group1 options: NOLOGIN
H.1.5.5.3.1. comment
#
Defines the SQL comment of a role. Default value is
Managed by ldap2pg
. Accepts LDAP
attribute injection.
In case of LDAP attributes injection, you must take care of how many combination will be generated. If the template generates a single comment, ldap2pg will copy the comment for each role generated by the role rule. If the template generates multiple comments, ldap2pg associates name and comment. If there is more or less comments generated than name generated, ldap2pg fails.
The following example defines a static comment shared by all generated roles:
rules: - roles: names: - alice - bob comment: "Static roles from YAML."
The following example generates a single comment from LDAP entry distinguised name, copied for all generated roles:
rules: - ldapsearch: ... role: name: "{cn}" comment: "Generated from LDAP entry {dn}."
The following example generate a unique comment for each roles generated:
rules: - ldapsearch: ... role: name: "{member.cn}" comment: "Generated from LDAP entry {member}."
Tip
If a role is defined multiple times, parents are merged. Other fields are kept as declared by the first definition of the role.
H.1.5.5.3.2. name
#
Name of the role wanted in the cluster. The value can be
either a single string or a list of strings. Plural form
names
is valid. You can inject LDAP
attributes in name using curly braces. When multiple names
are defined, a new role is defined for each name, each with
the same attributes such as options
and
parents
. comment
parameter has a special handling, see
above.
rules: - roles: name: "my-role-name"
When injecting LDAP attribute in name, each value of the LDAP attribute of each LDAP entry will define a new role. When multiple LDAP attributes are defined in the format, all combination of attributes are generated.
ldap2pg protects role name with double quotes in the target Postgres cluster. Capitalization is preserved, spaces are allowed (even if it’s a really bad idea).
ldap2pg applies roles_blacklist_query on this parameter.
H.1.5.5.3.3. options
#
Defines PostgreSQL role options. Maybe an SQL-like string or
a YAML dictionary. Valid options are
BYPASSRLS
,
CONNECTION LIMIT
,
LOGIN
, CREATEDB
,
CREATEROLE
, INHERIT
,
REPLICATION
and
SUPERUSER
. Available options varies
following the version of the target PostgreSQL cluster and
the privilege of ldap2pg user.
- roles: - name: my-dba options: LOGIN SUPERUSER - name: my-group options: LOGIN: no INHERIT: yes
H.1.5.5.3.4. config
#
Defines PostgreSQL configuration parameters that will be set for the role. Must be a YAML dictionary. Available configuration parameters varies following the version of the target PostgreSQL cluster. Some parameters requires superuser privileges to be set. ldap2pg will fails if it does not have privilege to set a config parameter.
- roles: - name: my-db-writer config: log_statement: mod log_min_duration_sample: 100
Setting config
to null
(the default) will disable the feature for the role. If
config
is a dict, ldap2pg will drop
parameter set in cluster but not defined in ldap2pg YAML. To
reset all parameters, set config
to an
empty dict like below.
- roles: - name: reset-my-configuration config: {}
Note that LDAP attributes are not expanded in config values.
H.1.5.5.3.5. parent
#
Name of a parent role. A list of names is accepted. The
plural form parents
is valid too. Parent
role is granted with
GRANT ROLE parent TO role;
.
parent
parameter accepts LDAP attributes
injection using curly braces. ldap2pg applies
roles_blacklist_query
on this parameter. Reference parent can be local roles not
managed by ldap2pg.
rules: - role: name: myrole parent: myparent
H.1.5.5.3.6. before_create
#
SQL snippet to execute before role creation.
before_create
accepts LDAP attributes
injection using curly braces. You are responsible to escape
attribute with either .identifier()
or
.string()
.
rules: - ldapsearch: ... role: name: "{cn}" before_create: "INSERT INTO log VALUES ({cn.string()})"
H.1.5.5.3.7. after_create
#
SQL snippet to execute after role creation.
after_create
accepts LDAP attributes
injection using curly braces. You are responsible to escape
attribute with either .identifier()
or
.string()
.
rules: - ldapsearch: ... role: name: "{sAMAccountName}" after_create: "CREATE SCHEMA {sAMAccountName.identifier()} AUTHORIZATION {sAMAccountName.identifier()}"
H.1.5.5.4. grant
#
Defines a grant of a privilege to a role with corresponding
parameters. Can be a mapping or a list of mapping. Plural form
grants
is valid too.
rules: - grant: privilege: reader databases: __all__ schema: public role: myrole
H.1.5.5.4.1. database
#
Scope the grant to one or more databases. May be a list of
names. Plural form databases
is valid.
Special value __all__
expands to all
managed databases as returned by
databases_query.
Defaults to __all__
. Grants found in
other databases will be revoked. Accepts LDAP attributes
injection using curly braces.
This parameter is ignored for instance-wide privileges (e.g. on LANGUAGE).
H.1.5.5.4.2. privilege
#
Name of a privilege, within the privileges defined in
privileges
YAML section. May be a list of names. Plural form
privileges
is valid. Required, there is
not default value. Accepts LDAP attribute injection using
curly braces.
H.1.5.5.4.3. role
#
Name of the target role of the grant (granted
role or grantee). Must be
listed by
managed_roles_query.
May be a list of names. Plural form roles
is valid. Accepts LDAP attribute injection using curly
braces. ldap2pg applies
roles_blacklist_query
on this parameter.
H.1.5.5.4.4. schema
#
Name of a schema, whithin the schemas returned by
schemas_query.
Special value __all__
means all
managed schemas in the databases. May be a list
of names. Plural form schemas
is valid.
Accepts LDAP attribute injection using curly braces.
This parameter is ignored for privileges on
DATABASE
and other instance-wide or
database-wide privileges.
H.1.5.5.4.5. owner
#
Name of role to configure default privileges for. Special
value __auto__
fallbacks to managed roles
having CREATE
privilege on the target
schema. May be a list of names. Plural form
owners
is valid. Accepts LDAP attribute
injection using curly braces.
H.1.6. Inspecting Postgres cluster #
ldap2pg follows the explicit create / implicit drop and explicit grant / implicit revoke pattern. Thus properly inspecting cluster for what you want to drop/revoke is very crucial to succeed in synchronization.
ldap2pg inspects databases, schemas, roles, owners and grants with
SQL queries. You can customize all these queries in the
postgres
YAML section with parameters ending
with _query
. See
ldap2pg.yaml reference for details.
H.1.6.1. What databases to synchronize ? #
databases_query
returns the flat list of
databases to manage. The databases_query
must
return the default database as defined in
PGDATABASE
. When dropping roles, ldap2pg
loops the databases list to reassign objects and clean GRANTs of
to be dropped role. This databases list also narrows the scope
of GRANTs inspection. ldap2pg will revoke GRANTs only on these
databases. See
ldap2pg.yaml reference for details.
postgres: databases_query: | SELECT datname FROM pg_catalog.pg_database WHERE datallowconn IS TRUE;
H.1.6.2. Synchronize a subset of roles #
By default, ldap2pg manages all roles from Postgres it has
powers on, minus the default blacklist. If you want ldap2pg to
synchronsize only a subset of roles, you need to customize
inspection query in
postgres:managed_roles_query
. The following
query excludes superusers from synchronization.
postgres: managed_roles_query: | SELECT 'public' UNION SELECT rolname FROM pg_catalog.pg_roles WHERE rolsuper IS FALSE ORDER BY 1;
ldap2pg will only drop, revoke, grant on roles returned by this query.
A common case for this query is to return only members of a
group like ldap_roles
. This way, ldap2pg is
scoped to a subset of roles in the cluster.
The public
role does not exists in the system
catalog. Thus if you want ldap2pg to manage
public
privileges, you must include
explicitly public
in the set of managed
roles. This is the default. Of course, even if
public
is managed, ldap2pg won’t drop or
alter it if it’s not in the directory.
A safety net to completely ignore some roles is roles_blacklist_query.
postgres: roles_blacklist_query: [postgres, pg_*] # This is the default.
Note
A pattern starting with a *
must be quoted.
Else you'll end up with a YAML error like found undefined alias
.
H.1.6.3. Inspecting Schemas #
For schema-wide privileges, ldap2pg needs to known managed
schemas for each database. This is the purpose of
schemas_query
.
H.1.6.4. Configuring owners default privileges #
To configure default privileges, use the
default
keyword when referencing a privilege:
privileges: reading: - default: global type: SELECT on: TABLES
Then grant it using grant
rule:
rules: - grant: - privilege: reading role: readers schema: public owner: ownerrole
You can use __auto__
as owner. For each
schema, ldap2pg will configure every managed role having
CREATE
privilege on schema.
rules: - grant: - privilege: reading role: readers schema: public owner __auto__
ldap2pg configures default privileges last, after all effective
privileges. Thus CREATE
on schema is granted
before ldap2pg inspects creators on schemas.
H.1.6.5. Static Queries #
You can replace all queries with a static list in YAML. This list will be used as if returned by Postgres. That’s very handy to freeze a value like databases or schemas.
postgres: databases_query: [postgres] schemas_query: [public]
H.1.7. Managing roles #
ldap2pg synchronizes Postgres roles in three steps:
Loop
rules
and generate wanted roles list fromrole
rules.Inspect Postgres for existing roles, their options and their membership.
Compare the two roles sets and apply to the Postgres cluster using
CREATE
,DROP
andALTER
.
Each role entry in
rules
is a rule to generate zero or more roles
with the corresponding parameters. A role
rule
is like a template. role
rules allows to
deduplicate membership and options by setting a list of names.
You can mix static rules and dynamic rules in the same file.
H.1.7.1. Running unprivileged #
ldap2pg is designed to run unprivileged. Synchronization user
needs CREATEROLE
option to manage other
unprivileged roles. CREATEDB
options allows
synchronization user to managed database owners.
ldap2pg user must have createrole_self_grant
set to inherit,set
to properly handle groups.
CREATE ROLE ldap2pg LOGIN CREATEDB CREATEROLE; ALTER ROLE ldap2pg SET createrole_self_grant TO 'inherit,set;
Running unprivileged before Postgres 16 is actually flawed. You’d better just run ldap2pg with superuser privileges, you wont feel falsly secured.
H.1.7.2. Ignoring roles #
ldap2pg totally ignores roles matching one of the glob pattern defined in roles_blacklist_query:
postgres: # This is the default value. roles_blacklist_query: [postgres, pg_*]
The role blacklist is also applied to grants. ldap2pg will never
apply GRANT
or REVOKE
on a
role matching one of the blacklist patterns.
ldap2pg blacklists its running user.
H.1.7.3. Membership #
ldap2pg manages parents of roles. ldap2pg applies roles_blacklist_query to parents. However, ldap2pg grants unmanaged parents. This way, you can create a group manually and manages its members using ldap2pg.
H.1.8. Querying Directory with LDAP #
ldap2pg reads LDAP searches in rules
steps in
the ldapsearch
entry.
A LDAP search is not mandatory. ldap2pg can create roles defined statically from YAML. Each LDAP search is executed once and only once. There is neither loop nor deduplication of LDAP searches.
Tip
ldap2pg logs LDAP searches as ldapsearch
commands.
Enable verbose messages to see them.
You can debug a failing search by copy-pasting the command in your shell and update parameters.
Once you are okay, translate back the right parameters in the YAML.
H.1.8.1. Configuring Directory Access #
ldap2pg reads directory configuration from ldaprc file and LDAP* environment variables. Known LDAP options are:
BASE
BINDDN
PASSWORD
REFERRALS
SASL_AUTHCID
SASL_AUTHZID
SASL_MECH
TIMEOUT
TLS_REQCERT
NETWORK_TIMEOUT
URI
See ldap.conf(5) for the meaning and format of each options.
H.1.8.2. Injecting LDAP attributes #
Several parameters accepts LDAP attribute injection using curly
braces. To do this, wraps attribute name with curly braces like
{cn}
or {sAMAccountName}
.
ldap2pg expands to each value of the attribute for each entries
of the search.
If the parameter has multiple LDAP attributes, ldap2pg expands to all combination of attributes for each entries.
Given the following LDAP entries:
dn: uid=dimitri,cn=Users,dc=bridoulou,dc=fr objectClass: inetOrgPerson uid: dimitri sn: Dimitri cn: dimitri mail: dimitri@bridoulou.fr company: external dn: cn=domitille,cn=Users,dc=bridoulou,dc=fr objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: top cn: domitille sn: Domitille company: acme company: external
The format {company}_{cn}
with the above LDAP
entries generates the following strings:
acme_domitille
external_domitille
external_dimitri
The pseudo attribute dn
is always available
and references the Distinguished Name of the original LDAP
entry.
H.1.8.2.1. Accessing RDN and sub-search #
If an attribute type is Distinguished Name (DN), you can refer
to a Relative Distinguished Name (RDN) with a dot, like this:
<attribute>.<rdn>
. If an RDN
has multiple values, only the first value is returned. There
is no way to access other value.
For example, if a LDAP entry has member
attribute with value
cn=toto,cn=Users,dc=bridoulou,dc=fr
, the
{member.cn}
format will generate
toto
. The {member.dc}
format will generate ldap
. There is no way
to access acme
and fr
.
Known RDN are cn
, l
,
st
, o
,
ou
, c
,
street
, dc
, and
uid
. Other attributes triggers a
sub-search. The format
{member.sAMAccountName}
will issue a
sub-search for all member
value as LDAP
search base narrowed to sAMAccountName
attribute.
H.1.8.2.2. LDAP Attribute Case #
When injecting an LDAP attribute with curly braces, you can
control the case of the value using
.lower()
or .upper()
methods.
- ldapsearch: ... role: "{cn.lower()}"
H.1.9. Managing Privileges #
Managing privileges is tricky. ldap2pg tries to make this simpler and safer.
H.1.9.1. Basics #
The base design of ldap2pg is ambitious. Instead of revoke-everything-regrant design, ldap2pg uses inspect-modify design. The process is the same as for roles synchronization, including the three following steps:
Loop
rules
and generate wanted grants set.Inspect Postgres cluster for granted privileges.
Compare the two sets of grants and update the Postgres cluster using
GRANT
,REVOKE
.
ldap2pg synchronizes privileges one at a time, database by database. ldap2pg synchronizes default privileges last.
By default, ldap2pg does not manage any privileges. To enable privilege management, you must define at least one active privilege profile in privileges section. The simplest way is to reuse [builtin privilege profiless] shipped with ldap2pg in an active group of privileges.
H.1.9.2. Defining a Privilege Profile #
A privilege profile is a list of references to either a
privilege type on an ACL or another profile. ldap2pg ships
several predefined ACL like DATABASE
,
LANGUAGE
, etc. A privilege type is
USAGE
, CONNECT
and so on
as describe in as documented in documentation Section 5.7.
See privileges YAML
section documentation for details on privilege profile format.
ldap2pg loads referenced ACL by inspecting PostgreSQL cluster
with carefully crafted queries. An unreferenced ACL is ignored.
Inspected grants are supposed to revokation unless explicitly
wanted by a grant
rule.
Warning
If it’s not granted, revoke it!
Once a privilege is enabled,
ldap2pg revokes all grants found in Postgres instance and
not required by a grant
rule in rules
.
H.1.9.3. Extended Intance inspection #
When managing privileges, ldap2pg has deeper inspection of
Postgres instance. ldap2pg inspects schemas after roles
synchronization and before synchronizing privileges. ldap2pg
inspects objects owner after privileges synchronization and
before synchronizing default privileges. An object owner is a
role having CREATE
privilege on a schema.
H.1.9.4. Granting Privilege Profile #
Inspecting privileges may consume a lot of resources on PostgreSQL instance. Revoking privileges is known to be slow in PostgreSQL. The best practice is to grant privileges to a group role and let user inherit privileges. With ldap2pg, you can define static groups in YAML and inherit them when creating roles from directory.
Use grant rule to grant a privilege profile to one or more roles. When granting privileges, you must define the grantee. You may scope the grant to one or more databases, one or more schemas. If the privilege profile includes default privileges, you may define the owners on which to configure default privileges.
By default, a grant applies to all managed databases as returned by databases_query, to all schema of each database as returned by schemas_query.
H.1.9.5. Example #
The following example defines three privileges profile. The
rules
defines three groups and grant the
corresponding privilege profile:
privileges: reading: - __connect__ - __usage_on_schemas__ - __select_on_tables__ writing: - reading # include reading privileges - __insert_on_tables__ - __update_on_tables__ owning: - writing - __create_on_schemas__ - __truncate_on_tables__ rules: - role: - names: - readers - writers - owners options: NOLOGIN - grant: - privilege: reading role: readers - privilege: writing role: writers - privilege: owning role: owners
Another way of including reading profile in writing is to writers group to inherit readers group.
H.1.9.6. Managing public Privileges #
PostgreSQL has a pseudo-role called public
.
It’s a wildcard roles meaning every users.
All roles in PostgreSQL implicitly inherits from this
public
role. Granting a privilege to
public
role grants to every role now and in
the future.
PostgreSQL also as the public
schema. The
public
schema is a real schema available in
all databases.
PostgreSQL has some built-in privileges for
public
role. Especially for the
public
schema. For example,
public
has CONNECT
on all
databases by default. This means that you only rely on
pg_hba.conf
to configure access to databases,
which requires administrative access to the cluster and a
pg_reload_conf()
call.
By default, ldap2pg includes public
role in
managed roles. Predefined ACL knows how to inspect built-in
privileges granted to public
. If you want to
preserve public
role, rewrite
managed_roles_query
to not include public
.
H.1.9.7. Managing Default Privileges #
If you grant SELECT
privileges on all tables
in a schema to a role, this wont apply to new tables created
afterward. Instead of reexecuting ldap2pg after the creation of
every objects, PostgreSQL provides a way to define default
privileges for future objects.
PostgreSQL attaches default privileges to the creator role. When
the role creates an object, PostgreSQL apply the corresponding
default privileges to the new object.
e.g. ALTER DEFAULT PRIVILEGES FOR ROLE bob GRANT SELECT ON TABLES TO alice;
ensures every new tables bob creates will be selectable by
alice:
If ldap2pg creates and drops creator roles, you want ldap2pg to properly configure default privileges on these roles. If you wonder whether to manage privileges with ldap2pg, you should at least manage default privileges along creator.
ldap2pg inspects the creators from PostgreSQL, per schemas, not LDAP directory. A creator is a role with LOGIN option and CREATE privilege on a schema. You can manually set the target owner of a grant to any managed roles.
ldap2pg does not configure privileges on
__all__
schemas. You are supposed to use
global
scope instead. If you want to
grant/revoke default privilege per schema, you must reference
schema
default.
The following example configures default privileges for alice to allow bob to SELECT on future tables created by alice.
privileges: reading: - default: global type: SELECT on: TABLES owning: - type: CREATE on: SCHEMAS rules: - roles: names: - alice - bob options: LOGIN - grant: privilege: owning role: alice - grant: privilege: reading role: bob
PostgreSQL has hard-wire global default privileges. If a role does not have global default privileges configured, PostgreSQL assume some defaults. By default, PostgreSQL just grant privileges on owner. You can see them once you modify the default privileges. PostgreSQL will copy the hard-wired values along your granted privileges.
If you don’t explicitly re-grant these privileges in ldap2pg.yml, ldap2pg will revoke these hard-wired privileges. Actually, an owner of table don’t need to be granted SELECT on its own tables. Thus, the hard-wired defaults are useless. You can let ldap2pg purge these useless defaults.
H.1.10. Builtins Privileges #
ldap2pg provides some builtin ACL and predefined privilege profiles for recurrent usage. There is no warranty on these privileges. You have to check privileges configuration on your databases just like you should do with your own code.
H.1.10.1. Using Predefined Privilege Profiles #
A privilege profile is a list of reference to a privilege type
in an ACL. In ldap2pg, an ACL is a set of query to inspect,
grant and revoke privilege on a class of objects. The inspect
query expands aclitem
PostgreSQL type to list
all grants from system catalog. Privilege profile can include
another profile.
Builtin privilege profile starts and ends with
__
. ldap2pg
disables privilege profile
starting with _
. Thus you have
to include builtin privileges profile in another profile to
enable them. If two profiles reference the same privilege,
ldap2pg will inspect it once.
privileges: ro: - __connect__ - __usage_on_schemas__ - __select_on_tables__ rw: - ro - __insert__ - __update_on_tables__ ddl: - rw - __all_on_schemas__ - __all_on_tables__ rules: - grant: privilege: ddl database: mydb role: admins
Builtin profile’s name follows the following loose convention:
..._on_all_tables__
referencesALL TABLES IN SCHEMA
ACL. Likewise for sequences and functions.__default_...__
references both global and schema-wide default privileges.__..._on_tables__
groups__..._on_all_tables__
and__default_..._on_tables__
.Group starting with
__all_on_...__
is equivalent toALL PRIVILEGES
in SQL. However, each privilege will be granted individually.A privilege specific to one object type does not have
_on_<type>
suffix. E.g.__delete_on_tables__
is aliased to__delete__
.
This page does not document the SQL standard and the meaning of each SQL privileges. You will find the documentation of SQL privileges in GRANT and ALTER DEFAULT PRIVILEGES.
H.1.10.2. ACL Reference #
Here is the list of builtin ACL.
For effective privileges:
DATABASE
: privilege on database likeCONNECT
,CREATE
, etc.SCHEMA
: manageUSAGE
andCREATE
on schema.LANGUAGE
: manageUSAGE
on procedural languages.ALL FUNCTIONS IN SCHEMA
: manageEXECUTE
on all functions per schema.ALL SEQUENCES IN SCHEMA
: like above but for sequences.ALL TABLES IN SCHEMA
: like above but for tables and views.
ALL ... IN SCHEMA
ACL inspects whether a
privilege is granted to only a subset of objects. This is a
partial grant. A partial grant is either
revoked if unwanted or regranted if expected.
ACL for default privileges:
SEQUENCES
FUNCTIONS
TABLES
Theses ACL must be referenced with global
set
to either schema
or
global
.
You can reference these ACL using privileges:on parameter in YAML. Like this:
privileges: myprofile: - type: SELECT on: ALL TABLES IN SCHEMA
You cannot (yet) configure custom ACL.
H.1.10.3. Profiles Reference #
H.1.10.3.1. Profile __all_on_functions__
#
H.1.10.3.2. Profile __all_on_schemas__
#
H.1.10.3.3. Profile __all_on_sequences__
#
H.1.10.3.4. Profile __all_on_tables__
#
H.1.10.3.5. Profile __delete_on_tables__
#
H.1.10.3.6. Profile
__execute_on_functions__
#
H.1.10.3.7. Profile __insert_on_tables__
#
H.1.10.3.8. Profile
__references_on_tables__
#
H.1.10.3.9. Profile
__select_on_sequences__
#
H.1.10.3.10. Profile __select_on_tables__
#
H.1.10.3.11. Profile __trigger_on_tables__
#
H.1.10.3.12. Profile __truncate_on_tables__
#
H.1.10.3.13. Profile
__update_on_sequences__
#
H.1.10.3.14. Profile __update_on_tables__
#
H.1.10.3.15. Profile __usage_on_sequences__
#
H.1.10.4. Privileges Reference #
Here is the list of predefined privileges:
Name | Manages |
---|---|
__connect__
|
CONNECT ON DATABASE
|
__create_on_schemas__
|
CREATE ON SCHEMA
|
__delete_on_all_tables__
|
DELETE ON ALL TABLES IN SCHEMA
|
__execute_on_all_functions__
|
EXECUTE ON ALL FUNCTIONS IN SCHEMA
|
__insert_on_all_tables__
|
INSERT ON ALL TABLES IN SCHEMA
|
__references_on_all_tables__
|
REFERENCES ON ALL TABLES IN SCHEMA
|
__select_on_all_sequences__
|
SELECT ON ALL SEQUENCES IN SCHEMA
|
__select_on_all_tables__
|
SELECT ON ALL TABLES IN SCHEMA
|
__temporary__
|
TEMPORARY ON DATABASE
|
__trigger_on_all_tables__
|
TRIGGER ON ALL TABLES IN SCHEMA
|
__truncate_on_all_tables__
|
TRUNCATE ON ALL TABLES IN SCHEMA
|
__update_on_all_sequences__
|
UPDATE ON ALL SEQUENCES IN SCHEMA
|
__update_on_all_tables__
|
UPDATE ON ALL TABLES IN SCHEMA
|
__usage_on_all_sequences__
|
USAGE ON ALL SEQUENCES IN SCHEMA
|
__usage_on_schemas__
|
USAGE ON SCHEMA
|
H.1.10.5. Default Privileges Reference #
Here is the list of predefined default privileges. Default privilege profile references both global and schema defaults.
Name | Manages |
---|---|
__default_delete_on_tables__
|
DELETE ON TABLES
|
__default_execute_on_functions__
|
EXECUTE ON FUNCTIONS
|
__default_insert_on_tables__
|
INSERT ON TABLES
|
__default_references_on_tables__
|
REFERENCES ON TABLES
|
__default_select_on_sequences__
|
SELECT ON SEQUENCES
|
__default_select_on_tables__
|
SELECT ON TABLES
|
__default_trigger_on_tables__
|
TRIGGER ON TABLES
|
__default_truncate_on_tables__
|
TRUNCATE ON TABLES
|
__default_update_on_sequences__
|
UPDATE ON SEQUENCES
|
__default_update_on_tables__
|
UPDATE ON TABLES
|
__default_usage_on_sequences__
|
USAGE ON SEQUENCES
|
H.1.11. Cookbook #
Here in this cookbook, you’ll find some recipes for various use case of ldap2pg.
If you struggle to find a way to setup ldap2pg for your needs, please file an issue so that we can update Cookbook with new recipes! Your contribution is welcome!
H.1.11.1. Configure pg_hba.conf
with LDAP #
ldap2pg does NOT configure
PostgreSQL for you. You should carefully read Section 20.10
for this point. Having PostgreSQL
properly configured before
writing ldap2pg.yaml
is a good start. Here is
the steps to setup PostgreSQL with LDAP in the best order:
Write the LDAP search and test it with
ldapsearch(1)
. This way, you can also check how you connect to your LDAP directory.In PostgreSQL cluster, manually create a single role having its password in LDAP directory.
Edit
pg_hba.conf
following Section 20.10 until you can effectively login with the single role and the password from LDAP.
Once you have LDAP authentication configured in PostgreSQL cluster, you can move to automate role creation from the LDAP directory using ldap2pg:
Write a simple
ldap2pg.yaml
with only one LDAP search just to setup ldap2pg connection parameters for PostgreSQL and LDAP connection. ldap2pg always run in dry mode by default, so you can safely loop ldap2pg execution until you get it right.Then, complete
ldap2pg.yaml
to fit your needs following Section H.1.4. Run ldap2pg for real and check that ldap2pg maintain your single test role, and that you can still connect to the cluster with it.Finally, you must decide when and how you want to trigger synchronization: a regular cron tab ? An ansible task ? Manually ? Other ? Ensure ldap2pg execution is frequent, on purpose and notified.
H.1.11.2. Search LDAP Directory #
The first step is to search your LDAP server with ldapsearch(1), the CLI tool from OpenLDAP. Like this:
$ ldapsearch -H ldaps://ldap.ldap2pg.docker -U testsasl -W Enter LDAP Password: SASL/DIGEST-MD5 authentication started SASL username: testsasl SASL SSF: 128 SASL data security layer installed. # extended LDIF # # LDAPv3 ... # search result search: 4 result: 0 Success # numResponses: 16 # numEntries: 15 $
Now save the settings in ldaprc
:
LDAPURI ldaps://ldap.ldap2pg.docker LDAPSASL_AUTHCID testsasl
And in environment: LDAPPASSWORD=secret
Next, update your ldapsearch(1) to properly match role entries in LDAP server:
$ ldapsearch -H ldaps://ldap.ldap2pg.docker -U testsasl -W -b cn=dba,ou=groups,dc=ldap,dc=ldap2pg,dc=docker '' member ... # dba, groups, ldap.ldap2pg.docker dn: cn=dba,ou=groups,dc=ldap,dc=ldap2pg,dc=docker member: cn=Alan,ou=people,dc=ldap,dc=ldap2pg,dc=docker member: cn=albert,ou=people,dc=ldap,dc=ldap2pg,dc=docker member: cn=ALICE,ou=people,dc=ldap,dc=ldap2pg,dc=docker # search result search: 4 result: 0 Success ... $
Now translate the query in ldap2pg.yaml
and
associate a role mapping to produce roles from each values of
each entries returned by the LDAP search:
- ldapsearch: base: cn=dba,ou=groups,dc=ldap,dc=ldap2pg,dc=docker role: name: '{member.cn}' options: LOGIN SUPERUSER
Test it:
$ ldap2pg ... Querying LDAP cn=dba,ou=groups,dc=ldap,dc=ldap2pg,dc=docker... Would create alan. Would create albert. Would update options of alice. ... Comparison complete. $
Read further on how to control role creation from LDAP entry in
Section H.1.5. Once you’re
satisfied with the comparison output, go real with
--real
.
H.1.11.3. Using LDAP High-Availability #
ldap2pg supports LDAP High Availability out of the box just like any openldap client. Use a space separated list of URI to tells all servers.
$ LDAPURI="ldaps://ldap1 ldaps://ldap2" ldap2pg
See [ldap.conf(5)] for further details.
H.1.11.4. Running as non-superuser #
Since Postgres provide a CREATEROLE
role
option, you can manage roles without superuser privileges.
Security-wise, it’s a good idea to manage roles without super
privileges.
Warning
Up to Postgres 15, having CREATEROLE is roughly equivalent to being superuser. This because CREATEROLE user can grant themselve almost every privileges. Thus ldap2pg supports running unprivileged against Postgres 16 and later only.
ldap2pg supports this case. However, you must be careful about
the limitations. Let’s call the non-super role creating other
roles creator
.
You can’t manage some roles options like
SUPERUSER
,BYPASSRLS
andREPLICATION
. Thus you wont be able to detect spurious superusers.Ensure
creator
can revoke all grants of managed users.
H.1.11.5. Removing All Roles #
If ever you want to clean all roles in a PostgreSQL cluster,
ldap2pg could be helpful. You must explicitly define an empty
rules
.
$ echo '{version: 6, rules: []}' | ldap2pg --config - ... Empty synchronization map. All roles will be dropped! ...
In this example, default blacklist applies. ldap2pg never drop its connection role.
H.1.11.6. ldap2pg as Docker container #
Already familiar with Docker and willing to save the setup time? You’re at the right place.
To run the container simply use the command:
$ docker run --rm dalibo/ldap2pg --help
The Docker image of ldap2pg use the same configuration options as explained in the Section H.1.4 and Section H.1.5 sections. You can mount the ldap2pg.yml configuration file.
$ docker run --rm -v ${PWD}/ldap2pg.yml:/workspace/ldap2pg.yml dalibo/ldap2pg
You can also export some environmnent variables with the -e option:
$ docker run --rm -v ${PWD}/ldap2pg.yml:/workspace/ldap2pg.yml -e PGDSN=postgres://postgres@localhost:5432/ -e LDAPURI=ldaps://localhost -e LDAPBINDDN=cn=you,dc=entreprise,dc=fr -e LDAPPASSWORD=pasglop dalibo/ldap2pg
Make sure your container can resolve the hostname your pointing to. If you use some internal name resolution be sure to add the –dns= option to your command pointing to your internal DNS server. More info
H.1.12. Hacking #
You are welcome to contribute to ldap2pg with patch to code, documentation or configuration sample ! Here is an extended documentation on how to setup a development environment. Feel free to adapt to your cumfort. Automatic tests on CircleCI will take care of validating regressions.
H.1.12.1. Docker Development Environment #
Project repository ships a docker-compose.yml
file to launch an Samba Directory and a PostgreSQL instances.
$ docker compose pull ... Status: Downloaded newer image for postgres:16-alpine $ docker compose up -d Creating network "ldap2pg_default" with the default driver Creating ldap2pg_postgres_1 ... Creating ldap2pg_samba_1 ... Creating ldap2pg_postgres_1 Creating ldap2pg_samba_1 ... done
It’s up to you to define how to access Postgres and LDAP
containers from your host: either use DNS resolution or a
docker-compose.override.yml
to expose port on
your host. Provided docker-compose.yml
comes
with postgres.ldap2pg.docker
and
samba.ldap2pg.docker
dnsdock
aliases.
Setup your environment with regular PG*
envvars so that psql
can just connect to your
PostgreSQL instance. Check with a simple psql
invocation.
$ export PGHOST=postgres.ldap2pg.docker PGUSER=postgres PGPASSWORD=postgres $ psql -c 'SELECT version()';
Do the same to setup libldap2
with
LDAP*
envvars. A ldaprc
is
provided setting up BINDDN
and
BASE
. ldap2pg supports
LDAPPASSWORD
to set password from env. Check
it with ldapsearch
:
$ export LDAPURI=ldaps://samba.ldap2pg.docker LDAPPASSWORD=1Ntegral $ ldapsearch -vxw $LDAPPASSWORD -s base cn ldap_initialize( <DEFAULT> ) filter: (objectclass=*) requesting: cn # extended LDIF # # LDAPv3 # base <cn=users,dc=bridoulou,dc=fr> (default) with scope baseObject # filter: (objectclass=*) # requesting: cn # # Users, bridoulou.fr dn: CN=Users,DC=bridoulou,DC=fr cn: Users # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 $
H.1.12.1.1. Environement without DNS resolution #
To access Samba Directory and PostgreSQL without dnsdock, exposes containers ports to your host with the following override:
# contents docker-compose.override.yml version: '3' services: samba: ports: # HOST:CONTAINER - 389:389 - 636:636 postgres: ports: - 5432:5432
Use PGHOST=localhost
and
LDAPURI=ldaps://localhost
.
H.1.12.1.2. Running ldap2pg with Changes #
Now you can run ldap2pg from source and test your changes!
$ go run ./cmd/ldap2pg 09:54:27 INFO Starting ldap2pg version=v6.0-alpha5 runtime=go1.20.3 commit=<none> 09:54:27 WARN Running a prerelease! Use at your own risks! 09:54:27 INFO Using YAML configuration file. path=./ldap2pg.yml ... 09:54:27 INFO Nothing to do. elapsed=78.470278ms mempeak=1.2MiB postgres=0s queries=0 ldap=486.921µs searches=1 $
H.1.12.2. Development Fixtures #
ldap2pg project comes with three cases for testing:
nominal: a regular case with:
running unprivileged
a single database named
nominal
.3 groupes : readers, writers and owners
roles and privileges synchronized.
extra: few corner cases together
running as superuser
synchronize role configuration
do LDAP sub-searches.
big: a huge synchronization project
multiple databases with a LOT of schemas, tables, views, etc.
all privileges synchronized
3 groups per schemas.
1K users in directory.
test/fixtures/
holds fixtures for Samba and
PostgreSQL. Default development environment loads
nominal and extra
fixtures. By default, big case is not loaded. Func tests use
nominal and extra
fixtures. See below for big case.
test/fixtures/postgres/reset.sh
resets
PostgreSQL state. You can also use
make reset-postgres
to recreate PostgreSQL
container from scratch.
H.1.12.3. Unit tests #
Unit tests strictly have no I/O. Run unit tests as usual go tests.
$ go test ./... ? github.com/dalibo/ldap2pg/cmd/ldap2pg [no test files] ? github.com/dalibo/ldap2pg/cmd/render-doc [no test files] ok github.com/dalibo/ldap2pg/cmd/mon-dojo 0.002s ok github.com/dalibo/ldap2pg/internal 0.003s ok github.com/dalibo/ldap2pg/internal/config 0.007s ok github.com/dalibo/ldap2pg/internal/inspect 0.005s ok github.com/dalibo/ldap2pg/internal/ldap 0.005s ok github.com/dalibo/ldap2pg/internal/lists 0.005s ? github.com/dalibo/ldap2pg/internal/postgres [no test files] ok github.com/dalibo/ldap2pg/internal/perf 0.004s ok github.com/dalibo/ldap2pg/internal/privilege 0.003s ? github.com/dalibo/ldap2pg/internal/role [no test files] ok github.com/dalibo/ldap2pg/internal/pyfmt 0.004s ok github.com/dalibo/ldap2pg/internal/tree 0.002s ok github.com/dalibo/ldap2pg/internal/wanted 0.003s $
H.1.12.4. Functionnal tests #
test/
directory is a [pytest] project with
functionnal tests. Functionnal tests tend to validate ldap2pg in
real world : no mocks.
Func tests requires Python 3.6. Create a virtualenv to isolate
ldap2pg dev Python dependencies. Install dev dependencies with
pip install -Ur test/requirements.txt
.
$ pip install -Ur test/requirements.txt ... Successfully installed iniconfig-2.0.0 packaging-23.1 pluggy-1.3.0 pytest-7.4.2 sh-1.14.1 $
You can run func tests right from you development environment:
$ pip install -Ur test/requirements.txt ... $ pytest test/ ... ldap2pg: /home/bersace/src/dalibo/ldap2pg/test/ldap2pg.sh ... test/test_nominal.py::test_re_revoke PASSED [ 90%] test/test_nominal.py::test_nothing_to_do PASSED [100%] =============================== 11 passed in 14.90s ================================ $
CI executes func tests in CentOS 6 and 7 and RockyLinux 8 and 9.
Tests are written with the great
pytest and
sh
projects. conftest.py
provides various
specific fixtures. The most important is that Postgres database
is reset between each Python
module. pytests executes Func
tests in definition order. If a test modifies Postgres, the
following tests will have this modification kept until the end
of the module. This allows to split a big scenario in severals
steps without loosing context and CPU cycle.
Two main pytest fixtures are very useful when testing:
psql
and ldap
. These
little helpers provide fastpath to frequent inspection of
Postgres database on LDAP base with
sh.py
-style API.
You can execute tests just like in CI with the following commands:
$ goreleaser build --clean --snapshot --single-target $ COMPOSE_FILE=docker-compose.yml:test/docker-compose.yml docker compose up --exit-code-from=test
H.1.12.5. Big Case #
To stress ldap2pg on big setup, use make big
.
This will feed directory with a lot of users and groups, several
databases with a lot of schemas, etc. Synchronize this setup
with:
$ test/genperfconfig.sh | PGDATABASE=big0 go run ./cmd/ldap2pg -c -
H.1.12.6. Documenting #
Building documentation requires Python 3.7.
mkdocs is in
charge of building the documentation. To edit the doc, install
docs/requirements.txt
and run
mkdocs serve
at the toplevel directory. See
mkdocs
documentation for further information.
$ pip install -r docs/requirements.txt ... Successfully installed babel-2.12.1 certifi-2023.7.22 charset-normalizer-3.2.0 click-8.1.7 colorama-0.4.6 ghp-import-2.1.0 idna-3.4 jinja2-3.1.2 markdown-3.5 m...
H.1.12.7. Releasing #
Update default.pgo
Review
docs/changelog.md
. First title must be# ldap2pg X.Y
Generate release commit, tag and changelog with
make release
. make reads next version from changelog.Once CircleCI has created GitHub release artifacts, publish packages with
make publish-packages
.Once Docker Hub has published new tag, tag latest image on docker hub with
make tag-latest
.
H.1.13. Support #
If you need support and you didn’t found it in documentation, just drop a question in a GitHub issue! French accepted. Don’t miss the cookbook for advanced use cases.
H.1.14. Authors #
ldap2pg is a Dalibo Labs project.
Étienne BERSAC is the maintainer.
Damien Cazeils designed the logo.
Harold le CLÉMENT de SAINT-MARCQ implemented LDAP sub searches.
Randolph Voorhies implemented role configuration synchronization.