Major architectural change from rootless user services to system-level (rootful) containers to enable group-based Unix socket access for containerized applications. Infrastructure Changes: - PostgreSQL: Export postgres-clients group GID as Ansible fact - Valkey: Export valkey-clients group GID as Ansible fact - Valkey: Add socket-fix service to maintain correct socket group ownership - Both: Set socket directories to 770 with client group ownership Authentik Role Refactoring: - Remove rootless container configuration (subuid/subgid, lingering, user systemd) - Deploy Quadlet files to /etc/containers/systemd/ (system-level) - Use dynamic GID facts in container PodmanArgs (--group-add) - Simplify user creation to system user with infrastructure group membership - Update handlers for system scope service management - Remove unnecessary container security options (no user namespace isolation) Container Template Changes: - Pod: Remove --userns args, change WantedBy to multi-user.target - Containers: Replace Annotation with PodmanArgs using dynamic GIDs - Remove /dev/shm mounts and SecurityLabelDisable (not needed for rootful) - Change WantedBy to multi-user.target for system services Documentation Updates: - Add ADR-005: Rootful Containers with Infrastructure Fact Pattern - Update ADR-003: Podman + systemd for system-level deployment - Update authentik-deployment-guide.md for system scope commands - Update service-integration-guide.md with rootful pattern examples - Document discarded rootless approach and rationale Why Rootful Succeeds: - Direct UID/GID mapping preserves supplementary groups - Container process groups match host socket group ownership - No user namespace remapping breaking permissions Why Rootless Failed (Discarded): - User namespace UID/GID remapping broke group-based socket access - Supplementary groups remapped into subgid range didn't match socket ownership - Even with --userns=host and keep_original_groups, permissions failed Pattern Established: - Infrastructure roles create client groups and export GID facts - Application roles validate facts and consume in container templates - Rootful containers run as dedicated users with --group-add for socket access - System-level deployment provides standard systemd service management Deployment Validated: - Services in /system.slice/ ✓ - Process groups: 961 (valkey-clients), 962 (postgres-clients), 966 (authentik) ✓ - Socket permissions: 770 with client groups ✓ - HTTP endpoint responding ✓
PostgreSQL Infrastructure Role
This role provides PostgreSQL as shared database infrastructure for rick-infra applications. It follows the self-contained service architecture where this role provides the database server, and applications manage their own databases and users.
Architecture
PostgreSQL serves as database infrastructure (similar to how Caddy provides web infrastructure):
- PostgreSQL Role: Installs and configures PostgreSQL server
- Application Roles: Create their own databases/users via dependency
Features
- ✅ Native Arch Linux installation via pacman
- ✅ Secure configuration with scram-sha-256 authentication
- ✅ SystemD security hardening
- ✅ Data integrity with checksums enabled by default
- ✅ Performance-tuned defaults
- ✅ Comprehensive logging configuration
- ✅ UTF-8 encoding with C.UTF-8 locale
Usage
In Application Roles
Add PostgreSQL as a dependency in your application's meta/main.yml:
dependencies:
- role: postgresql
tags: ['postgresql', 'infrastructure']
Then create your application's database and user in your tasks:
- name: Create application database user
postgresql_user:
name: "{{ myapp_db_user }}"
password: "{{ myapp_db_password }}"
encrypted: yes
become: yes
become_user: postgres
- name: Create application database
postgresql_db:
name: "{{ myapp_db_name }}"
owner: "{{ myapp_db_user }}"
encoding: UTF8
template: template0
become: yes
become_user: postgres
In site.yml
- name: Deploy Infrastructure
hosts: arch-vps
become: yes
roles:
- role: postgresql
tags: ['postgresql', 'infrastructure', 'database']
- role: myapp # Will use PostgreSQL infrastructure
tags: ['myapp']
Configuration Variables
Basic Configuration
| Variable | Default | Description |
|---|---|---|
postgresql_service_enabled |
true |
Enable PostgreSQL service |
postgresql_service_state |
"started" |
Service state |
postgresql_port |
5432 |
PostgreSQL port |
postgresql_listen_addresses |
"localhost" |
Listen addresses |
Security Configuration
| Variable | Default | Description |
|---|---|---|
postgresql_auth_method |
"scram-sha-256" |
Authentication method |
postgresql_systemd_security |
true |
Enable systemd security hardening |
postgresql_data_checksums |
true |
Enable data checksums |
postgresql_ssl |
false |
Enable SSL/TLS |
Performance Configuration
| Variable | Default | Description |
|---|---|---|
postgresql_max_connections |
100 |
Maximum connections |
postgresql_shared_buffers |
"128MB" |
Shared buffer size |
postgresql_effective_cache_size |
"1GB" |
Effective cache size |
See defaults/main.yml for all available configuration options.
Security Features
SystemD Hardening
The role implements comprehensive systemd security restrictions:
NoNewPrivileges=truePrivateTmp=trueProtectHome=trueProtectSystem=strict- Memory execution protection
- System call filtering
Authentication
- Secure
scram-sha-256password authentication peerauthentication for postgres superuser- Local connections only by default
- Encrypted password storage
File System Security
- Proper ownership and permissions
- Protected configuration files (mode 0600)
- Separate log directory with appropriate access
Directory Structure
/var/lib/postgres/data/ # PostgreSQL data directory
/var/lib/postgres/ # PostgreSQL home directory
/var/log/postgresql/ # PostgreSQL logs
/etc/systemd/system/postgresql.service.d/ # SystemD overrides
Database Administration
Connect as postgres superuser:
sudo -u postgres psql
Create application database and user:
CREATE ROLE myapp WITH LOGIN PASSWORD 'secure_password';
CREATE DATABASE myapp WITH OWNER myapp TEMPLATE template0 ENCODING 'UTF8';
List databases:
\l
List users:
\du
Performance Tuning
The role provides conservative performance defaults suitable for most applications. For production workloads, consider adjusting:
postgresql_shared_buffers: 25% of system RAMpostgresql_effective_cache_size: 75% of system RAMpostgresql_max_connections: Based on application needspostgresql_maintenance_work_mem: For large datasets
Monitoring
Service Status
systemctl status postgresql
Logs
journalctl -u postgresql
# or
sudo -u postgres tail -f /var/log/postgresql/postgresql-*.log
Connection Test
sudo -u postgres psql -c "SELECT version();"
Troubleshooting
Common Issues
- Permission Denied: Ensure postgres user owns data directory
- Connection Refused: Check service status and listen_addresses
- Authentication Failed: Verify pg_hba.conf configuration
Debug Mode
Enable detailed logging:
postgresql_log_statement: "all"
postgresql_log_connections: true
postgresql_log_disconnections: true
Examples
Development Setup
postgresql_log_statement: "all" # Log all statements
postgresql_max_connections: 50 # Lower for development
Production Setup
postgresql_shared_buffers: "256MB"
postgresql_effective_cache_size: "2GB"
postgresql_log_min_duration_statement: 1000 # Log slow queries
postgresql_log_connections: true # Audit trail
High Security Setup
postgresql_ssl: true
postgresql_log_connections: true
postgresql_log_disconnections: true
postgresql_log_statement: "ddl" # Log schema changes
Dependencies
- Arch Linux PostgreSQL package
- python-psycopg2 (for Ansible modules)
Compatibility
- OS: Arch Linux
- PostgreSQL: Latest stable version from Arch repositories
- Ansible: >= 2.9
Contributing
When modifying this role:
- Update this README for any new features
- Test with example applications
- Ensure security configurations remain intact
- Follow rick-infra coding standards
Integration Examples
See roles that use this infrastructure:
gitea: Git repository managementnextcloud(planned): File sharing and collaboration
Rick-Infra PostgreSQL Infrastructure Role
Provides secure, performant PostgreSQL database infrastructure for rick-infra applications.