2026-03-12 21:01:38

This commit is contained in:
2026-03-12 22:01:38 +01:00
parent 3bd1db26cc
commit 26296b6d6a
336 changed files with 27507 additions and 0 deletions

View File

@@ -0,0 +1,208 @@
# 📄 Technical Guide: Setting Up TLS for PostgreSQL
This document consolidates the groups discussion into a practical, productionready reference for configuring and using TLS with PostgreSQL, including server setup, client configuration, password management, and example application code.
---
## 1. Overview
PostgreSQL supports encrypted connections using TLS (often referred to as SSL in its configuration). Enabling TLS ensures secure clientserver communication and can optionally enforce client certificate authentication. This guide provides stepbystep instructions for server and client configuration, common pitfalls, and usage examples.
---
## 2. Server-Side Configuration
### Certificates
* Required files:
* [`server.key`](https://server.key) → private key
* [`server.crt`](https://server.crt) → server certificate
* [`root.crt`](https://root.crt) → CA certificate (recommended)
* Sources: internal PKI, Lets Encrypt, or selfsigned CA.
* Permissions: [`server.key`](https://server.key) must be `0600` or rootowned with restricted group access.
### Placement
* Default paths:
* `$PGDATA/`[`server.key`](https://server.key)
* `$PGDATA/`[`server.crt`](https://server.crt)
* Override with `ssl_cert_file`, `ssl_key_file`, `ssl_ca_file` in [`postgresql.conf`](https://postgresql.conf).
### Configuration
Enable TLS in [`postgresql.conf`](https://postgresql.conf):
```conf
ssl = on
ssl_ciphers = 'HIGH:!aNULL:!MD5'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'
ssl_max_protocol_version = 'TLSv1.3'
```
### Access Control
Configure `pg_hba.conf`:
* Allow TLS but not require:
```
host all all 0.0.0.0/0 md5
```
* Require TLS:
```
hostssl all all 0.0.0.0/0 md5
```
* Require TLS + client certificate:
```
hostssl all all 0.0.0.0/0 cert
```
---
## 3. Client-Side Configuration
### Basic TLS
```bash
psql "host=db.example.com sslmode=require"
```
### Verify server certificate
```bash
psql "host=db.example.com sslmode=verify-full sslrootcert=/etc/ssl/myca/root.crt"
```
* `sslrootcert` is a **client-side path** to the CA certificate.
### Mutual TLS
```bash
psql "host=db.example.com sslmode=verify-full \
sslrootcert=/etc/ssl/myca/root.crt \
sslcert=/etc/ssl/myca/client.crt \
sslkey=/etc/ssl/myca/client.key"
```
### Modes comparison
| Mode | Encrypts | Validates CA | Validates Hostname | Typical Use |
| --- | --- | --- | --- | --- |
| `require` | Yes | No | No | Basic encryption |
| `verify-ca` | Yes | Yes | No | Internal/IP-based |
| `verify-full` | Yes | Yes | Yes | Production |
---
## 4. Password Management
### `.pgpass` file (recommended)
Format:
```
hostname:port:database:username:password
```
Example:
```
db.example.com:5432:mydb:myuser:SuperSecretPassword123
localhost:5432:*:postgres:localdevpass
*:5432:*:replicator:replicaPassword
```
* Location: `~/.pgpass`
* Permissions: `chmod 600 ~/.pgpass`
* Supports wildcards (`*`).
### Environment variable
```bash
PGPASSWORD='secret123' psql -U myuser -h localhost -d mydb
```
Less secure; use only for quick commands.
---
## 5. Testing & Verification
* Check server TLS status:
```sql
SHOW ssl;
```
* Inspect negotiated protocol & cipher:
```sql
SELECT * FROM pg_stat_ssl;
```
* External test:
```bash
openssl s_client -connect db.example.com:5432 -starttls postgres
```
---
## 6. Common Pitfalls
| Issue | Cause | Fix |
| --- | --- | --- |
| `FATAL: private key file has group or world access` | Wrong permissions | `chmod 600 `[`server.key`](https://server.key) |
| Client rejects certificate | CN/SAN mismatch | Ensure proper DNS SANs |
| TLS not enforced | Used `host` instead of `hostssl` | Update `pg_hba.conf` |
| Backup tools fail | Key readable only by postgres | Store certs outside `$PGDATA` if group-readable needed |
---
## 7. Application Example (Python)
Minimal psycopg2 script with TLS `verify-full` and bind variables:
```python
import psycopg2
import psycopg2.extras
def main():
conn = psycopg2.connect(
host="db.example.com",
port=5432,
dbname="mydb",
user="myuser",
password="SuperSecretPassword123",
sslmode="verify-full",
sslrootcert="/etc/ssl/myca/root.crt",
sslcert="/etc/ssl/myca/client.crt", # optional
sslkey="/etc/ssl/myca/client.key" # optional
)
with conn:
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
cur.execute("SELECT id, name FROM demo WHERE id = %s", (1,))
print("SELECT:", cur.fetchone())
cur.execute("INSERT INTO demo (id, name) VALUES (%s, %s)", (2, "Inserted Name"))
cur.execute("UPDATE demo SET name = %s WHERE id = %s", ("Updated Name", 2))
cur.execute("DELETE FROM demo WHERE id = %s", (2,))
conn.close()
if __name__ == "__main__":
main()
```
---
## Appendix / Future Considerations
* Hardened production templates (PKI layout, Ansible roles, CI/CD verification checklist).
* Alternative drivers: psycopg3, SQLAlchemy, async examples.
* Integration with secret management (Kubernetes secrets, systemd, Ansible vault).
* Directory layout best practices for server vs client PKI.
---
✅ This document now serves as a consolidated technical guide for setting up and using TLS with PostgreSQL, including secure password handling and client application integration.