Skip to main content

PostgreSQL PAM Authentication

Guide for configuring PAM (Pluggable Authentication Modules) authentication in PostgreSQL, including integration with LDAP for centralized user management.

What is PAM Authentication?

PAM allows PostgreSQL to use the system's authentication mechanisms instead of managing passwords internally. This enables:

  • Using system users for database access
  • Integration with LDAP/Active Directory
  • Centralized authentication management
  • Support for various authentication methods

Basic PAM Setup

Step 1: Configure pg_hba.conf

Edit PostgreSQL's host-based authentication file:

sudo nvim /var/lib/pgsql/data/pg_hba.conf

Add a PAM authentication entry:

# TYPE  DATABASE  USER  ADDRESS      METHOD          OPTIONS
host all all 0.0.0.0/0 pam pamservice=postgresql
Connection Types
  • local: Unix socket connections
  • host: TCP/IP connections (with or without SSL)
  • hostssl: SSL-encrypted TCP/IP only
  • hostnossl: Non-SSL TCP/IP only

Step 2: Adjust Shadow File Permissions

PostgreSQL needs to read the shadow file for authentication:

sudo chmod 444 /etc/shadow
Security Consideration

This makes the shadow file readable by all users. While the passwords are still hashed, consider security implications in your environment. Alternative: add postgres user to shadow group.

Alternative (more secure):

sudo usermod -aG shadow postgres
sudo chmod 640 /etc/shadow

Step 3: Create PAM Service File

Create or edit the PAM configuration for PostgreSQL:

sudo nvim /etc/pam.d/postgresql

Basic configuration:

auth        required    pam_unix.so debug
account required pam_permit.so

Explanation:

  • auth required pam_unix.so: Use Unix system authentication
  • debug: Enable detailed logging (remove in production)
  • account required pam_permit.so: Allow all authenticated users

Step 4: Restart PostgreSQL

Apply the changes:

sudo systemctl restart postgresql

Step 5: Test Authentication

Try connecting with a system user:

psql -h localhost -U systemuser -d postgres

The system will prompt for the user's system password.

PAM with LDAP Integration

Prerequisites

Install PAM LDAP module:

Arch Linux:

yay -S pam_ldap

Debian/Ubuntu:

sudo apt install libpam-ldap

RHEL/AlmaLinux:

sudo yum install pam_ldap

This installs:

  • PAM module: /usr/lib/security/pam_ldap.so
  • Config file: /etc/pam_ldap.conf

Configure PAM LDAP

Edit the LDAP configuration:

sudo nvim /etc/pam_ldap.conf

Basic configuration:

# LDAP server host
host localhost

# Base DN for user searches
base ou=users,dc=example,dc=org

# LDAP port
port 389

# Optional: Use LDAPS (secure)
# ssl start_tls
# port 636

Advanced options:

# Bind credentials (if required)
binddn cn=readonly,dc=example,dc=org
bindpw secretpassword

# Search scope
scope sub

# Filter for user authentication
pam_filter objectClass=posixAccount

# Attribute mappings
pam_login_attribute uid
pam_member_attribute memberUid

Configure PAM Service for LDAP

Edit or create the PAM service file:

sudo nvim /etc/pam.d/postgresql

For LDAP authentication:

auth        required    pam_ldap.so
account required pam_ldap.so

Or combine Unix and LDAP (fallback):

auth        sufficient  pam_ldap.so
auth required pam_unix.so
account sufficient pam_ldap.so
account required pam_permit.so
sufficient vs required
  • sufficient: If successful, no further modules are checked
  • required: Must succeed, but continues checking other modules
  • requisite: Must succeed, stops immediately if fails

PgBouncer PAM Configuration

If using PgBouncer as a connection pooler:

Configure PgBouncer

Edit pgbouncer.ini:

[databases]
mydb = host=localhost port=5432 dbname=mydb

[pgbouncer]
auth_type = pam
auth_file = /etc/pgbouncer/userlist.txt

Create PAM Service for PgBouncer

sudo nvim /etc/pam.d/pgbouncer

Content:

auth        required    pam_ldap.so
account required pam_ldap.so

Adjust Permissions

sudo chmod 444 /etc/shadow
# Or add pgbouncer user to shadow group
sudo usermod -aG shadow pgbouncer

Testing and Troubleshooting

Test LDAP Connection

# Test LDAP search
ldapsearch -x -H ldap://localhost:389 -b "ou=users,dc=example,dc=org"

# Test specific user
ldapsearch -x -H ldap://localhost:389 -b "ou=users,dc=example,dc=org" "(uid=username)"

Check PAM Authentication

Test PAM directly:

pamtester postgresql username authenticate

View Logs

# PostgreSQL logs
sudo tail -f /var/log/postgresql/postgresql-*.log

# System auth logs
sudo tail -f /var/log/auth.log # Debian/Ubuntu
sudo tail -f /var/log/secure # RHEL/CentOS

# PAM debug output
journalctl -u postgresql -f

Common Issues

Issue: Permission denied

Solution: Check shadow file permissions and postgres user groups

Issue: LDAP connection failed

Solution: 
- Verify LDAP server is running: systemctl status slapd
- Test connectivity: telnet localhost 389
- Check firewall: sudo firewall-cmd --list-all

Issue: User not found in LDAP

Solution:
- Verify base DN in pam_ldap.conf
- Check LDAP user's posixAccount objectClass
- Test ldapsearch with same parameters

Security Best Practices

  1. Use SSL/TLS for LDAP
ssl start_tls
port 636
tls_cacertdir /etc/ssl/certs
  1. Limit Database Access
# Only allow specific users
host mydb ldapuser1,ldapuser2 0.0.0.0/0 pam
  1. Use Read-Only LDAP Bind Account
binddn cn=readonly,dc=example,dc=org
  1. Enable Logging
auth    required    pam_unix.so debug
  1. Restrict Shadow File
sudo usermod -aG shadow postgres
sudo chmod 640 /etc/shadow

Complete Example Configuration

pg_hba.conf

# TYPE  DATABASE  USER           ADDRESS      METHOD    OPTIONS
local all postgres peer
host all all 127.0.0.1/32 pam pamservice=postgresql
host all all 0.0.0.0/0 pam pamservice=postgresql

/etc/pam.d/postgresql

auth        sufficient  pam_ldap.so
auth required pam_unix.so
account sufficient pam_ldap.so
account required pam_permit.so

/etc/pam_ldap.conf

host ldap.example.org
base ou=users,dc=example,dc=org
port 389
ssl start_tls
pam_login_attribute uid
pam_filter objectClass=posixAccount

Additional Resources