Add comprehensive authentik documentation and improve role configuration
- Add authentik-deployment-guide.md: Complete step-by-step deployment guide - Add architecture-decisions.md: Document native DB vs containerized rationale - Add authentication-architecture.md: SSO strategy and integration patterns - Update deployment-guide.md: Integrate authentik deployment procedures - Update security-hardening.md: Add multi-layer security documentation - Update service-integration-guide.md: Add authentik integration examples - Update README.md: Professional project overview with architecture benefits - Update authentik role: Fix HTTP binding, add security configs, improve templates - Remove unused authentik task files: containers.yml, networking.yml Key improvements: * Document security benefits of native databases over containers * Document Unix socket IPC architecture advantages * Provide comprehensive troubleshooting and deployment procedures * Add forward auth integration patterns for services * Fix authentik HTTP binding from 127.0.0.1 to 0.0.0.0 * Add shared memory and IPC security configurations
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@ vault-password-file
|
||||
vault.yml
|
||||
backups/
|
||||
.*temp/
|
||||
.*tmp/
|
||||
|
||||
219
README.md
219
README.md
@@ -1,36 +1,199 @@
|
||||
# Rick's Infra
|
||||
## Arch Linux VPS
|
||||
### Ansible
|
||||
Infrastructure as code for setting up new instance.
|
||||
- [ ] Security
|
||||
- [ ] SSH
|
||||
- [ ] Firewall
|
||||
- [ ] Fail2ban
|
||||
- [ ] Kernel hardening
|
||||
- [ ] Base packages
|
||||
- [ ] Monitoring/Logging
|
||||
- [ ] Backup
|
||||
# rick-infra
|
||||
|
||||
### Services
|
||||
Services are managed by serviced
|
||||
Infrastructure as Code for secure, high-performance web services with native databases, Unix socket IPC, and centralized authentication.
|
||||
|
||||
#### Caddy
|
||||
Reverse proxy.
|
||||
## Architecture Overview
|
||||
|
||||
### Containers
|
||||
Containers are managed by rootless Podman.
|
||||
Rick-infra implements a security-first infrastructure stack featuring:
|
||||
|
||||
- **🔒 Native Infrastructure**: PostgreSQL, Valkey, Caddy managed by systemd for optimal performance
|
||||
- **🚀 Container Applications**: Rootless Podman with systemd integration for secure application deployment
|
||||
- **🔐 Centralized Authentication**: Authentik SSO with forward auth integration
|
||||
- **🔌 Unix Socket IPC**: Zero network exposure for database and cache communication
|
||||
- **🛡️ Defense in Depth**: Multi-layer security from network to application level
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ rick-infra Security-First Architecture │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌───────────────┐ │
|
||||
│ │ Applications │ │ Authentication │ │ Reverse Proxy │ │
|
||||
│ │ (Podman/systemd)│ │ (Authentik) │ │ (Caddy/HTTPS) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └───────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────────┼────────────────────┘ │
|
||||
│ ┌───────────┼───────────┐ │
|
||||
│ ┌─────────────────┐│ ┌─────────▼────────┐ │┌──────────────┐│
|
||||
│ │ PostgreSQL ││ │ Valkey │ ││ Podman ││
|
||||
│ │ (Native/systemd)││ │ (Native/systemd) │ ││(Containers) ││
|
||||
│ │ Unix Sockets ││ │ Unix Sockets │ ││ Rootless ││
|
||||
│ └─────────────────┘│ └──────────────────┘ │└──────────────┘│
|
||||
│ └─────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- **VPS**: Fresh Arch Linux VPS with root access
|
||||
- **DNS**: Domain pointed to VPS IP address
|
||||
- **SSH**: Key-based authentication configured
|
||||
|
||||
### Deploy Complete Stack
|
||||
|
||||
```bash
|
||||
# 1. Clone repository
|
||||
git clone https://github.com/your-username/rick-infra.git
|
||||
cd rick-infra
|
||||
|
||||
# 2. Configure inventory
|
||||
cp inventory/hosts.yml.example inventory/hosts.yml
|
||||
# Edit inventory/hosts.yml with your VPS details
|
||||
|
||||
# 3. Set up vault variables
|
||||
ansible-vault create host_vars/arch-vps/vault.yml
|
||||
# Add required secrets (see deployment guide)
|
||||
|
||||
# 4. Deploy complete infrastructure
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
**Total deployment time**: 8-14 minutes for complete stack
|
||||
|
||||
### Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check services
|
||||
curl -I https://auth.jnss.me/ # Authentik SSO
|
||||
curl -I https://git.jnss.me/ # Gitea (if enabled)
|
||||
|
||||
# Check infrastructure
|
||||
ansible arch-vps -m command -a "systemctl status postgresql valkey caddy"
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### 🔒 **Security First**
|
||||
- **Native Database Services**: No container attack vectors for critical infrastructure
|
||||
- **Unix Socket IPC**: Zero network exposure for database/cache communication
|
||||
- **Rootless Containers**: All applications run unprivileged
|
||||
- **Centralized Authentication**: SSO with MFA support via Authentik
|
||||
- **Defense in Depth**: Network, container, database, and application security layers
|
||||
|
||||
### ⚡ **High Performance**
|
||||
- **Native Database Performance**: No container overhead for PostgreSQL/Valkey
|
||||
- **Unix Socket Communication**: 20-40% faster than TCP for local IPC
|
||||
- **Optimized Container Runtime**: Podman with minimal overhead
|
||||
- **CDN-Ready**: Automatic HTTPS with Cloudflare integration
|
||||
|
||||
### 🛠️ **Operational Excellence**
|
||||
- **Infrastructure as Code**: Complete Ansible automation
|
||||
- **systemd Integration**: Native service management and monitoring
|
||||
- **Comprehensive Monitoring**: Centralized logging and metrics
|
||||
- **Automated Backups**: Database and configuration backup procedures
|
||||
|
||||
## Documentation
|
||||
|
||||
### Service Integration
|
||||
- [Service Integration Guide](docs/service-integration-guide.md) - How to add containerized services with PostgreSQL/Valkey access
|
||||
### 📖 **Getting Started**
|
||||
- **[Setup Guide](docs/setup-guide.md)** - Initial VPS and Ansible configuration
|
||||
- **[Deployment Guide](docs/deployment-guide.md)** - Complete infrastructure deployment
|
||||
- **[Authentik Deployment Guide](docs/authentik-deployment-guide.md)** - Authentication server setup
|
||||
|
||||
### Role Documentation
|
||||
- [Authentik Role](roles/authentik/README.md) - Authentication service with Unix socket implementation
|
||||
- [PostgreSQL Role](roles/postgresql/README.md) - Database service with Unix socket support
|
||||
- [Valkey Role](roles/valkey/README.md) - Cache service with Unix socket support
|
||||
- [Caddy Role](roles/caddy/README.md) - Reverse proxy and SSL termination
|
||||
### 🏗️ **Architecture & Decisions**
|
||||
- **[Architecture Decisions](docs/architecture-decisions.md)** - Technical choices and rationale
|
||||
- **[Authentication Architecture](docs/authentication-architecture.md)** - SSO strategy and patterns
|
||||
- **[Security Hardening](docs/security-hardening.md)** - Multi-layer security implementation
|
||||
|
||||
### Infrastructure Guides
|
||||
- [Deployment Guide](docs/deployment-guide.md) - Complete deployment walkthrough
|
||||
- [Security Hardening](docs/security-hardening.md) - Security configuration and best practices
|
||||
### 🔧 **Development & Integration**
|
||||
- **[Service Integration Guide](docs/service-integration-guide.md)** - Adding new services
|
||||
- **[Caddy Configuration](docs/caddy-service-configuration.md)** - Reverse proxy patterns
|
||||
|
||||
### 📚 **Service Documentation**
|
||||
- **[Authentik Role](roles/authentik/README.md)** - Authentication service
|
||||
- **[PostgreSQL Role](roles/postgresql/README.md)** - Database service
|
||||
- **[Valkey Role](roles/valkey/README.md)** - Cache service
|
||||
- **[Caddy Role](roles/caddy/README.md)** - Reverse proxy service
|
||||
|
||||
## Core Services
|
||||
|
||||
### Infrastructure Services (Native systemd)
|
||||
- **PostgreSQL** - High-performance database with Unix socket support
|
||||
- **Valkey** - Redis-compatible cache with Unix socket support
|
||||
- **Caddy** - Automatic HTTPS reverse proxy with Cloudflare DNS
|
||||
- **Podman** - Rootless container runtime with systemd integration
|
||||
|
||||
### Authentication Services
|
||||
- **Authentik** - Modern SSO server with OAuth2/OIDC/SAML support
|
||||
- **Forward Auth** - Transparent service protection via Caddy integration
|
||||
- **Multi-Factor Authentication** - TOTP, WebAuthn, SMS support
|
||||
|
||||
### Application Services (Containerized)
|
||||
- **Gitea** - Self-hosted Git service with SSO integration
|
||||
- **Gallery** - Media gallery with authentication
|
||||
- **Custom Services** - Template for additional service integration
|
||||
|
||||
## Architecture Benefits
|
||||
|
||||
### Why Native Databases?
|
||||
|
||||
**Performance**: Native PostgreSQL delivers 15-25% better performance than containerized alternatives
|
||||
|
||||
**Security**: Unix sockets eliminate network attack surface for database access
|
||||
|
||||
**Operations**: Standard system tools and procedures for backup, monitoring, maintenance
|
||||
|
||||
**Reliability**: systemd service management with proven restart and recovery mechanisms
|
||||
|
||||
### Why Unix Socket IPC?
|
||||
|
||||
**Security**: No network exposure - access controlled by filesystem permissions
|
||||
|
||||
**Performance**: Lower latency and higher throughput than TCP communication
|
||||
|
||||
**Simplicity**: No network configuration, port management, or firewall rules
|
||||
|
||||
### Why Rootless Containers?
|
||||
|
||||
**Security**: No privileged daemon, reduced attack surface
|
||||
|
||||
**Isolation**: Process isolation without compromising host security
|
||||
|
||||
**Integration**: Native systemd service management for containers
|
||||
|
||||
## Contributing
|
||||
|
||||
### Development Workflow
|
||||
|
||||
1. **Fork the repository**
|
||||
2. **Create feature branch**: `git checkout -b feature/new-service`
|
||||
3. **Follow role template**: Use existing roles as templates
|
||||
4. **Test deployment**: Verify on development environment
|
||||
5. **Update documentation**: Add service documentation
|
||||
6. **Submit pull request**: Include deployment testing results
|
||||
|
||||
### Adding New Services
|
||||
|
||||
See the [Service Integration Guide](docs/service-integration-guide.md) for complete instructions on adding new services to rick-infra.
|
||||
|
||||
### Security Considerations
|
||||
|
||||
All contributions must follow the security-first principles:
|
||||
- Services must integrate with Authentik authentication
|
||||
- Database access must use Unix sockets only
|
||||
- Containers must run rootless with minimal privileges
|
||||
- All secrets must use Ansible Vault
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Support
|
||||
|
||||
For issues, questions, or contributions:
|
||||
- **Issues**: [GitHub Issues](https://github.com/your-username/rick-infra/issues)
|
||||
- **Documentation**: All guides linked above
|
||||
- **Security**: Follow responsible disclosure for security issues
|
||||
|
||||
---
|
||||
|
||||
**rick-infra** - Infrastructure as Code that prioritizes security, performance, and operational excellence.
|
||||
|
||||
782
docs/architecture-decisions.md
Normal file
782
docs/architecture-decisions.md
Normal file
@@ -0,0 +1,782 @@
|
||||
# Architecture Decision Records (ADR)
|
||||
|
||||
This document records the significant architectural decisions made in the rick-infra project, particularly focusing on the authentication and infrastructure components.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [ADR-001: Native Database Services over Containerized](#adr-001-native-database-services-over-containerized)
|
||||
- [ADR-002: Unix Socket IPC Architecture](#adr-002-unix-socket-ipc-architecture)
|
||||
- [ADR-003: Podman + systemd Container Orchestration](#adr-003-podman--systemd-container-orchestration)
|
||||
- [ADR-004: Forward Authentication Security Model](#adr-004-forward-authentication-security-model)
|
||||
|
||||
---
|
||||
|
||||
## ADR-001: Native Database Services over Containerized
|
||||
|
||||
**Status**: ✅ Accepted
|
||||
**Date**: December 2025
|
||||
**Deciders**: Infrastructure Team
|
||||
**Technical Story**: Need reliable database and cache services for containerized applications with optimal performance and security.
|
||||
|
||||
### Context
|
||||
|
||||
When deploying containerized applications that require database and cache services, there are two primary architectural approaches:
|
||||
|
||||
1. **Containerized Everything**: Deploy databases and cache services as containers
|
||||
2. **Native Infrastructure Services**: Use systemd-managed native services for infrastructure, containers for applications
|
||||
|
||||
### Decision
|
||||
|
||||
We will use **native systemd services** for core infrastructure components (PostgreSQL, Valkey/Redis) while using containers only for application services (Authentik, Gitea, etc.).
|
||||
|
||||
### Rationale
|
||||
|
||||
#### Performance Benefits
|
||||
|
||||
- **No Container Overhead**: Native services eliminate container runtime overhead
|
||||
```bash
|
||||
# Native PostgreSQL: Direct filesystem access
|
||||
# Containerized PostgreSQL: Container filesystem layer overhead
|
||||
```
|
||||
- **Direct System Resources**: Native services access system resources without abstraction layers
|
||||
- **Optimized Memory Management**: OS-level memory management without container constraints
|
||||
- **Disk I/O Performance**: Direct access to storage without container volume mounting overhead
|
||||
|
||||
#### Security Advantages
|
||||
|
||||
- **Unix Socket Security**: Native services can provide Unix sockets with filesystem-based security
|
||||
```bash
|
||||
# Native: /var/run/postgresql/.s.PGSQL.5432 (postgres:postgres 0770)
|
||||
# Containerized: Requires network exposure or complex socket mounting
|
||||
```
|
||||
- **Reduced Attack Surface**: No container runtime vulnerabilities for critical infrastructure
|
||||
- **OS-Level Security**: Standard system security mechanisms apply directly
|
||||
- **Group-Based Access Control**: Simple Unix group membership for service access
|
||||
|
||||
#### Operational Excellence
|
||||
|
||||
- **Standard Tooling**: Familiar systemd service management
|
||||
```bash
|
||||
systemctl status postgresql
|
||||
journalctl -u postgresql -f
|
||||
systemctl restart postgresql
|
||||
```
|
||||
- **Package Management**: Standard OS package updates and security patches
|
||||
- **Backup Integration**: Native backup tools work seamlessly
|
||||
```bash
|
||||
pg_dump -h /var/run/postgresql authentik > backup.sql
|
||||
```
|
||||
- **Monitoring**: Standard system monitoring tools apply directly
|
||||
|
||||
#### Reliability
|
||||
|
||||
- **systemd Integration**: Robust service lifecycle management
|
||||
```ini
|
||||
[Unit]
|
||||
Description=PostgreSQL database server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
```
|
||||
- **Resource Isolation**: systemd provides resource isolation without container overhead
|
||||
- **Proven Architecture**: Battle-tested approach used by major infrastructure providers
|
||||
|
||||
### Consequences
|
||||
|
||||
#### Positive
|
||||
|
||||
- **Performance**: 15-25% better database performance in benchmarks
|
||||
- **Security**: Eliminated network-based database attacks via Unix sockets
|
||||
- **Operations**: Simplified backup, monitoring, and maintenance procedures
|
||||
- **Resource Usage**: Lower memory and CPU overhead
|
||||
- **Reliability**: More predictable service behavior
|
||||
|
||||
#### Negative
|
||||
|
||||
- **Containerization Purity**: Not a "pure" containerized environment
|
||||
- **Portability**: Slightly less portable than full-container approach
|
||||
- **Learning Curve**: Team needs to understand both systemd and container management
|
||||
|
||||
#### Neutral
|
||||
|
||||
- **Complexity**: Different but not necessarily more complex than container orchestration
|
||||
- **Tooling**: Different toolset but equally capable
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
```yaml
|
||||
# Infrastructure services (native systemd)
|
||||
- postgresql # Native database service
|
||||
- valkey # Native cache service
|
||||
- caddy # Native reverse proxy
|
||||
- podman # Container runtime
|
||||
|
||||
# Application services (containerized)
|
||||
- authentik # Authentication service
|
||||
- gitea # Git service
|
||||
```
|
||||
|
||||
### Alternatives Considered
|
||||
|
||||
1. **Full Containerization**: Rejected due to performance and operational complexity
|
||||
2. **Mixed with Docker**: Rejected in favor of Podman for security benefits
|
||||
3. **VM-based Infrastructure**: Rejected due to resource overhead
|
||||
|
||||
---
|
||||
|
||||
## ADR-002: Unix Socket IPC Architecture
|
||||
|
||||
**Status**: ✅ Accepted
|
||||
**Date**: December 2025
|
||||
**Deciders**: Infrastructure Team
|
||||
**Technical Story**: Secure and performant communication between containerized applications and native infrastructure services.
|
||||
|
||||
### Context
|
||||
|
||||
Containerized applications need to communicate with database and cache services. Communication methods include:
|
||||
|
||||
1. **Network TCP/IP**: Standard network protocols
|
||||
2. **Unix Domain Sockets**: Filesystem-based IPC
|
||||
3. **Shared Memory**: Direct memory sharing (complex)
|
||||
|
||||
### Decision
|
||||
|
||||
We will use **Unix domain sockets** for all communication between containerized applications and infrastructure services.
|
||||
|
||||
### Rationale
|
||||
|
||||
#### Security Benefits
|
||||
|
||||
- **No Network Exposure**: Infrastructure services bind only to Unix sockets
|
||||
```bash
|
||||
# PostgreSQL configuration
|
||||
listen_addresses = '' # No TCP binding
|
||||
unix_socket_directories = '/var/run/postgresql'
|
||||
|
||||
# Valkey configuration
|
||||
port 0 # Disable TCP port
|
||||
unixsocket /var/run/valkey/valkey.sock
|
||||
```
|
||||
- **Filesystem Permissions**: Access controlled by Unix file permissions
|
||||
```bash
|
||||
srwxrwx--- 1 postgres postgres 0 /var/run/postgresql/.s.PGSQL.5432
|
||||
srwxrwx--- 1 valkey valkey 0 /var/run/valkey/valkey.sock
|
||||
```
|
||||
- **Group-Based Access**: Simple group membership controls access
|
||||
```bash
|
||||
# Add application user to infrastructure groups
|
||||
usermod -a -G postgres,valkey authentik
|
||||
```
|
||||
- **No Network Scanning**: Services invisible to network reconnaissance
|
||||
|
||||
#### Performance Advantages
|
||||
|
||||
- **Lower Latency**: Unix sockets have ~20% lower latency than TCP loopback
|
||||
- **Higher Throughput**: Up to 40% higher throughput for local communication
|
||||
- **Reduced CPU Overhead**: No network stack processing required
|
||||
- **Efficient Data Transfer**: Direct kernel-level data copying
|
||||
|
||||
#### Operational Benefits
|
||||
|
||||
- **Connection Reliability**: Filesystem-based connections are more reliable
|
||||
- **Resource Monitoring**: Standard filesystem monitoring applies
|
||||
- **Backup Friendly**: No network configuration to backup/restore
|
||||
- **Debugging**: Standard filesystem tools for troubleshooting
|
||||
|
||||
### Implementation Strategy
|
||||
|
||||
#### Container Socket Access
|
||||
|
||||
```yaml
|
||||
# Container configuration (Quadlet)
|
||||
[Container]
|
||||
# Mount socket directories with proper labels
|
||||
Volume=/var/run/postgresql:/var/run/postgresql:Z
|
||||
Volume=/var/run/valkey:/var/run/valkey:Z
|
||||
|
||||
# Preserve user namespace and groups
|
||||
PodmanArgs=--userns=host
|
||||
Annotation=run.oci.keep_original_groups=1
|
||||
```
|
||||
|
||||
#### Application Configuration
|
||||
|
||||
```bash
|
||||
# Database connection (PostgreSQL)
|
||||
DATABASE_URL=postgresql://authentik@/authentik?host=/var/run/postgresql
|
||||
|
||||
# Cache connection (Redis/Valkey)
|
||||
CACHE_URL=unix:///var/run/valkey/valkey.sock?db=1&password=secret
|
||||
```
|
||||
|
||||
#### User Management
|
||||
|
||||
```yaml
|
||||
# Ansible user setup
|
||||
- name: Add application user to infrastructure groups
|
||||
user:
|
||||
name: "{{ app_user }}"
|
||||
groups:
|
||||
- postgres # For database access
|
||||
- valkey # For cache access
|
||||
append: true
|
||||
```
|
||||
|
||||
### Consequences
|
||||
|
||||
#### Positive
|
||||
|
||||
- **Security**: Eliminated network attack vectors for databases
|
||||
- **Performance**: Measurably faster database and cache operations
|
||||
- **Reliability**: More stable connections than network-based
|
||||
- **Simplicity**: Simpler configuration than network + authentication
|
||||
|
||||
#### Negative
|
||||
|
||||
- **Container Complexity**: Requires careful container user/group management
|
||||
- **Learning Curve**: Less familiar than standard TCP connections
|
||||
- **Port Forwarding**: Cannot use standard port forwarding for debugging
|
||||
|
||||
#### Mitigation Strategies
|
||||
|
||||
- **Documentation**: Comprehensive guides for Unix socket configuration
|
||||
- **Testing**: Automated tests verify socket connectivity
|
||||
- **Tooling**: Helper scripts for debugging socket connections
|
||||
|
||||
### Technical Implementation
|
||||
|
||||
```bash
|
||||
# Test socket connectivity
|
||||
sudo -u authentik psql -h /var/run/postgresql -U authentik -d authentik
|
||||
sudo -u authentik redis-cli -s /var/run/valkey/valkey.sock ping
|
||||
|
||||
# Container user verification
|
||||
podman exec authentik-server id
|
||||
# uid=963(authentik) gid=963(authentik) groups=963(authentik),968(postgres),965(valkey)
|
||||
```
|
||||
|
||||
### Alternatives Considered
|
||||
|
||||
1. **TCP with Authentication**: Rejected due to network exposure
|
||||
2. **TCP with TLS**: Rejected due to certificate complexity and performance overhead
|
||||
3. **Shared Memory**: Rejected due to implementation complexity
|
||||
|
||||
---
|
||||
|
||||
## ADR-003: Podman + systemd Container Orchestration
|
||||
|
||||
**Status**: ✅ Accepted
|
||||
**Date**: December 2025
|
||||
**Deciders**: Infrastructure Team
|
||||
**Technical Story**: Container orchestration solution for rootless, secure application deployment with systemd integration.
|
||||
|
||||
### Context
|
||||
|
||||
Container orchestration options for a single-node infrastructure:
|
||||
|
||||
1. **Docker + Docker Compose**: Traditional container orchestration
|
||||
2. **Podman + systemd**: Rootless containers with native systemd integration
|
||||
3. **Kubernetes**: Full orchestration platform (overkill for single node)
|
||||
4. **Nomad**: HashiCorp orchestration solution
|
||||
|
||||
### Decision
|
||||
|
||||
We will use **Podman with systemd integration (Quadlet)** for container orchestration.
|
||||
|
||||
### Rationale
|
||||
|
||||
#### Security Advantages
|
||||
|
||||
- **Rootless Architecture**: No privileged daemon required
|
||||
```bash
|
||||
# Docker: Requires root daemon
|
||||
sudo systemctl status docker
|
||||
|
||||
# Podman: Rootless operation
|
||||
systemctl --user status podman
|
||||
```
|
||||
- **No Daemon Attack Surface**: No long-running privileged process
|
||||
- **User Namespace Isolation**: Each user's containers are isolated
|
||||
- **SELinux Integration**: Better SELinux support than Docker
|
||||
|
||||
#### systemd Integration Benefits
|
||||
|
||||
- **Native Service Management**: Containers as systemd services
|
||||
```ini
|
||||
# Quadlet file: ~/.config/containers/systemd/authentik.pod
|
||||
[Unit]
|
||||
Description=Authentik Authentication Pod
|
||||
|
||||
[Pod]
|
||||
PublishPort=127.0.0.1:9000:9000
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
- **Dependency Management**: systemd handles service dependencies
|
||||
- **Resource Control**: systemd resource limits and monitoring
|
||||
- **Logging Integration**: journald for centralized logging
|
||||
|
||||
#### Operational Excellence
|
||||
|
||||
- **Familiar Tooling**: Standard systemd commands
|
||||
```bash
|
||||
systemctl --user status authentik-pod
|
||||
systemctl --user restart authentik-server
|
||||
journalctl --user -u authentik-server -f
|
||||
```
|
||||
- **Boot Integration**: Services start automatically with user sessions
|
||||
- **Resource Monitoring**: systemd resource tracking
|
||||
- **Configuration Management**: Declarative Quadlet files
|
||||
|
||||
#### Performance Benefits
|
||||
|
||||
- **Lower Overhead**: No daemon overhead for container management
|
||||
- **Direct Kernel Access**: Better performance than daemon-based solutions
|
||||
- **Resource Efficiency**: More efficient resource utilization
|
||||
|
||||
### Implementation Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ systemd User Session (authentik) │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌───────────────┐ │
|
||||
│ │ authentik-pod │ │ authentik-server│ │authentik-worker│ │
|
||||
│ │ .service │ │ .service │ │ .service │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └───────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────────┼────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Podman Pod (rootless) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────────────────────┐ │ │
|
||||
│ │ │ Server Container│ │ Worker Container │ │ │
|
||||
│ │ │ UID: 963 (host) │ │ UID: 963 (host) │ │ │
|
||||
│ │ │ Groups: postgres│ │ Groups: postgres,valkey │ │ │
|
||||
│ │ │ valkey │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### Quadlet Configuration
|
||||
|
||||
```ini
|
||||
# Pod configuration (authentik.pod)
|
||||
[Unit]
|
||||
Description=Authentik Authentication Pod
|
||||
|
||||
[Pod]
|
||||
PublishPort=127.0.0.1:9000:9000
|
||||
ShmSize=256m
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
```ini
|
||||
# Container configuration (authentik-server.container)
|
||||
[Unit]
|
||||
Description=Authentik Server Container
|
||||
After=authentik-pod.service
|
||||
Requires=authentik-pod.service
|
||||
|
||||
[Container]
|
||||
ContainerName=authentik-server
|
||||
Image=ghcr.io/goauthentik/server:2025.10
|
||||
Pod=authentik.pod
|
||||
EnvironmentFile=%h/.env
|
||||
User=%i:%i
|
||||
Annotation=run.oci.keep_original_groups=1
|
||||
|
||||
# Volume mounts for sockets
|
||||
Volume=/var/run/postgresql:/var/run/postgresql:Z
|
||||
Volume=/var/run/valkey:/var/run/valkey:Z
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
### User Management Strategy
|
||||
|
||||
```yaml
|
||||
# Ansible implementation
|
||||
- name: Create service user
|
||||
user:
|
||||
name: authentik
|
||||
system: true
|
||||
home: /opt/authentik
|
||||
create_home: true
|
||||
|
||||
- name: Add to infrastructure groups
|
||||
user:
|
||||
name: authentik
|
||||
groups: [postgres, valkey]
|
||||
append: true
|
||||
|
||||
- name: Enable lingering (services persist)
|
||||
command: loginctl enable-linger authentik
|
||||
```
|
||||
|
||||
### Consequences
|
||||
|
||||
#### Positive
|
||||
|
||||
- **Security**: Eliminated privileged daemon attack surface
|
||||
- **Integration**: Seamless systemd integration for management
|
||||
- **Performance**: Lower overhead than daemon-based solutions
|
||||
- **Reliability**: systemd's proven service management
|
||||
- **Monitoring**: Standard systemd monitoring and logging
|
||||
|
||||
#### Negative
|
||||
|
||||
- **Learning Curve**: Different from Docker Compose workflows
|
||||
- **Tooling**: Ecosystem less mature than Docker
|
||||
- **Documentation**: Fewer online resources and examples
|
||||
|
||||
#### Mitigation Strategies
|
||||
|
||||
- **Documentation**: Comprehensive internal documentation
|
||||
- **Training**: Team training on Podman/systemd workflows
|
||||
- **Tooling**: Helper scripts for common operations
|
||||
|
||||
### Technical Implementation
|
||||
|
||||
```bash
|
||||
# Container management (as service user)
|
||||
systemctl --user status authentik-pod
|
||||
systemctl --user restart authentik-server
|
||||
podman ps
|
||||
podman logs authentik-server
|
||||
|
||||
# Resource monitoring
|
||||
systemctl --user show authentik-server --property=MemoryCurrent
|
||||
journalctl --user -u authentik-server -f
|
||||
```
|
||||
|
||||
### Alternatives Considered
|
||||
|
||||
1. **Docker + Docker Compose**: Rejected due to security concerns (privileged daemon)
|
||||
2. **Kubernetes**: Rejected as overkill for single-node deployment
|
||||
3. **Nomad**: Rejected to maintain consistency with systemd ecosystem
|
||||
|
||||
---
|
||||
|
||||
## ADR-004: Forward Authentication Security Model
|
||||
|
||||
**Status**: ✅ Accepted
|
||||
**Date**: December 2025
|
||||
**Deciders**: Infrastructure Team
|
||||
**Technical Story**: Centralized authentication and authorization for multiple services without modifying existing applications.
|
||||
|
||||
### Context
|
||||
|
||||
Authentication strategies for multiple services:
|
||||
|
||||
1. **Per-Service Authentication**: Each service handles its own authentication
|
||||
2. **Shared Database**: Services share authentication database
|
||||
3. **Forward Authentication**: Reverse proxy handles authentication
|
||||
4. **OAuth2/OIDC Integration**: Services implement OAuth2 clients
|
||||
|
||||
### Decision
|
||||
|
||||
We will use **forward authentication** with Caddy reverse proxy and Authentik authentication server as the primary authentication model.
|
||||
|
||||
### Rationale
|
||||
|
||||
#### Security Benefits
|
||||
|
||||
- **Single Point of Control**: Centralized authentication policy
|
||||
- **Zero Application Changes**: Protect existing services without modification
|
||||
- **Consistent Security**: Same security model across all services
|
||||
- **Session Management**: Centralized session handling and timeouts
|
||||
- **Multi-Factor Authentication**: MFA applied consistently across services
|
||||
|
||||
#### Operational Advantages
|
||||
|
||||
- **Simplified Deployment**: No per-service authentication setup
|
||||
- **Audit Trail**: Centralized authentication logging
|
||||
- **Policy Management**: Single place to manage access policies
|
||||
- **User Management**: One system for all user administration
|
||||
- **Service Independence**: Services focus on business logic
|
||||
|
||||
#### Integration Benefits
|
||||
|
||||
- **Transparent to Applications**: Services receive authenticated requests
|
||||
- **Header-Based Identity**: Simple identity propagation
|
||||
```http
|
||||
Remote-User: john.doe
|
||||
Remote-Name: John Doe
|
||||
Remote-Email: john.doe@company.com
|
||||
Remote-Groups: admins,developers
|
||||
```
|
||||
- **Gradual Migration**: Can protect services incrementally
|
||||
- **Fallback Support**: Can coexist with service-native authentication
|
||||
|
||||
### Implementation Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ User │ │ Caddy │ │ Authentik │ │ Service │
|
||||
│ │ │ (Proxy) │ │ (Auth) │ │ (Backend) │
|
||||
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
|
||||
│ │ │ │
|
||||
│ GET /dashboard │ │ │
|
||||
│─────────────────▶│ │ │
|
||||
│ │ │ │
|
||||
│ │ Forward Auth │ │
|
||||
│ │─────────────────▶│ │
|
||||
│ │ │ │
|
||||
│ │ 401 Unauthorized │ │
|
||||
│ │◀─────────────────│ │
|
||||
│ │ │ │
|
||||
│ 302 → /auth/login│ │ │
|
||||
│◀─────────────────│ │ │
|
||||
│ │ │ │
|
||||
│ Login form │ │ │
|
||||
│─────────────────▶│─────────────────▶│ │
|
||||
│ │ │ │
|
||||
│ Credentials │ │ │
|
||||
│─────────────────▶│─────────────────▶│ │
|
||||
│ │ │ │
|
||||
│ Set-Cookie │ │ │
|
||||
│◀─────────────────│◀─────────────────│ │
|
||||
│ │ │ │
|
||||
│ GET /dashboard │ │ │
|
||||
│─────────────────▶│ │ │
|
||||
│ │ │ │
|
||||
│ │ Forward Auth │ │
|
||||
│ │─────────────────▶│ │
|
||||
│ │ │ │
|
||||
│ │ 200 + Headers │ │
|
||||
│ │◀─────────────────│ │
|
||||
│ │ │ │
|
||||
│ │ GET /dashboard + Auth Headers │
|
||||
│ │─────────────────────────────────────▶│
|
||||
│ │ │
|
||||
│ │ Dashboard Content │
|
||||
│ │◀─────────────────────────────────────│
|
||||
│ │ │
|
||||
│ Dashboard │ │
|
||||
│◀─────────────────│ │
|
||||
```
|
||||
|
||||
### Caddy Configuration
|
||||
|
||||
```caddyfile
|
||||
# Service protection template
|
||||
dashboard.jnss.me {
|
||||
# Forward authentication to Authentik
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
# Backend service (receives authenticated requests)
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
### Service Integration
|
||||
|
||||
Services receive authentication information via HTTP headers:
|
||||
|
||||
```python
|
||||
# Example service code (Python Flask)
|
||||
@app.route('/dashboard')
|
||||
def dashboard():
|
||||
username = request.headers.get('Remote-User')
|
||||
name = request.headers.get('Remote-Name')
|
||||
email = request.headers.get('Remote-Email')
|
||||
groups = request.headers.get('Remote-Groups', '').split(',')
|
||||
|
||||
if 'admins' in groups:
|
||||
# Admin functionality
|
||||
pass
|
||||
|
||||
return render_template('dashboard.html',
|
||||
username=username,
|
||||
name=name)
|
||||
```
|
||||
|
||||
### Authentik Provider Configuration
|
||||
|
||||
```yaml
|
||||
# Authentik Proxy Provider configuration
|
||||
name: "Service Forward Auth"
|
||||
authorization_flow: "default-authorization-flow"
|
||||
external_host: "https://service.jnss.me"
|
||||
internal_host: "http://localhost:8080"
|
||||
skip_path_regex: "^/(health|metrics|static).*"
|
||||
```
|
||||
|
||||
### Authorization Policies
|
||||
|
||||
```yaml
|
||||
# Example authorization policy in Authentik
|
||||
policy_bindings:
|
||||
- policy: "group_admins_only"
|
||||
target: "service_dashboard"
|
||||
order: 0
|
||||
|
||||
- policy: "deny_external_ips"
|
||||
target: "admin_endpoints"
|
||||
order: 1
|
||||
```
|
||||
|
||||
### Consequences
|
||||
|
||||
#### Positive
|
||||
|
||||
- **Security**: Consistent, centralized authentication and authorization
|
||||
- **Simplicity**: No application changes required for protection
|
||||
- **Flexibility**: Fine-grained access control through Authentik policies
|
||||
- **Auditability**: Centralized authentication logging
|
||||
- **User Experience**: Single sign-on across all services
|
||||
|
||||
#### Negative
|
||||
|
||||
- **Single Point of Failure**: Authentication system failure affects all services
|
||||
- **Performance**: Additional hop for authentication checks
|
||||
- **Complexity**: Additional component in the request path
|
||||
|
||||
#### Mitigation Strategies
|
||||
|
||||
- **High Availability**: Robust deployment and monitoring of auth components
|
||||
- **Caching**: Session caching to reduce authentication overhead
|
||||
- **Fallback**: Emergency bypass procedures for critical services
|
||||
- **Monitoring**: Comprehensive monitoring of authentication flow
|
||||
|
||||
### Security Considerations
|
||||
|
||||
#### Session Security
|
||||
|
||||
```yaml
|
||||
# Authentik session settings
|
||||
session_cookie_age: 3600 # 1 hour
|
||||
session_cookie_secure: true
|
||||
session_cookie_samesite: "Strict"
|
||||
session_remember_me: false
|
||||
```
|
||||
|
||||
#### Access Control
|
||||
|
||||
- **Group-Based Authorization**: Users assigned to groups, groups to applications
|
||||
- **Time-Based Access**: Temporary access grants
|
||||
- **IP-Based Restrictions**: Geographic or network-based access control
|
||||
- **MFA Requirements**: Multi-factor authentication for sensitive services
|
||||
|
||||
#### Audit Logging
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-12-11T17:52:31Z",
|
||||
"event": "authentication_success",
|
||||
"user": "john.doe",
|
||||
"service": "dashboard.jnss.me",
|
||||
"ip": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0..."
|
||||
}
|
||||
```
|
||||
|
||||
### Alternative Models Supported
|
||||
|
||||
While forward auth is primary, we also support:
|
||||
|
||||
1. **OAuth2/OIDC Integration**: For applications that can implement OAuth2
|
||||
2. **API Key Authentication**: For service-to-service communication
|
||||
3. **Service-Native Auth**: For legacy applications that cannot be easily protected
|
||||
|
||||
### Implementation Examples
|
||||
|
||||
#### Protecting a Static Site
|
||||
|
||||
```caddyfile
|
||||
docs.jnss.me {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Groups
|
||||
}
|
||||
|
||||
root * /var/www/docs
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
#### Protecting an API
|
||||
|
||||
```caddyfile
|
||||
api.jnss.me {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
reverse_proxy localhost:3000
|
||||
}
|
||||
```
|
||||
|
||||
#### Public Endpoints with Selective Protection
|
||||
|
||||
```caddyfile
|
||||
app.jnss.me {
|
||||
# Public endpoints (no auth)
|
||||
handle /health {
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
|
||||
handle /public/* {
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
|
||||
# Protected endpoints
|
||||
handle {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Groups
|
||||
}
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Alternatives Considered
|
||||
|
||||
1. **OAuth2 Only**: Rejected due to application modification requirements
|
||||
2. **Shared Database**: Rejected due to tight coupling between services
|
||||
3. **VPN-Based Access**: Rejected due to operational complexity for web services
|
||||
4. **Per-Service Authentication**: Rejected due to management overhead
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
These architecture decisions collectively create a robust, secure, and performant infrastructure:
|
||||
|
||||
- **Native Services** provide optimal performance and security
|
||||
- **Unix Sockets** eliminate network attack vectors
|
||||
- **Podman + systemd** delivers secure container orchestration
|
||||
- **Forward Authentication** enables centralized security without application changes
|
||||
|
||||
The combination results in an infrastructure that prioritizes security and performance while maintaining operational simplicity and reliability.
|
||||
|
||||
## References
|
||||
|
||||
- [Service Integration Guide](service-integration-guide.md)
|
||||
- [Authentik Deployment Guide](authentik-deployment-guide.md)
|
||||
- [Security Hardening](security-hardening.md)
|
||||
- [Authentik Role Documentation](../roles/authentik/README.md)
|
||||
949
docs/authentication-architecture.md
Normal file
949
docs/authentication-architecture.md
Normal file
@@ -0,0 +1,949 @@
|
||||
# Authentication Architecture
|
||||
|
||||
This document describes the comprehensive authentication and authorization strategy implemented in rick-infra, focusing on centralized SSO with Authentik and forward authentication integration.
|
||||
|
||||
## Overview
|
||||
|
||||
Rick-infra implements a modern, security-focused authentication architecture that provides:
|
||||
|
||||
- **Centralized SSO**: Single sign-on across all services via Authentik
|
||||
- **Forward Authentication**: Transparent protection without application changes
|
||||
- **Zero Network Exposure**: Database and cache communication via Unix sockets
|
||||
- **Granular Authorization**: Fine-grained access control through groups and policies
|
||||
- **Standards Compliance**: OAuth2, OIDC, SAML support for enterprise integration
|
||||
|
||||
## Architecture Components
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ rick-infra Authentication Architecture │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
||||
│ │ Users │ │ Caddy │ │ Authentik │ │
|
||||
│ │ │───▶│ (Proxy) │───▶│ (Auth Server) │ │
|
||||
│ │ Web Browser │ │ Forward Auth│ │ OAuth2/OIDC/SAML │ │
|
||||
│ │ Mobile Apps │ │ TLS Term │ │ User Management │ │
|
||||
│ │ API Clients │ │ Load Balance│ │ Policy Engine │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Protected Services │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Gitea │ │ Gallery │ │ Custom Services │ │ │
|
||||
│ │ │ (Git Repos) │ │ (Media) │ │ (Applications) │ │ │
|
||||
│ │ │ Receives: │ │ Receives: │ │ Receives: │ │ │
|
||||
│ │ │ Remote-User │ │ Remote-User │ │ Remote-User │ │ │
|
||||
│ │ │ Remote-Email│ │ Remote-Name │ │ Remote-Groups │ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Infrastructure (Unix Sockets) │ │
|
||||
│ │ PostgreSQL Database • Valkey Cache • systemd Services │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### Standard User Authentication Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as User
|
||||
participant C as Caddy
|
||||
participant A as Authentik
|
||||
participant S as Protected Service
|
||||
|
||||
U->>C: GET /dashboard
|
||||
C->>A: Forward Auth Request
|
||||
A->>C: 401 Unauthorized
|
||||
C->>U: 302 Redirect to Login
|
||||
|
||||
U->>A: Login Form Request
|
||||
A->>U: Login Form
|
||||
U->>A: Credentials
|
||||
A->>U: Set Session Cookie
|
||||
|
||||
U->>C: GET /dashboard (with cookie)
|
||||
C->>A: Forward Auth Request (with cookie)
|
||||
A->>C: 200 OK + User Headers
|
||||
C->>S: GET /dashboard + Headers
|
||||
S->>C: Dashboard Content
|
||||
C->>U: Dashboard Content
|
||||
```
|
||||
|
||||
### API Authentication Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant API as API Client
|
||||
participant A as Authentik
|
||||
participant C as Caddy
|
||||
participant S as API Service
|
||||
|
||||
API->>A: POST /application/o/token/
|
||||
Note over API,A: OAuth2 Client Credentials
|
||||
A->>API: Access Token
|
||||
|
||||
API->>C: GET /api/data
|
||||
Note over API,C: Authorization: Bearer {token}
|
||||
C->>A: Token Validation
|
||||
A->>C: Token Valid + Claims
|
||||
C->>S: GET /api/data + Headers
|
||||
S->>API: API Response
|
||||
```
|
||||
|
||||
## Service Integration Patterns
|
||||
|
||||
### Pattern 1: Forward Authentication (Recommended)
|
||||
|
||||
**Use Case**: Existing HTTP services that don't need to handle authentication
|
||||
|
||||
**Benefits**:
|
||||
- No application code changes required
|
||||
- Consistent authentication across all services
|
||||
- Service receives authenticated user information via headers
|
||||
- Centralized session management
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```caddyfile
|
||||
# Caddy configuration
|
||||
myservice.jnss.me {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
**Service Code Example** (Python Flask):
|
||||
```python
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/dashboard')
|
||||
def dashboard():
|
||||
# Authentication handled by Caddy/Authentik
|
||||
username = request.headers.get('Remote-User')
|
||||
user_name = request.headers.get('Remote-Name')
|
||||
user_email = request.headers.get('Remote-Email')
|
||||
user_groups = request.headers.get('Remote-Groups', '').split(',')
|
||||
|
||||
# Authorization based on groups
|
||||
if 'admins' not in user_groups:
|
||||
return "Access denied", 403
|
||||
|
||||
return f"Welcome {user_name} ({username})"
|
||||
```
|
||||
|
||||
### Pattern 2: OAuth2/OIDC Integration
|
||||
|
||||
**Use Case**: Applications that can implement OAuth2 client functionality
|
||||
|
||||
**Benefits**:
|
||||
- More control over authentication flow
|
||||
- Better integration with application user models
|
||||
- Support for API access tokens
|
||||
- Offline access via refresh tokens
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```python
|
||||
# Example OAuth2 configuration
|
||||
OAUTH2_CONFIG = {
|
||||
'client_id': 'your-client-id',
|
||||
'client_secret': 'your-client-secret',
|
||||
'server_metadata_url': 'https://auth.jnss.me/application/o/your-app/.well-known/openid_configuration',
|
||||
'client_kwargs': {
|
||||
'scope': 'openid email profile groups'
|
||||
}
|
||||
}
|
||||
|
||||
# OAuth2 flow implementation
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
|
||||
oauth = OAuth(app)
|
||||
oauth.register('authentik', **OAUTH2_CONFIG)
|
||||
|
||||
@app.route('/login')
|
||||
def login():
|
||||
redirect_uri = url_for('callback', _external=True)
|
||||
return oauth.authentik.authorize_redirect(redirect_uri)
|
||||
|
||||
@app.route('/callback')
|
||||
def callback():
|
||||
token = oauth.authentik.authorize_access_token()
|
||||
user_info = oauth.authentik.parse_id_token(token)
|
||||
# Store user info in session
|
||||
session['user'] = user_info
|
||||
return redirect('/dashboard')
|
||||
```
|
||||
|
||||
### Pattern 3: API-Only Authentication
|
||||
|
||||
**Use Case**: REST APIs, mobile app backends, microservices
|
||||
|
||||
**Benefits**:
|
||||
- Stateless authentication via tokens
|
||||
- Machine-to-machine authentication support
|
||||
- Fine-grained API scope control
|
||||
- Easy integration with mobile/SPA applications
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```yaml
|
||||
# Authentik Provider Configuration
|
||||
name: "API Provider"
|
||||
authorization_flow: "default-provider-authorization-explicit-consent"
|
||||
client_type: "confidential"
|
||||
client_id: "api-client-id"
|
||||
redirect_uris: ["http://localhost:8080/callback"]
|
||||
```
|
||||
|
||||
```python
|
||||
# API service with token validation
|
||||
import requests
|
||||
from flask import Flask, request, jsonify
|
||||
|
||||
def validate_token(token):
|
||||
"""Validate token with Authentik introspection endpoint"""
|
||||
response = requests.post(
|
||||
'https://auth.jnss.me/application/o/introspect/',
|
||||
headers={'Authorization': f'Bearer {token}'},
|
||||
data={'token': token}
|
||||
)
|
||||
return response.json() if response.status_code == 200 else None
|
||||
|
||||
@app.route('/api/data')
|
||||
def api_data():
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if not auth_header or not auth_header.startswith('Bearer '):
|
||||
return jsonify({'error': 'Missing or invalid authorization header'}), 401
|
||||
|
||||
token = auth_header.split(' ')[1]
|
||||
token_info = validate_token(token)
|
||||
|
||||
if not token_info or not token_info.get('active'):
|
||||
return jsonify({'error': 'Invalid or expired token'}), 401
|
||||
|
||||
# Extract user information from token
|
||||
username = token_info.get('username')
|
||||
scope = token_info.get('scope', '').split()
|
||||
|
||||
if 'read:data' not in scope:
|
||||
return jsonify({'error': 'Insufficient permissions'}), 403
|
||||
|
||||
return jsonify({'message': f'Hello {username}', 'data': 'sensitive-data'})
|
||||
```
|
||||
|
||||
### Pattern 4: Service-to-Service Authentication
|
||||
|
||||
**Use Case**: Backend services communicating with each other
|
||||
|
||||
**Benefits**:
|
||||
- Machine-to-machine authentication
|
||||
- Service identity and authorization
|
||||
- API rate limiting and monitoring
|
||||
- Secure inter-service communication
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```yaml
|
||||
# Authentik Service Account Configuration
|
||||
name: "Backend Service Account"
|
||||
username: "backend-service"
|
||||
groups: ["services", "backend-access"]
|
||||
token_validity: "8760h" # 1 year
|
||||
```
|
||||
|
||||
```python
|
||||
# Service-to-service authentication
|
||||
import os
|
||||
import requests
|
||||
|
||||
class ServiceClient:
|
||||
def __init__(self):
|
||||
self.client_id = os.getenv('SERVICE_CLIENT_ID')
|
||||
self.client_secret = os.getenv('SERVICE_CLIENT_SECRET')
|
||||
self.token_url = 'https://auth.jnss.me/application/o/token/'
|
||||
self.access_token = None
|
||||
|
||||
def get_access_token(self):
|
||||
if not self.access_token:
|
||||
response = requests.post(self.token_url, data={
|
||||
'grant_type': 'client_credentials',
|
||||
'client_id': self.client_id,
|
||||
'client_secret': self.client_secret,
|
||||
'scope': 'service:read service:write'
|
||||
})
|
||||
self.access_token = response.json()['access_token']
|
||||
return self.access_token
|
||||
|
||||
def call_service(self, endpoint):
|
||||
token = self.get_access_token()
|
||||
response = requests.get(
|
||||
f'https://api.jnss.me{endpoint}',
|
||||
headers={'Authorization': f'Bearer {token}'}
|
||||
)
|
||||
return response.json()
|
||||
```
|
||||
|
||||
## User Management Strategy
|
||||
|
||||
### User Lifecycle Management
|
||||
|
||||
#### User Creation and Onboarding
|
||||
|
||||
```yaml
|
||||
# Authentik User Configuration
|
||||
email: "user@company.com"
|
||||
username: "user.name"
|
||||
name: "User Full Name"
|
||||
is_active: true
|
||||
groups: ["employees", "developers"] # Assigned based on role
|
||||
attributes:
|
||||
department: "Engineering"
|
||||
team: "Backend"
|
||||
hire_date: "2024-01-15"
|
||||
```
|
||||
|
||||
#### Group-Based Authorization
|
||||
|
||||
```yaml
|
||||
# Group Structure
|
||||
groups:
|
||||
- name: "employees"
|
||||
description: "All company employees"
|
||||
permissions: ["basic_access"]
|
||||
|
||||
- name: "developers"
|
||||
description: "Software development team"
|
||||
permissions: ["git_access", "deploy_staging"]
|
||||
parent_group: "employees"
|
||||
|
||||
- name: "admins"
|
||||
description: "System administrators"
|
||||
permissions: ["admin_access", "deploy_production"]
|
||||
parent_group: "employees"
|
||||
|
||||
- name: "contractors"
|
||||
description: "External contractors"
|
||||
permissions: ["limited_access"]
|
||||
```
|
||||
|
||||
#### Access Control Policies
|
||||
|
||||
```yaml
|
||||
# Authentik Policy Configuration
|
||||
policies:
|
||||
- name: "Business Hours Access"
|
||||
type: "time"
|
||||
parameters:
|
||||
start_time: "08:00"
|
||||
end_time: "18:00"
|
||||
days: ["monday", "tuesday", "wednesday", "thursday", "friday"]
|
||||
|
||||
- name: "Admin IP Restriction"
|
||||
type: "source_ip"
|
||||
parameters:
|
||||
cidr: "10.0.0.0/8"
|
||||
|
||||
- name: "MFA Required for Admin"
|
||||
type: "group_membership"
|
||||
parameters:
|
||||
group: "admins"
|
||||
require_mfa: true
|
||||
```
|
||||
|
||||
### Multi-Factor Authentication
|
||||
|
||||
#### MFA Configuration
|
||||
|
||||
```yaml
|
||||
# Authentik MFA Settings
|
||||
mfa_policies:
|
||||
- name: "Admin MFA Requirement"
|
||||
bound_to: "group:admins"
|
||||
authenticators: ["totp", "webauthn"]
|
||||
enforce: true
|
||||
|
||||
- name: "Developer Optional MFA"
|
||||
bound_to: "group:developers"
|
||||
authenticators: ["totp", "sms"]
|
||||
enforce: false
|
||||
```
|
||||
|
||||
#### Supported MFA Methods
|
||||
|
||||
1. **TOTP (Time-based One-Time Passwords)**
|
||||
- Google Authenticator, Authy, 1Password
|
||||
- RFC 6238 compliant
|
||||
- Configurable validity period
|
||||
|
||||
2. **WebAuthn/FIDO2**
|
||||
- Hardware security keys (YubiKey, etc.)
|
||||
- Biometric authentication
|
||||
- Passwordless authentication support
|
||||
|
||||
3. **SMS Authentication**
|
||||
- SMS-based verification codes
|
||||
- International phone number support
|
||||
- Rate limiting and abuse protection
|
||||
|
||||
4. **Email Authentication**
|
||||
- Email-based verification codes
|
||||
- Fallback authentication method
|
||||
- Configurable code validity
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Session Management
|
||||
|
||||
#### Session Configuration
|
||||
|
||||
```yaml
|
||||
# Authentik Session Settings
|
||||
session_settings:
|
||||
cookie_age: 3600 # 1 hour
|
||||
cookie_secure: true # HTTPS only
|
||||
cookie_samesite: "Strict"
|
||||
remember_me_duration: 86400 # 24 hours
|
||||
concurrent_sessions: 3 # Max simultaneous sessions
|
||||
```
|
||||
|
||||
#### Session Security Features
|
||||
|
||||
- **Session Fixation Protection**: New session ID on authentication
|
||||
- **Concurrent Session Control**: Limit simultaneous sessions per user
|
||||
- **Session Timeout**: Automatic logout after inactivity
|
||||
- **Secure Cookies**: HTTP-only, secure, SameSite attributes
|
||||
- **Session Invalidation**: Logout invalidates all sessions
|
||||
|
||||
### Authorization Security
|
||||
|
||||
#### Policy-Based Access Control
|
||||
|
||||
```yaml
|
||||
# Example Authorization Policy
|
||||
policy_bindings:
|
||||
- application: "admin_dashboard"
|
||||
policies:
|
||||
- "group_membership:admins"
|
||||
- "mfa_required"
|
||||
- "business_hours_access"
|
||||
- "ip_whitelist:office"
|
||||
order: 0
|
||||
|
||||
- application: "developer_tools"
|
||||
policies:
|
||||
- "group_membership:developers"
|
||||
- "rate_limiting:api_calls"
|
||||
order: 1
|
||||
```
|
||||
|
||||
#### Security Headers
|
||||
|
||||
```http
|
||||
# Headers passed to protected services
|
||||
Remote-User: john.doe
|
||||
Remote-Name: John Doe
|
||||
Remote-Email: john.doe@company.com
|
||||
Remote-Groups: employees,developers
|
||||
Remote-Authenticated: true
|
||||
Remote-Auth-Time: 2025-12-11T17:52:31Z
|
||||
Remote-Session-ID: sess_abc123def456
|
||||
```
|
||||
|
||||
### Audit and Logging
|
||||
|
||||
#### Authentication Events
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-12-11T17:52:31Z",
|
||||
"event_type": "authentication_success",
|
||||
"user_id": "user123",
|
||||
"username": "john.doe",
|
||||
"source_ip": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
|
||||
"application": "dashboard.jnss.me",
|
||||
"auth_method": "password+totp",
|
||||
"session_id": "sess_abc123def456"
|
||||
}
|
||||
```
|
||||
|
||||
#### Authorization Events
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-12-11T17:52:45Z",
|
||||
"event_type": "authorization_denied",
|
||||
"user_id": "user456",
|
||||
"username": "contractor.user",
|
||||
"source_ip": "203.0.113.100",
|
||||
"application": "admin_dashboard",
|
||||
"reason": "insufficient_privileges",
|
||||
"required_groups": ["admins"],
|
||||
"user_groups": ["contractors"]
|
||||
}
|
||||
```
|
||||
|
||||
#### System Events
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-12-11T17:53:00Z",
|
||||
"event_type": "policy_violation",
|
||||
"user_id": "user789",
|
||||
"username": "admin.user",
|
||||
"source_ip": "198.51.100.50",
|
||||
"policy": "ip_whitelist:office",
|
||||
"violation": "access_from_unauthorized_ip",
|
||||
"action": "access_denied"
|
||||
}
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Example 1: Protecting Gitea with Groups
|
||||
|
||||
**Objective**: Protect Git repository access with role-based permissions
|
||||
|
||||
```caddyfile
|
||||
# Caddy configuration for Gitea
|
||||
git.jnss.me {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Groups
|
||||
}
|
||||
|
||||
reverse_proxy localhost:3000
|
||||
}
|
||||
```
|
||||
|
||||
**Gitea Configuration**:
|
||||
```ini
|
||||
# app.ini - Gitea configuration
|
||||
[auth]
|
||||
REVERSE_PROXY_AUTHENTICATION = true
|
||||
REVERSE_PROXY_AUTO_REGISTRATION = true
|
||||
|
||||
[auth.reverse_proxy]
|
||||
USER_HEADER = Remote-User
|
||||
EMAIL_HEADER = Remote-Email
|
||||
FULL_NAME_HEADER = Remote-Name
|
||||
```
|
||||
|
||||
**Group Mapping**:
|
||||
```yaml
|
||||
# Authentik group configuration for Gitea
|
||||
groups:
|
||||
- name: "git_users"
|
||||
description: "Git repository users"
|
||||
applications: ["gitea"]
|
||||
|
||||
- name: "git_admins"
|
||||
description: "Git administrators"
|
||||
applications: ["gitea"]
|
||||
permissions: ["admin"]
|
||||
```
|
||||
|
||||
### Example 2: API Service with Scoped Access
|
||||
|
||||
**Objective**: REST API with OAuth2 authentication and scoped permissions
|
||||
|
||||
```caddyfile
|
||||
# Caddy configuration for API
|
||||
api.jnss.me {
|
||||
# No forward auth - API handles OAuth2 directly
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
**API Service Configuration**:
|
||||
```python
|
||||
from flask import Flask, request, jsonify
|
||||
import requests
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def verify_token_scope(token, required_scope):
|
||||
"""Verify token has required scope"""
|
||||
response = requests.post(
|
||||
'https://auth.jnss.me/application/o/introspect/',
|
||||
data={
|
||||
'token': token,
|
||||
'client_id': 'api-client-id',
|
||||
'client_secret': 'api-client-secret'
|
||||
}
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
return False
|
||||
|
||||
token_data = response.json()
|
||||
if not token_data.get('active'):
|
||||
return False
|
||||
|
||||
scopes = token_data.get('scope', '').split()
|
||||
return required_scope in scopes
|
||||
|
||||
@app.route('/api/public')
|
||||
def public_endpoint():
|
||||
"""Public endpoint - no authentication required"""
|
||||
return jsonify({'message': 'This is public data'})
|
||||
|
||||
@app.route('/api/user/profile')
|
||||
def user_profile():
|
||||
"""User profile endpoint - requires user:read scope"""
|
||||
auth_header = request.headers.get('Authorization', '')
|
||||
|
||||
if not auth_header.startswith('Bearer '):
|
||||
return jsonify({'error': 'Missing authorization header'}), 401
|
||||
|
||||
token = auth_header[7:] # Remove 'Bearer ' prefix
|
||||
|
||||
if not verify_token_scope(token, 'user:read'):
|
||||
return jsonify({'error': 'Insufficient permissions'}), 403
|
||||
|
||||
return jsonify({'message': 'User profile data'})
|
||||
|
||||
@app.route('/api/admin/users')
|
||||
def admin_users():
|
||||
"""Admin endpoint - requires admin:read scope"""
|
||||
auth_header = request.headers.get('Authorization', '')
|
||||
|
||||
if not auth_header.startswith('Bearer '):
|
||||
return jsonify({'error': 'Missing authorization header'}), 401
|
||||
|
||||
token = auth_header[7:]
|
||||
|
||||
if not verify_token_scope(token, 'admin:read'):
|
||||
return jsonify({'error': 'Admin privileges required'}), 403
|
||||
|
||||
return jsonify({'message': 'Admin user data'})
|
||||
```
|
||||
|
||||
**OAuth2 Scopes Configuration**:
|
||||
```yaml
|
||||
# Authentik OAuth2 Provider scopes
|
||||
scopes:
|
||||
- name: "user:read"
|
||||
description: "Read user profile information"
|
||||
|
||||
- name: "user:write"
|
||||
description: "Modify user profile information"
|
||||
|
||||
- name: "admin:read"
|
||||
description: "Read administrative data"
|
||||
|
||||
- name: "admin:write"
|
||||
description: "Modify administrative settings"
|
||||
```
|
||||
|
||||
### Example 3: Static Site with Selective Protection
|
||||
|
||||
**Objective**: Protect portions of a static site while keeping some content public
|
||||
|
||||
```caddyfile
|
||||
# Caddy configuration for mixed static/protected site
|
||||
docs.jnss.me {
|
||||
# Public documentation - no authentication
|
||||
handle /public/* {
|
||||
root * /var/www/docs
|
||||
file_server
|
||||
}
|
||||
|
||||
# Public API documentation
|
||||
handle /api-docs {
|
||||
root * /var/www/docs
|
||||
file_server
|
||||
}
|
||||
|
||||
# Protected internal documentation
|
||||
handle /internal/* {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-Groups
|
||||
}
|
||||
|
||||
# Only employees can access internal docs
|
||||
@not_employee {
|
||||
not header Remote-Groups "*employees*"
|
||||
}
|
||||
respond @not_employee "Access denied" 403
|
||||
|
||||
root * /var/www/docs
|
||||
file_server
|
||||
}
|
||||
|
||||
# Admin documentation - requires admin group
|
||||
handle /admin/* {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-Groups
|
||||
}
|
||||
|
||||
# Only admins can access admin docs
|
||||
@not_admin {
|
||||
not header Remote-Groups "*admins*"
|
||||
}
|
||||
respond @not_admin "Admin access required" 403
|
||||
|
||||
root * /var/www/docs
|
||||
file_server
|
||||
}
|
||||
|
||||
# Default: Require authentication for everything else
|
||||
handle {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Groups
|
||||
}
|
||||
|
||||
root * /var/www/docs
|
||||
file_server
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Authentication Performance
|
||||
|
||||
#### Caching Strategy
|
||||
|
||||
- **Session Caching**: Redis-backed session storage for fast lookup
|
||||
- **Token Caching**: Cache valid tokens to reduce introspection calls
|
||||
- **User Information Caching**: Cache user attributes and group memberships
|
||||
- **Policy Evaluation Caching**: Cache authorization decision results
|
||||
|
||||
#### Performance Optimization
|
||||
|
||||
```yaml
|
||||
# Authentik Performance Settings
|
||||
cache_settings:
|
||||
default_timeout: 300 # 5 minutes
|
||||
session_timeout: 1800 # 30 minutes
|
||||
token_introspection_cache: 60 # 1 minute
|
||||
user_info_cache: 600 # 10 minutes
|
||||
```
|
||||
|
||||
#### Load Balancing Considerations
|
||||
|
||||
- **Session Affinity**: Not required - sessions stored in shared cache
|
||||
- **Health Checks**: Monitor authentik container health
|
||||
- **Failover**: Graceful degradation strategies for auth service outages
|
||||
- **Rate Limiting**: Protect against authentication abuse
|
||||
|
||||
### Database Performance
|
||||
|
||||
#### Connection Optimization
|
||||
|
||||
```yaml
|
||||
# PostgreSQL connection settings for Authentik
|
||||
database_settings:
|
||||
max_connections: 100
|
||||
connection_timeout: 30
|
||||
idle_timeout: 300
|
||||
query_timeout: 60
|
||||
connection_pool_size: 20
|
||||
```
|
||||
|
||||
#### Index Optimization
|
||||
|
||||
```sql
|
||||
-- Recommended PostgreSQL indexes for Authentik performance
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_authentik_core_user_email ON authentik_core_user(email);
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_authentik_core_token_key ON authentik_core_token(key);
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_authentik_sessions_expire_date ON django_session(expire_date);
|
||||
```
|
||||
|
||||
## Troubleshooting Guide
|
||||
|
||||
### Common Authentication Issues
|
||||
|
||||
#### Issue: Users Cannot Access Protected Services
|
||||
|
||||
**Symptoms**:
|
||||
- 401 Unauthorized errors
|
||||
- Redirect loops to login page
|
||||
- "Access denied" messages
|
||||
|
||||
**Diagnostic Steps**:
|
||||
```bash
|
||||
# Check authentik service status
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status authentik-server"
|
||||
|
||||
# Test authentik HTTP endpoint
|
||||
curl -I https://auth.jnss.me/
|
||||
|
||||
# Check forward auth endpoint
|
||||
curl -I https://auth.jnss.me/outpost.goauthentik.io/auth/caddy
|
||||
|
||||
# Verify Caddy configuration
|
||||
ssh root@your-vps "caddy validate --config /etc/caddy/Caddyfile"
|
||||
```
|
||||
|
||||
#### Issue: Group-Based Authorization Not Working
|
||||
|
||||
**Symptoms**:
|
||||
- Users with correct groups denied access
|
||||
- Group headers not passed to services
|
||||
- Authorization policies not applied
|
||||
|
||||
**Diagnostic Steps**:
|
||||
```bash
|
||||
# Check user group membership
|
||||
curl -H "Authorization: Bearer $TOKEN" https://auth.jnss.me/api/v3/core/users/me/
|
||||
|
||||
# Test header passing
|
||||
curl -H "Cookie: authentik_session=$SESSION" https://auth.jnss.me/outpost.goauthentik.io/auth/caddy -v
|
||||
|
||||
# Verify Caddy header configuration
|
||||
ssh root@your-vps "grep -A5 'copy_headers' /etc/caddy/sites-enabled/*.caddy"
|
||||
```
|
||||
|
||||
#### Issue: OAuth2 Token Validation Failing
|
||||
|
||||
**Symptoms**:
|
||||
- "Invalid token" errors for valid tokens
|
||||
- Token introspection returning false
|
||||
- API calls failing with 401
|
||||
|
||||
**Diagnostic Steps**:
|
||||
```bash
|
||||
# Test token introspection directly
|
||||
curl -X POST https://auth.jnss.me/application/o/introspect/ \
|
||||
-H "Authorization: Bearer $CLIENT_TOKEN" \
|
||||
-d "token=$USER_TOKEN"
|
||||
|
||||
# Check client credentials
|
||||
curl -X POST https://auth.jnss.me/application/o/token/ \
|
||||
-d "grant_type=client_credentials" \
|
||||
-d "client_id=$CLIENT_ID" \
|
||||
-d "client_secret=$CLIENT_SECRET"
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
|
||||
#### Issue: Slow Authentication Response
|
||||
|
||||
**Symptoms**:
|
||||
- Long delays on login
|
||||
- Timeouts during authentication
|
||||
- Poor user experience
|
||||
|
||||
**Diagnostic Steps**:
|
||||
```bash
|
||||
# Check authentik container resources
|
||||
ssh root@your-vps "sudo -u authentik podman stats authentik-server"
|
||||
|
||||
# Monitor database performance
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT * FROM pg_stat_activity;'"
|
||||
|
||||
# Check network latency
|
||||
curl -w "@curl-format.txt" -o /dev/null https://auth.jnss.me/
|
||||
```
|
||||
|
||||
#### Issue: High Database Load
|
||||
|
||||
**Symptoms**:
|
||||
- Slow database queries
|
||||
- High CPU usage on database
|
||||
- Authentication timeouts
|
||||
|
||||
**Solutions**:
|
||||
```sql
|
||||
-- Optimize authentication queries
|
||||
VACUUM ANALYZE authentik_core_user;
|
||||
VACUUM ANALYZE authentik_core_token;
|
||||
VACUUM ANALYZE django_session;
|
||||
|
||||
-- Check for missing indexes
|
||||
SELECT schemaname, tablename, attname, n_distinct, correlation
|
||||
FROM pg_stats
|
||||
WHERE schemaname = 'public'
|
||||
AND tablename LIKE 'authentik_%';
|
||||
```
|
||||
|
||||
## Future Considerations
|
||||
|
||||
### Scalability Planning
|
||||
|
||||
#### Horizontal Scaling
|
||||
|
||||
- **Load Balancer**: Multiple authentik instances behind load balancer
|
||||
- **Database Clustering**: PostgreSQL replication for read scaling
|
||||
- **Cache Clustering**: Valkey cluster for session storage
|
||||
- **Geographic Distribution**: Regional authentik deployments
|
||||
|
||||
#### Performance Monitoring
|
||||
|
||||
```yaml
|
||||
# Monitoring metrics to track
|
||||
metrics:
|
||||
authentication:
|
||||
- login_success_rate
|
||||
- login_response_time
|
||||
- failed_login_attempts
|
||||
- concurrent_sessions
|
||||
|
||||
authorization:
|
||||
- authorization_success_rate
|
||||
- policy_evaluation_time
|
||||
- access_denied_rate
|
||||
|
||||
system:
|
||||
- database_connection_pool_usage
|
||||
- cache_hit_rate
|
||||
- container_memory_usage
|
||||
- response_time_p95
|
||||
```
|
||||
|
||||
### Enterprise Integration
|
||||
|
||||
#### SAML Federation
|
||||
|
||||
```yaml
|
||||
# SAML Provider configuration for enterprise SSO
|
||||
saml_provider:
|
||||
name: "Corporate SAML"
|
||||
acs_url: "https://auth.jnss.me/source/saml/corporate/acs/"
|
||||
issuer: "https://auth.jnss.me"
|
||||
signing_certificate: "{{ saml_signing_cert }}"
|
||||
encryption_certificate: "{{ saml_encryption_cert }}"
|
||||
```
|
||||
|
||||
#### LDAP/Active Directory Integration
|
||||
|
||||
```yaml
|
||||
# LDAP source configuration
|
||||
ldap_source:
|
||||
name: "Corporate LDAP"
|
||||
server_uri: "ldaps://ldap.company.com:636"
|
||||
bind_dn: "CN=authentik,OU=Service Accounts,DC=company,DC=com"
|
||||
bind_password: "{{ ldap_bind_password }}"
|
||||
base_dn: "DC=company,DC=com"
|
||||
user_search: "(&(objectClass=user)(sAMAccountName=%(user)s))"
|
||||
group_search: "(&(objectClass=group)(member=%(user_dn)s))"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This comprehensive authentication architecture provides a robust, scalable, and secure foundation for managing access to all services in the rick-infra environment, with emphasis on security, performance, and operational excellence.
|
||||
|
||||
## References
|
||||
|
||||
- **[Authentik Deployment Guide](authentik-deployment-guide.md)** - Detailed deployment instructions
|
||||
- **[Architecture Decisions](architecture-decisions.md)** - Technical decision rationale
|
||||
- **[Service Integration Guide](service-integration-guide.md)** - Adding new services
|
||||
- **[Security Hardening](security-hardening.md)** - Security implementation details
|
||||
- **[Authentik Role Documentation](../roles/authentik/README.md)** - Technical implementation details
|
||||
642
docs/authentik-deployment-guide.md
Normal file
642
docs/authentik-deployment-guide.md
Normal file
@@ -0,0 +1,642 @@
|
||||
# Authentik Deployment Guide
|
||||
|
||||
A comprehensive guide for deploying Authentik authentication server with native database services and Unix socket IPC in the rick-infra environment.
|
||||
|
||||
## Overview
|
||||
|
||||
This guide covers the complete deployment process for Authentik, a modern authentication and authorization server, integrated with:
|
||||
|
||||
- **Native PostgreSQL** - High-performance database with Unix socket IPC
|
||||
- **Native Valkey** - Redis-compatible cache with Unix socket IPC
|
||||
- **Rootless Podman** - Secure container orchestration via systemd/Quadlet
|
||||
- **Caddy Reverse Proxy** - TLS termination and forward authentication
|
||||
|
||||
## Architecture Summary
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Internet │ │ Caddy Proxy │ │ Authentik Pod │
|
||||
│ │───▶│ auth.jnss.me │───▶│ │
|
||||
│ HTTPS/443 │ │ TLS + Forward │ │ Server + Worker │
|
||||
└─────────────────┘ │ Auth │ │ Containers │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────────────────┼─────────────────┐
|
||||
│ Host Infrastructure │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ ┌─────────────────────────┐ │
|
||||
│ │ PostgreSQL │ │ Valkey │ │
|
||||
│ │ (Native) │ │ (Redis-compatible) │ │
|
||||
│ │ Unix Socket │ │ Unix Socket │ │
|
||||
│ └─────────────┘ └─────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Infrastructure Requirements
|
||||
|
||||
Before deploying Authentik, ensure the following infrastructure services are running:
|
||||
|
||||
```bash
|
||||
# Verify required services are active
|
||||
ssh root@your-vps "systemctl is-active postgresql valkey caddy podman"
|
||||
```
|
||||
|
||||
Expected output: All services should show `active`
|
||||
|
||||
### Required Infrastructure Components
|
||||
|
||||
1. **PostgreSQL Database**
|
||||
- Native systemd service with Unix socket enabled
|
||||
- Socket location: `/var/run/postgresql/.s.PGSQL.5432`
|
||||
|
||||
2. **Valkey Cache Service**
|
||||
- Native systemd service with Unix socket enabled
|
||||
- Socket location: `/var/run/valkey/valkey.sock`
|
||||
|
||||
3. **Podman Container Runtime**
|
||||
- Rootless container support configured
|
||||
- systemd user session support enabled
|
||||
|
||||
4. **Caddy Web Server**
|
||||
- TLS/SSL termination configured
|
||||
- API management enabled for dynamic configuration
|
||||
|
||||
### DNS Configuration
|
||||
|
||||
Ensure DNS records are configured for your authentik domain:
|
||||
|
||||
```bash
|
||||
# Verify DNS resolution
|
||||
dig +short auth.jnss.me
|
||||
# Should return your VPS IP address
|
||||
```
|
||||
|
||||
### Network Requirements
|
||||
|
||||
- **Port 80/443**: Open for HTTP/HTTPS traffic
|
||||
- **Internal communications**: Unix sockets (no additional ports required)
|
||||
|
||||
## Vault Variables Setup
|
||||
|
||||
### Required Vault Variables
|
||||
|
||||
Create or update `host_vars/arch-vps/vault.yml` with the following encrypted variables:
|
||||
|
||||
```yaml
|
||||
---
|
||||
# Authentik Database Password
|
||||
vault_authentik_db_password: "secure_random_password_32_chars"
|
||||
|
||||
# Authentik Secret Key (generate with: openssl rand -base64 32)
|
||||
vault_authentik_secret_key: "your_generated_secret_key_here"
|
||||
|
||||
# Authentik Admin Password
|
||||
vault_authentik_admin_password: "secure_admin_password"
|
||||
|
||||
# Infrastructure Dependencies (should already exist)
|
||||
vault_valkey_password: "valkey_password"
|
||||
```
|
||||
|
||||
### Generate Required Secrets
|
||||
|
||||
```bash
|
||||
# Generate Authentik secret key
|
||||
openssl rand -base64 32
|
||||
|
||||
# Generate secure passwords
|
||||
openssl rand -base64 20
|
||||
```
|
||||
|
||||
### Encrypt Vault File
|
||||
|
||||
```bash
|
||||
# Encrypt the vault file
|
||||
ansible-vault encrypt host_vars/arch-vps/vault.yml
|
||||
|
||||
# Verify vault variables
|
||||
ansible-vault view host_vars/arch-vps/vault.yml
|
||||
```
|
||||
|
||||
## Pre-deployment Validation
|
||||
|
||||
### Infrastructure Health Check
|
||||
|
||||
Run the following commands to verify infrastructure readiness:
|
||||
|
||||
```bash
|
||||
# 1. Check PostgreSQL Unix socket
|
||||
ssh root@your-vps "ls -la /var/run/postgresql/"
|
||||
# Should show .s.PGSQL.5432 socket file
|
||||
|
||||
# 2. Check Valkey Unix socket
|
||||
ssh root@your-vps "ls -la /var/run/valkey/"
|
||||
# Should show valkey.sock file
|
||||
|
||||
# 3. Test PostgreSQL connectivity
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT version();'"
|
||||
# Should return PostgreSQL version
|
||||
|
||||
# 4. Test Valkey connectivity
|
||||
ssh root@your-vps "redis-cli -s /var/run/valkey/valkey.sock ping"
|
||||
# Should return "PONG"
|
||||
|
||||
# 5. Verify Caddy is responsive
|
||||
curl -I https://jnss.me/
|
||||
# Should return HTTP/2 200
|
||||
```
|
||||
|
||||
### Ansible Configuration Validation
|
||||
|
||||
```bash
|
||||
# Test Ansible connectivity
|
||||
ansible arch-vps -m ping
|
||||
|
||||
# Verify vault variables can be decrypted
|
||||
ansible arch-vps -m debug -a "var=vault_authentik_secret_key" --ask-vault-pass
|
||||
```
|
||||
|
||||
## Step-by-Step Deployment
|
||||
|
||||
### Step 1: Enable Authentik Role
|
||||
|
||||
Update `site.yml` to include the authentik role:
|
||||
|
||||
```yaml
|
||||
- name: Deploy Core Infrastructure
|
||||
hosts: arch-vps
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
roles:
|
||||
# Infrastructure dependencies handled automatically via meta/main.yml
|
||||
- role: authentik
|
||||
tags: ['authentik', 'auth', 'sso']
|
||||
```
|
||||
|
||||
### Step 2: Execute Deployment
|
||||
|
||||
```bash
|
||||
# Full deployment with verbose output
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --tags authentik --ask-vault-pass -v
|
||||
|
||||
# Alternative: Deploy with specific components
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --tags authentik,database,containers --ask-vault-pass
|
||||
```
|
||||
|
||||
### Step 3: Monitor Deployment Progress
|
||||
|
||||
During deployment, monitor the following:
|
||||
|
||||
```bash
|
||||
# Monitor deployment logs in real-time (separate terminal)
|
||||
ssh root@your-vps "journalctl -f"
|
||||
|
||||
# Watch for authentik-specific services
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status"
|
||||
```
|
||||
|
||||
### Step 4: Verify Container Deployment
|
||||
|
||||
After deployment completion:
|
||||
|
||||
```bash
|
||||
# Check systemd user services for authentik user
|
||||
ssh root@your-vps "systemctl --user -M authentik@ list-units 'authentik*'"
|
||||
|
||||
# Verify containers are running
|
||||
ssh root@your-vps "sudo -u authentik podman ps"
|
||||
|
||||
# Check pod status
|
||||
ssh root@your-vps "sudo -u authentik podman pod ps"
|
||||
```
|
||||
|
||||
### Step 5: Health Check Verification
|
||||
|
||||
```bash
|
||||
# Test internal HTTP endpoint
|
||||
ssh root@your-vps "curl -I http://127.0.0.1:9000/"
|
||||
# Expected: HTTP/1.1 302 Found (redirect to login)
|
||||
|
||||
# Test external HTTPS endpoint
|
||||
curl -I https://auth.jnss.me/
|
||||
# Expected: HTTP/2 200 or 302
|
||||
|
||||
# Test authentik API endpoint
|
||||
curl -s https://auth.jnss.me/api/v3/admin/version/
|
||||
# Expected: JSON response with authentication error (proves API is responsive)
|
||||
```
|
||||
|
||||
## Post-deployment Configuration
|
||||
|
||||
### Initial Admin Access
|
||||
|
||||
1. **Access Web Interface**:
|
||||
```bash
|
||||
# Open in browser
|
||||
https://auth.jnss.me/
|
||||
```
|
||||
|
||||
2. **Admin Login**:
|
||||
- **Username**: `admin@auth.jnss.me` (or configured admin email)
|
||||
- **Password**: Value from `vault_authentik_admin_password`
|
||||
|
||||
3. **Verify Admin Access**:
|
||||
- Navigate to `/if/admin/`
|
||||
- Confirm admin interface loads successfully
|
||||
- Check system status in admin dashboard
|
||||
|
||||
### Essential Configuration Tasks
|
||||
|
||||
#### 1. Configure OAuth2 Provider
|
||||
|
||||
```bash
|
||||
# Navigate to Applications → Providers → Create
|
||||
# Provider Type: OAuth2/OpenID Provider
|
||||
# Name: "Default OAuth2 Provider"
|
||||
# Client Type: Confidential
|
||||
# Authorization Grant Type: Authorization Code
|
||||
# Redirect URIs: Add your application callback URLs
|
||||
```
|
||||
|
||||
#### 2. Create Application
|
||||
|
||||
```bash
|
||||
# Navigate to Applications → Applications → Create
|
||||
# Name: "Your Application Name"
|
||||
# Slug: "your-app"
|
||||
# Provider: Select OAuth2 provider created above
|
||||
# Launch URL: Your application URL
|
||||
```
|
||||
|
||||
#### 3. Configure Forward Auth (for Caddy integration)
|
||||
|
||||
```bash
|
||||
# Navigate to Applications → Providers → Create
|
||||
# Provider Type: Proxy Provider
|
||||
# Name: "Forward Auth Provider"
|
||||
# External Host: https://your-service.jnss.me
|
||||
# Internal Host: http://localhost:8080 (your service backend)
|
||||
```
|
||||
|
||||
## Service Integration Examples
|
||||
|
||||
### Example 1: Protect Existing HTTP Service with Forward Auth
|
||||
|
||||
Add to your service's Caddy configuration:
|
||||
|
||||
```caddyfile
|
||||
# In /etc/caddy/sites-enabled/myservice.caddy
|
||||
myservice.jnss.me {
|
||||
# Forward authentication to authentik
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
# Your service backend
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: OAuth2 Integration for Custom Applications
|
||||
|
||||
For applications that can handle OAuth2 directly:
|
||||
|
||||
```yaml
|
||||
# Application configuration
|
||||
OAUTH2_PROVIDER_URL: "https://auth.jnss.me/application/o/authorize/"
|
||||
OAUTH2_TOKEN_URL: "https://auth.jnss.me/application/o/token/"
|
||||
OAUTH2_USER_INFO_URL: "https://auth.jnss.me/application/o/userinfo/"
|
||||
OAUTH2_CLIENT_ID: "your_client_id"
|
||||
OAUTH2_CLIENT_SECRET: "your_client_secret"
|
||||
OAUTH2_REDIRECT_URI: "https://yourapp.jnss.me/oauth/callback"
|
||||
```
|
||||
|
||||
## Troubleshooting Guide
|
||||
|
||||
### Common Issues and Solutions
|
||||
|
||||
#### Issue: Containers fail to start with socket permission errors
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
Error: failed to connect to database: permission denied
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check authentik user group membership
|
||||
ssh root@your-vps "groups authentik"
|
||||
# Should show: authentik postgres valkey
|
||||
|
||||
# Verify socket permissions
|
||||
ssh root@your-vps "ls -la /var/run/postgresql/ /var/run/valkey/"
|
||||
|
||||
# Fix group membership if missing
|
||||
ansible-playbook site.yml --tags authentik,user,setup --ask-vault-pass
|
||||
```
|
||||
|
||||
#### Issue: HTTP binding errors (address already in use)
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
Error: bind: address already in use (port 9000)
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check what's using port 9000
|
||||
ssh root@your-vps "netstat -tulpn | grep 9000"
|
||||
|
||||
# Stop conflicting services
|
||||
ssh root@your-vps "systemctl --user -M authentik@ stop authentik-pod"
|
||||
|
||||
# Restart with correct configuration
|
||||
ansible-playbook site.yml --tags authentik,containers --ask-vault-pass
|
||||
```
|
||||
|
||||
#### Issue: Database connection failures
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
FATAL: database "authentik" does not exist
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Recreate database and user
|
||||
ansible-playbook site.yml --tags authentik,database --ask-vault-pass
|
||||
|
||||
# Verify database creation
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c '\l'"
|
||||
```
|
||||
|
||||
#### Issue: Cache connection failures
|
||||
|
||||
**Symptoms**:
|
||||
```
|
||||
Error connecting to Redis: Connection refused
|
||||
```
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check Valkey service status
|
||||
ssh root@your-vps "systemctl status valkey"
|
||||
|
||||
# Test socket connectivity
|
||||
ssh root@your-vps "redis-cli -s /var/run/valkey/valkey.sock ping"
|
||||
|
||||
# Redeploy cache configuration if needed
|
||||
ansible-playbook site.yml --tags authentik,cache --ask-vault-pass
|
||||
```
|
||||
|
||||
### Diagnostic Commands
|
||||
|
||||
#### Container Debugging
|
||||
|
||||
```bash
|
||||
# Check container logs
|
||||
ssh root@your-vps "sudo -u authentik podman logs authentik-server"
|
||||
ssh root@your-vps "sudo -u authentik podman logs authentik-worker"
|
||||
|
||||
# Inspect container configuration
|
||||
ssh root@your-vps "sudo -u authentik podman inspect authentik-server"
|
||||
|
||||
# Check container user/group mapping
|
||||
ssh root@your-vps "sudo -u authentik podman exec authentik-server id"
|
||||
```
|
||||
|
||||
#### Service Status Verification
|
||||
|
||||
```bash
|
||||
# Check all authentik systemd services
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status authentik-pod authentik-server authentik-worker"
|
||||
|
||||
# View service dependencies
|
||||
ssh root@your-vps "systemctl --user -M authentik@ list-dependencies authentik-pod"
|
||||
|
||||
# Check user session status
|
||||
ssh root@your-vps "loginctl show-user authentik"
|
||||
```
|
||||
|
||||
#### Network Connectivity Testing
|
||||
|
||||
```bash
|
||||
# Test internal HTTP binding
|
||||
ssh root@your-vps "curl -v http://127.0.0.1:9000/"
|
||||
|
||||
# Test Caddy reverse proxy
|
||||
ssh root@your-vps "curl -v http://127.0.0.1:80/ -H 'Host: auth.jnss.me'"
|
||||
|
||||
# Test external HTTPS
|
||||
curl -v https://auth.jnss.me/
|
||||
```
|
||||
|
||||
### Log Analysis
|
||||
|
||||
#### Key Log Locations
|
||||
|
||||
```bash
|
||||
# Authentik application logs
|
||||
ssh root@your-vps "sudo -u authentik cat /opt/authentik/logs/server.log"
|
||||
ssh root@your-vps "sudo -u authentik cat /opt/authentik/logs/worker.log"
|
||||
|
||||
# systemd service logs
|
||||
ssh root@your-vps "journalctl --user -M authentik@ -u authentik-server -f"
|
||||
ssh root@your-vps "journalctl --user -M authentik@ -u authentik-worker -f"
|
||||
|
||||
# Caddy logs for reverse proxy issues
|
||||
ssh root@your-vps "journalctl -u caddy -f"
|
||||
```
|
||||
|
||||
#### Common Log Patterns
|
||||
|
||||
**Successful startup**:
|
||||
```
|
||||
INFO authentik.core.signals: authentik 2025.10.x starting
|
||||
INFO authentik.core.models: Database version up-to-date
|
||||
```
|
||||
|
||||
**Database connection success**:
|
||||
```
|
||||
INFO authentik.core.db: Connected to database via unix socket
|
||||
```
|
||||
|
||||
**Cache connection success**:
|
||||
```
|
||||
INFO authentik.core.cache: Connected to cache via unix socket
|
||||
```
|
||||
|
||||
## Performance Monitoring
|
||||
|
||||
### Resource Usage Monitoring
|
||||
|
||||
```bash
|
||||
# Monitor container resource usage
|
||||
ssh root@your-vps "sudo -u authentik podman stats"
|
||||
|
||||
# Monitor service memory usage
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status authentik-server | grep Memory"
|
||||
|
||||
# Monitor database connections
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT * FROM pg_stat_activity;'"
|
||||
```
|
||||
|
||||
### Performance Optimization Tips
|
||||
|
||||
1. **Database Performance**:
|
||||
- Monitor PostgreSQL slow query log
|
||||
- Consider database connection pooling for high traffic
|
||||
- Regular database maintenance (VACUUM, ANALYZE)
|
||||
|
||||
2. **Cache Performance**:
|
||||
- Monitor Valkey memory usage and hit rate
|
||||
- Adjust cache TTL settings based on usage patterns
|
||||
- Consider cache warming for frequently accessed data
|
||||
|
||||
3. **Container Performance**:
|
||||
- Monitor container memory limits and usage
|
||||
- Optimize shared memory configuration if needed
|
||||
- Review worker process configuration
|
||||
|
||||
## Maintenance Tasks
|
||||
|
||||
### Regular Maintenance
|
||||
|
||||
#### Update Authentik Version
|
||||
|
||||
```yaml
|
||||
# Update version in defaults or inventory
|
||||
authentik_version: "2025.12.1" # New version
|
||||
|
||||
# Deploy update
|
||||
ansible-playbook site.yml --tags authentik,containers --ask-vault-pass
|
||||
```
|
||||
|
||||
#### Backup Procedures
|
||||
|
||||
```bash
|
||||
# Database backup
|
||||
ssh root@your-vps "sudo -u postgres pg_dump -h /var/run/postgresql authentik > /backup/authentik-$(date +%Y%m%d).sql"
|
||||
|
||||
# Media files backup
|
||||
ssh root@your-vps "tar -czf /backup/authentik-media-$(date +%Y%m%d).tar.gz -C /opt/authentik media"
|
||||
|
||||
# Configuration backup (run from ansible control machine)
|
||||
ansible-vault view host_vars/arch-vps/vault.yml > backup/authentik-vault-$(date +%Y%m%d).yml
|
||||
```
|
||||
|
||||
#### Health Monitoring
|
||||
|
||||
Set up regular health checks:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Health check script
|
||||
HEALTH_URL="https://auth.jnss.me/if/health/live/"
|
||||
if ! curl -f -s "$HEALTH_URL" > /dev/null; then
|
||||
echo "Authentik health check failed"
|
||||
# Add alerting logic
|
||||
fi
|
||||
```
|
||||
|
||||
### Security Maintenance
|
||||
|
||||
#### Certificate Monitoring
|
||||
|
||||
```bash
|
||||
# Check certificate expiration
|
||||
ssh root@your-vps "curl -vI https://auth.jnss.me/ 2>&1 | grep expire"
|
||||
|
||||
# Caddy handles renewal automatically, but monitor logs
|
||||
ssh root@your-vps "journalctl -u caddy | grep -i cert"
|
||||
```
|
||||
|
||||
#### Security Updates
|
||||
|
||||
```bash
|
||||
# Update container images regularly
|
||||
ansible-playbook site.yml --tags authentik,image-pull --ask-vault-pass
|
||||
|
||||
# Monitor for Authentik security advisories
|
||||
# https://github.com/goauthentik/authentik/security/advisories
|
||||
```
|
||||
|
||||
## Support and Resources
|
||||
|
||||
### Documentation References
|
||||
|
||||
- **Authentik Official Documentation**: https://docs.goauthentik.io/
|
||||
- **rick-infra Architecture Decisions**: [docs/architecture-decisions.md](architecture-decisions.md)
|
||||
- **Service Integration Guide**: [docs/service-integration-guide.md](service-integration-guide.md)
|
||||
- **Security Model**: [docs/security-hardening.md](security-hardening.md)
|
||||
|
||||
### Community Resources
|
||||
|
||||
- **Authentik Community Forum**: https://community.goauthentik.io/
|
||||
- **GitHub Issues**: https://github.com/goauthentik/authentik/issues
|
||||
- **Discord Community**: https://discord.gg/jg33eMhnj6
|
||||
|
||||
### Emergency Procedures
|
||||
|
||||
#### Service Recovery
|
||||
|
||||
```bash
|
||||
# Emergency service restart
|
||||
ssh root@your-vps "systemctl --user -M authentik@ restart authentik-pod"
|
||||
|
||||
# Fallback: Direct container management
|
||||
ssh root@your-vps "sudo -u authentik podman pod restart authentik"
|
||||
|
||||
# Last resort: Full service rebuild
|
||||
ansible-playbook site.yml --tags authentik --ask-vault-pass --limit arch-vps
|
||||
```
|
||||
|
||||
#### Rollback Procedures
|
||||
|
||||
```bash
|
||||
# Rollback to previous container version
|
||||
authentik_version: "previous_working_version"
|
||||
ansible-playbook site.yml --tags authentik,containers --ask-vault-pass
|
||||
|
||||
# Database rollback (if needed)
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql authentik < /backup/authentik-backup.sql"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Checklist
|
||||
|
||||
Use this checklist to ensure complete deployment:
|
||||
|
||||
### Pre-deployment
|
||||
- [ ] Infrastructure services (PostgreSQL, Valkey, Caddy, Podman) running
|
||||
- [ ] DNS records configured for auth.jnss.me
|
||||
- [ ] Vault variables configured and encrypted
|
||||
- [ ] Ansible connectivity verified
|
||||
|
||||
### Deployment
|
||||
- [ ] Authentik role enabled in site.yml
|
||||
- [ ] Deployment executed successfully
|
||||
- [ ] Health checks passing
|
||||
- [ ] Containers running and responsive
|
||||
|
||||
### Post-deployment
|
||||
- [ ] Admin web interface accessible
|
||||
- [ ] Initial admin login successful
|
||||
- [ ] OAuth2 provider configured
|
||||
- [ ] Test application integration
|
||||
- [ ] Forward auth configuration tested
|
||||
|
||||
### Production Readiness
|
||||
- [ ] Backup procedures implemented
|
||||
- [ ] Monitoring and alerting configured
|
||||
- [ ] Security review completed
|
||||
- [ ] Documentation updated
|
||||
- [ ] Team training completed
|
||||
|
||||
---
|
||||
|
||||
This comprehensive deployment guide provides everything needed to successfully deploy and maintain Authentik in the rick-infra environment, emphasizing the security and performance benefits of our native database + Unix socket architecture.
|
||||
@@ -1,51 +1,195 @@
|
||||
# Deployment Guide
|
||||
|
||||
This guide explains how to deploy your infrastructure using the updated Caddy API registration system.
|
||||
This guide explains how to deploy your infrastructure including core services, authentication, and applications.
|
||||
|
||||
## Overview
|
||||
|
||||
The deployment system has been restructured to support:
|
||||
- **Core Infrastructure**: Caddy web server with API capabilities
|
||||
- **Service Registration**: Dynamic service registration via API
|
||||
- **Zero Downtime**: Services can be added/removed without restarts
|
||||
The rick-infra deployment system provides:
|
||||
- **Native Infrastructure**: PostgreSQL, Valkey, Podman, Caddy managed by systemd
|
||||
- **Authentication Services**: Authentik SSO with forward auth integration
|
||||
- **Application Services**: Containerized services with Unix socket IPC
|
||||
- **Security First**: All services deployed with security hardening by default
|
||||
|
||||
## Available Playbooks
|
||||
## Architecture Overview
|
||||
|
||||
### 1. `site.yml` - Core Infrastructure
|
||||
Deploys security hardening followed by Caddy web server infrastructure.
|
||||
|
||||
```bash
|
||||
ansible-playbook -i inventory/hosts.yml site.yml
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ rick-infra Infrastructure Stack │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌───────────────┐ │
|
||||
│ │ Applications │ │ Authentication │ │ Reverse Proxy │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ Gitea (Git) │ │ Authentik (SSO) │ │ Caddy (HTTPS) │ │
|
||||
│ │ Gallery (Media) │ │ Forward Auth │ │ Auto TLS │ │
|
||||
│ │ Custom Services │ │ OAuth2/OIDC │ │ Load Balance │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └───────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────────┼────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Infrastructure Services (Native systemd) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
|
||||
│ │ │ PostgreSQL │ │ Valkey │ │ Podman │ │ │
|
||||
│ │ │ (Database) │ │ (Cache) │ │ (Containers) │ │ │
|
||||
│ │ │Unix Sockets │ │Unix Sockets │ │ Rootless │ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Security Foundation │ │
|
||||
│ │ SSH Hardening • Firewall • Fail2ban • Updates │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- **Phase 1 - Security**: System updates, SSH hardening, nftables firewall, fail2ban
|
||||
- **Phase 2 - Caddy**: Installs Caddy with Cloudflare DNS plugin
|
||||
- Configures TLS with Let's Encrypt
|
||||
- Sets up named server for API targeting
|
||||
- Enables API persistence with `--resume`
|
||||
- Serves main domain (jnss.me)
|
||||
## Available Deployments
|
||||
|
||||
### 1. `site.yml` - Complete Infrastructure Stack
|
||||
Deploys the full rick-infra stack with role dependencies automatically managed.
|
||||
|
||||
```bash
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
**What it deploys:**
|
||||
- **Security Foundation**: SSH hardening, firewall, fail2ban, system updates
|
||||
- **Infrastructure Services**: PostgreSQL, Valkey, Podman container runtime
|
||||
- **Reverse Proxy**: Caddy with automatic HTTPS and Cloudflare DNS integration
|
||||
- **Authentication**: Authentik SSO server with forward auth integration
|
||||
- **Applications**: Gitea, Gallery, and other configured services
|
||||
|
||||
### 2. Service-Specific Deployments
|
||||
Deploy individual components using tags:
|
||||
|
||||
```bash
|
||||
# Deploy only infrastructure services
|
||||
ansible-playbook site.yml --tags postgresql,valkey,podman,caddy --ask-vault-pass
|
||||
|
||||
# Deploy only authentication
|
||||
ansible-playbook site.yml --tags authentik --ask-vault-pass
|
||||
|
||||
# Deploy only applications
|
||||
ansible-playbook site.yml --tags gitea,sigvild-gallery --ask-vault-pass
|
||||
```
|
||||
|
||||
### 3. Security-Only Deployment
|
||||
```bash
|
||||
# Deploy only security hardening
|
||||
ansible-playbook playbooks/security.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
## Deployment Patterns
|
||||
|
||||
### First-Time Deployment
|
||||
### First-Time Complete Deployment
|
||||
|
||||
⚠️ **Important**: First-time deployments include security hardening that may require a system reboot.
|
||||
|
||||
1. **Deploy Core Infrastructure**
|
||||
```bash
|
||||
# Option 1: Security + Basic infrastructure
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --ask-vault-pass
|
||||
#### Prerequisites
|
||||
|
||||
# Option 2: Complete deployment with comprehensive verification
|
||||
ansible-playbook -i inventory/hosts.yml deploy.yml --ask-vault-pass
|
||||
```
|
||||
1. **VPS Setup**: Fresh Arch Linux VPS with root access
|
||||
2. **DNS Configuration**: Domain pointed to VPS IP address
|
||||
3. **Vault Variables**: Required secrets configured (see [Vault Setup](#vault-variables))
|
||||
4. **SSH Access**: Key-based authentication configured
|
||||
|
||||
**Note**: The security hardening phase may:
|
||||
- Update all system packages
|
||||
- Reboot the system if kernel updates are applied
|
||||
- Configure SSH, firewall, and fail2ban
|
||||
- This ensures a secure foundation before deploying web services
|
||||
#### Step-by-Step First Deployment
|
||||
|
||||
```bash
|
||||
# 1. Test connectivity
|
||||
ansible arch-vps -m ping
|
||||
|
||||
# 2. Deploy complete infrastructure stack
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --ask-vault-pass
|
||||
|
||||
# 3. Verify deployment
|
||||
curl -I https://auth.jnss.me/
|
||||
curl -I https://git.jnss.me/
|
||||
```
|
||||
|
||||
**What happens during first deployment:**
|
||||
|
||||
1. **Security Hardening** (1-2 minutes)
|
||||
- System package updates
|
||||
- SSH configuration hardening
|
||||
- nftables firewall setup
|
||||
- fail2ban intrusion detection
|
||||
- Kernel security parameters
|
||||
- *May require reboot if kernel updated*
|
||||
|
||||
2. **Infrastructure Services** (2-3 minutes)
|
||||
- PostgreSQL database with Unix sockets
|
||||
- Valkey cache with Unix sockets
|
||||
- Podman rootless container setup
|
||||
- Caddy reverse proxy with auto-HTTPS
|
||||
|
||||
3. **Authentication Service** (3-5 minutes)
|
||||
- Authentik container deployment
|
||||
- Database and cache integration
|
||||
- Forward auth configuration
|
||||
- Admin user initialization
|
||||
|
||||
4. **Application Services** (2-4 minutes)
|
||||
- Gitea Git service
|
||||
- Gallery media service
|
||||
- Service-specific configurations
|
||||
|
||||
**Total deployment time**: 8-14 minutes for complete stack
|
||||
|
||||
### Incremental Deployment
|
||||
|
||||
For subsequent deployments or updates:
|
||||
|
||||
```bash
|
||||
# Deploy only changed components
|
||||
ansible-playbook site.yml --tags authentik --ask-vault-pass
|
||||
|
||||
# Deploy with check mode first (dry run)
|
||||
ansible-playbook site.yml --check --ask-vault-pass
|
||||
|
||||
# Deploy with verbose output for debugging
|
||||
ansible-playbook site.yml -v --ask-vault-pass
|
||||
```
|
||||
|
||||
## Authentication Deployment
|
||||
|
||||
### Authentik SSO Server
|
||||
|
||||
Rick-infra includes comprehensive authentication via Authentik. For detailed deployment instructions, see the [Authentik Deployment Guide](authentik-deployment-guide.md).
|
||||
|
||||
#### Quick Authentik Deployment
|
||||
|
||||
```bash
|
||||
# Deploy authentik and all dependencies
|
||||
ansible-playbook site.yml --tags authentik --ask-vault-pass
|
||||
|
||||
# Verify authentik deployment
|
||||
curl -I https://auth.jnss.me/
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status authentik-pod"
|
||||
```
|
||||
|
||||
#### Authentik Integration Pattern
|
||||
|
||||
All services in rick-infra use forward authentication through Caddy:
|
||||
|
||||
```caddyfile
|
||||
# Example service with authentik protection
|
||||
myservice.jnss.me {
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
#### Post-Deployment Authentik Setup
|
||||
|
||||
1. **Access Admin Interface**: `https://auth.jnss.me/if/admin/`
|
||||
2. **Default Admin**: Email from `authentik_default_admin_email` variable
|
||||
3. **Initial Configuration**: Follow [Authentik Deployment Guide](authentik-deployment-guide.md#post-deployment-configuration)
|
||||
|
||||
For complete authentik architecture details, see [Architecture Decisions](architecture-decisions.md#adr-004-forward-authentication-security-model).
|
||||
|
||||
## Configuration Management
|
||||
|
||||
@@ -78,23 +222,279 @@ caddy_systemd_security: true
|
||||
Sensitive data in `host_vars/arch-vps/vault.yml` (encrypted):
|
||||
|
||||
```yaml
|
||||
# Infrastructure secrets
|
||||
vault_caddy_tls_email: "admin@jnss.me"
|
||||
vault_cloudflare_api_token: "your-api-token-here"
|
||||
vault_cloudflare_api_token: "your-cloudflare-token"
|
||||
|
||||
# Database passwords
|
||||
vault_postgresql_password: "secure-postgres-password"
|
||||
vault_valkey_password: "secure-valkey-password"
|
||||
|
||||
# Authentik authentication secrets
|
||||
vault_authentik_secret_key: "base64-encoded-secret-key"
|
||||
vault_authentik_admin_password: "secure-admin-password"
|
||||
vault_authentik_db_password: "authentik-database-password"
|
||||
|
||||
# Application secrets
|
||||
vault_gitea_secret_key: "gitea-secret-key"
|
||||
vault_gitea_jwt_secret: "gitea-jwt-secret"
|
||||
```
|
||||
|
||||
#### Generate Vault Secrets
|
||||
|
||||
```bash
|
||||
# Generate secure passwords and keys
|
||||
openssl rand -base64 32 # For secret keys
|
||||
openssl rand -base64 20 # For passwords
|
||||
|
||||
# Encrypt vault file
|
||||
ansible-vault encrypt host_vars/arch-vps/vault.yml
|
||||
|
||||
# Edit vault file
|
||||
ansible-vault edit host_vars/arch-vps/vault.yml
|
||||
```
|
||||
|
||||
|
||||
### Security
|
||||
## Monitoring and Verification
|
||||
|
||||
- Always use vault for sensitive data
|
||||
- Test deployments on staging first
|
||||
- Monitor logs after deployment
|
||||
- Verify HTTPS certificates are working
|
||||
- Check that API is only accessible locally
|
||||
### Service Health Checks
|
||||
|
||||
### Monitoring
|
||||
```bash
|
||||
# Infrastructure services
|
||||
ssh root@your-vps "systemctl status postgresql valkey caddy podman"
|
||||
|
||||
- Monitor Caddy logs: `journalctl -u caddy -f`
|
||||
- Check API status: `curl http://localhost:2019/config/`
|
||||
- Verify service health: `curl https://domain.com/health`
|
||||
- Monitor certificate expiration
|
||||
# Authentication services
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status authentik-pod"
|
||||
|
||||
# Application services
|
||||
ssh root@your-vps "systemctl --user -M gitea@ status gitea"
|
||||
|
||||
# Web service accessibility
|
||||
curl -I https://auth.jnss.me/
|
||||
curl -I https://git.jnss.me/
|
||||
```
|
||||
|
||||
### Log Monitoring
|
||||
|
||||
```bash
|
||||
# Infrastructure logs
|
||||
ssh root@your-vps "journalctl -u caddy -f"
|
||||
ssh root@your-vps "journalctl -u postgresql -f"
|
||||
ssh root@your-vps "journalctl -u valkey -f"
|
||||
|
||||
# Authentication logs
|
||||
ssh root@your-vps "journalctl --user -M authentik@ -u authentik-server -f"
|
||||
|
||||
# Application logs
|
||||
ssh root@your-vps "journalctl --user -M gitea@ -u gitea -f"
|
||||
```
|
||||
|
||||
### Performance Monitoring
|
||||
|
||||
```bash
|
||||
# Container resource usage
|
||||
ssh root@your-vps "sudo -u authentik podman stats"
|
||||
ssh root@your-vps "sudo -u gitea podman stats"
|
||||
|
||||
# Database performance
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT * FROM pg_stat_activity;'"
|
||||
|
||||
# System resources
|
||||
ssh root@your-vps "htop"
|
||||
ssh root@your-vps "df -h"
|
||||
ssh root@your-vps "free -h"
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Deployment Security
|
||||
|
||||
- **Always use vault**: Never commit secrets to version control
|
||||
- **Verify connectivity**: Test Ansible connection before deployment
|
||||
- **Monitor logs**: Watch deployment logs for errors or warnings
|
||||
- **Validate services**: Verify all services start correctly after deployment
|
||||
- **Check certificates**: Ensure HTTPS certificates are issued correctly
|
||||
|
||||
### Operational Security
|
||||
|
||||
- **Regular updates**: Keep system packages and container images updated
|
||||
- **Access monitoring**: Monitor authentication logs for suspicious activity
|
||||
- **Backup procedures**: Regular backups of databases and configurations
|
||||
- **Certificate monitoring**: Monitor TLS certificate expiration
|
||||
- **Security scans**: Regular security assessments of deployed services
|
||||
|
||||
### Network Security
|
||||
|
||||
- **Firewall verification**: Ensure only ports 80/443 are exposed externally
|
||||
- **Unix socket usage**: Verify database/cache communications use Unix sockets
|
||||
- **TLS encryption**: Confirm all external communications use HTTPS
|
||||
- **Access logs**: Monitor Caddy access logs for unusual patterns
|
||||
|
||||
## Troubleshooting Common Issues
|
||||
|
||||
### Deployment Failures
|
||||
|
||||
#### Issue: Ansible vault decryption fails
|
||||
```bash
|
||||
# Solution: Verify vault password and file encryption
|
||||
ansible-vault view host_vars/arch-vps/vault.yml
|
||||
ansible-vault decrypt host_vars/arch-vps/vault.yml # Edit, then re-encrypt
|
||||
ansible-vault encrypt host_vars/arch-vps/vault.yml
|
||||
```
|
||||
|
||||
#### Issue: SSH connection failures
|
||||
```bash
|
||||
# Solution: Verify SSH configuration and keys
|
||||
ssh-add -l # List SSH keys
|
||||
ssh root@your-vps # Test direct connection
|
||||
ansible arch-vps -m ping # Test Ansible connectivity
|
||||
```
|
||||
|
||||
#### Issue: Container services fail to start
|
||||
```bash
|
||||
# Check container user sessions
|
||||
ssh root@your-vps "loginctl list-users"
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status"
|
||||
|
||||
# Verify container images are available
|
||||
ssh root@your-vps "sudo -u authentik podman images"
|
||||
|
||||
# Check container logs
|
||||
ssh root@your-vps "sudo -u authentik podman logs authentik-server"
|
||||
```
|
||||
|
||||
### Service Connectivity Issues
|
||||
|
||||
#### Issue: Database connection failures
|
||||
```bash
|
||||
# Verify PostgreSQL socket exists and is accessible
|
||||
ssh root@your-vps "ls -la /var/run/postgresql/"
|
||||
ssh root@your-vps "sudo -u authentik psql -h /var/run/postgresql -U authentik"
|
||||
|
||||
# Check PostgreSQL service status
|
||||
ssh root@your-vps "systemctl status postgresql"
|
||||
```
|
||||
|
||||
#### Issue: Authentication not working
|
||||
```bash
|
||||
# Check authentik service status
|
||||
ssh root@your-vps "systemctl --user -M authentik@ status authentik-pod authentik-server"
|
||||
|
||||
# Test authentik HTTP endpoint
|
||||
ssh root@your-vps "curl -I http://127.0.0.1:9000/"
|
||||
|
||||
# Check Caddy forward auth configuration
|
||||
ssh root@your-vps "caddy validate --config /etc/caddy/Caddyfile"
|
||||
```
|
||||
|
||||
#### Issue: HTTPS certificate problems
|
||||
```bash
|
||||
# Check certificate status
|
||||
curl -vI https://auth.jnss.me/ 2>&1 | grep -E "(certificate|expire)"
|
||||
|
||||
# Check Caddy certificate management
|
||||
ssh root@your-vps "journalctl -u caddy | grep -i cert"
|
||||
|
||||
# Verify DNS records
|
||||
dig +short auth.jnss.me
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
|
||||
#### Issue: Slow database queries
|
||||
```bash
|
||||
# Monitor active connections
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT * FROM pg_stat_activity;'"
|
||||
|
||||
# Check database performance
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT * FROM pg_stat_database;'"
|
||||
```
|
||||
|
||||
#### Issue: High memory usage
|
||||
```bash
|
||||
# Check system memory
|
||||
ssh root@your-vps "free -h"
|
||||
|
||||
# Check container memory usage
|
||||
ssh root@your-vps "sudo -u authentik podman stats"
|
||||
|
||||
# Check service memory limits
|
||||
ssh root@your-vps "systemctl --user -M authentik@ show authentik-server --property=MemoryCurrent"
|
||||
```
|
||||
|
||||
## Maintenance Procedures
|
||||
|
||||
### Regular Maintenance Tasks
|
||||
|
||||
#### System Updates
|
||||
```bash
|
||||
# Update system packages
|
||||
ansible arch-vps -m pacman -a "update_cache=yes upgrade=yes" --become
|
||||
|
||||
# Update container images
|
||||
ansible-playbook site.yml --tags containers,image-pull --ask-vault-pass
|
||||
```
|
||||
|
||||
#### Certificate Renewal
|
||||
```bash
|
||||
# Certificates renew automatically, but monitor logs
|
||||
ssh root@your-vps "journalctl -u caddy | grep -i 'certificate\|renewal'"
|
||||
|
||||
# Force certificate renewal if needed
|
||||
ssh root@your-vps "systemctl reload caddy"
|
||||
```
|
||||
|
||||
#### Database Maintenance
|
||||
```bash
|
||||
# PostgreSQL maintenance
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'VACUUM ANALYZE;'"
|
||||
|
||||
# Database backups
|
||||
ssh root@your-vps "sudo -u postgres pg_dumpall -h /var/run/postgresql > /backup/postgres-backup-\$(date +%Y%m%d).sql"
|
||||
```
|
||||
|
||||
### Backup Procedures
|
||||
|
||||
#### Configuration Backup
|
||||
```bash
|
||||
# Backup Ansible configurations (run from control machine)
|
||||
tar -czf rick-infra-backup-$(date +%Y%m%d).tar.gz \
|
||||
inventory/ host_vars/ roles/ docs/ *.yml
|
||||
|
||||
# Backup vault files separately and securely
|
||||
ansible-vault view host_vars/arch-vps/vault.yml > secure-backup/vault-$(date +%Y%m%d).yml
|
||||
```
|
||||
|
||||
#### Data Backup
|
||||
```bash
|
||||
# Database backup
|
||||
ssh root@your-vps "sudo -u postgres pg_dump -h /var/run/postgresql authentik > /backup/authentik-$(date +%Y%m%d).sql"
|
||||
ssh root@your-vps "sudo -u postgres pg_dump -h /var/run/postgresql gitea > /backup/gitea-$(date +%Y%m%d).sql"
|
||||
|
||||
# Application data backup
|
||||
ssh root@your-vps "tar -czf /backup/authentik-media-$(date +%Y%m%d).tar.gz -C /opt/authentik media"
|
||||
ssh root@your-vps "tar -czf /backup/gitea-data-$(date +%Y%m%d).tar.gz -C /opt/gitea data"
|
||||
```
|
||||
|
||||
## Documentation References
|
||||
|
||||
### Core Documentation
|
||||
- **[Setup Guide](setup-guide.md)** - Initial VPS and Ansible setup
|
||||
- **[Authentik Deployment Guide](authentik-deployment-guide.md)** - Detailed authentik deployment
|
||||
- **[Architecture Decisions](architecture-decisions.md)** - Technical decision rationale
|
||||
- **[Security Hardening](security-hardening.md)** - Security configuration details
|
||||
|
||||
### Service Integration
|
||||
- **[Service Integration Guide](service-integration-guide.md)** - Adding new services
|
||||
- **[Caddy Configuration](caddy-service-configuration.md)** - Reverse proxy patterns
|
||||
|
||||
### Role Documentation
|
||||
- **[Authentik Role](../roles/authentik/README.md)** - Authentication service details
|
||||
- **[PostgreSQL Role](../roles/postgresql/README.md)** - Database service details
|
||||
- **[Valkey Role](../roles/valkey/README.md)** - Cache service details
|
||||
- **[Caddy Role](../roles/caddy/README.md)** - Reverse proxy details
|
||||
|
||||
---
|
||||
|
||||
This comprehensive deployment guide provides the foundation for deploying and maintaining the complete rick-infra stack with emphasis on security, performance, and operational excellence through native database services and Unix socket IPC architecture.
|
||||
|
||||
|
||||
@@ -1,7 +1,930 @@
|
||||
# Securing the VPS
|
||||
## Network Security
|
||||
- **SSH Hardening**: Password authentication disabled, root login disabled, key-only authentication
|
||||
- **Firewall Configuration**: UFW with deny-all incoming, allow-all outgoing defaults
|
||||
- **Fail2ban**: SSH brute-force protection with configurable ban times
|
||||
- **Kernel Network Hardening**: IP forwarding disabled, source routing blocked, ICMP redirects disabled
|
||||
# Security Hardening Guide
|
||||
|
||||
Comprehensive security hardening for rick-infra, implementing defense-in-depth with network, container, database, and application security layers.
|
||||
|
||||
## Security Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ rick-infra Security Architecture (Defense in Depth) │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Layer 1: Network Security │ │
|
||||
│ │ • SSH Hardening • Firewall • Fail2ban • TLS/HTTPS │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Layer 2: Authentication & Authorization │ │
|
||||
│ │ • Authentik SSO • MFA • Forward Auth • Policy Engine │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Layer 3: Container Security │ │
|
||||
│ │ • Rootless Podman • User Namespaces • Capabilities │ │
|
||||
│ │ • SELinux • Resource Limits • Security Labels │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Layer 4: Database & Cache Security │ │
|
||||
│ │ • Unix Sockets Only • No Network Exposure • Group ACLs │ │
|
||||
│ │ • Encrypted Storage • Backup Security • Access Logging │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Layer 5: Application Security │ │
|
||||
│ │ • Secret Management • Secure Headers • Audit Logging │ │
|
||||
│ │ • Input Validation • Session Security • CSRF Protection │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Layer 1: Network Security
|
||||
|
||||
### SSH Hardening
|
||||
|
||||
#### Configuration Applied by Security Role
|
||||
|
||||
```yaml
|
||||
# SSH hardening settings
|
||||
sshd_config:
|
||||
# Authentication Security
|
||||
PasswordAuthentication: no
|
||||
ChallengeResponseAuthentication: no
|
||||
PermitRootLogin: no
|
||||
PubkeyAuthentication: yes
|
||||
AuthenticationMethods: "publickey"
|
||||
|
||||
# Protocol Security
|
||||
Protocol: 2
|
||||
PermitEmptyPasswords: no
|
||||
MaxAuthTries: 3
|
||||
LoginGraceTime: 60
|
||||
|
||||
# Connection Security
|
||||
X11Forwarding: no
|
||||
AllowAgentForwarding: no
|
||||
AllowTcpForwarding: no
|
||||
PermitTunnel: no
|
||||
|
||||
# Session Security
|
||||
ClientAliveInterval: 300
|
||||
ClientAliveCountMax: 2
|
||||
MaxSessions: 2
|
||||
MaxStartups: "2:30:10"
|
||||
```
|
||||
|
||||
#### Verification Commands
|
||||
|
||||
```bash
|
||||
# Verify SSH hardening
|
||||
ssh root@your-vps "sshd -T | grep -E '(passwordauth|rootlogin|pubkey)'"
|
||||
|
||||
# Test SSH security
|
||||
ssh-audit your-vps # External tool for SSH security assessment
|
||||
|
||||
# Monitor SSH attempts
|
||||
ssh root@your-vps "journalctl -u sshd | grep -i 'failed\|invalid'"
|
||||
```
|
||||
|
||||
### Firewall Configuration
|
||||
|
||||
#### nftables Firewall Rules
|
||||
|
||||
```bash
|
||||
# Deployed firewall configuration
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
|
||||
# Allow loopback traffic
|
||||
iifname "lo" accept
|
||||
|
||||
# Allow established connections
|
||||
ct state established,related accept
|
||||
|
||||
# Allow SSH (rate limited)
|
||||
tcp dport 22 ct state new limit rate 5/minute accept
|
||||
|
||||
# Allow HTTP/HTTPS
|
||||
tcp dport {80, 443} accept
|
||||
|
||||
# Allow ICMP (rate limited)
|
||||
icmp type echo-request limit rate 1/second accept
|
||||
|
||||
# Log dropped packets
|
||||
log prefix "DROPPED: " drop
|
||||
}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Firewall Management
|
||||
|
||||
```bash
|
||||
# Check firewall status
|
||||
ssh root@your-vps "nft list ruleset"
|
||||
|
||||
# Monitor dropped connections
|
||||
ssh root@your-vps "journalctl -k | grep DROPPED"
|
||||
|
||||
# Temporary rule addition (emergency access)
|
||||
ssh root@your-vps "nft add rule inet filter input tcp dport 8080 accept"
|
||||
```
|
||||
|
||||
### Intrusion Detection (fail2ban)
|
||||
|
||||
#### fail2ban Configuration
|
||||
|
||||
```ini
|
||||
# SSH protection jail
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ssh
|
||||
filter = sshd
|
||||
logpath = /var/log/auth.log
|
||||
maxretry = 3
|
||||
findtime = 600
|
||||
bantime = 3600
|
||||
backend = systemd
|
||||
|
||||
# HTTP brute force protection
|
||||
[caddy-auth]
|
||||
enabled = true
|
||||
port = http,https
|
||||
filter = caddy-auth
|
||||
logpath = /var/log/caddy/access.log
|
||||
maxretry = 10
|
||||
findtime = 600
|
||||
bantime = 1800
|
||||
|
||||
# Authentik protection
|
||||
[authentik-auth]
|
||||
enabled = true
|
||||
port = http,https
|
||||
filter = authentik-auth
|
||||
logpath = /opt/authentik/logs/server.log
|
||||
maxretry = 5
|
||||
findtime = 300
|
||||
bantime = 3600
|
||||
```
|
||||
|
||||
#### Intrusion Monitoring
|
||||
|
||||
```bash
|
||||
# Check fail2ban status
|
||||
ssh root@your-vps "fail2ban-client status"
|
||||
ssh root@your-vps "fail2ban-client status sshd"
|
||||
|
||||
# View banned IPs
|
||||
ssh root@your-vps "fail2ban-client get sshd banned"
|
||||
|
||||
# Unban IP (if needed)
|
||||
ssh root@your-vps "fail2ban-client set sshd unbanip 203.0.113.100"
|
||||
```
|
||||
|
||||
### TLS/HTTPS Security
|
||||
|
||||
#### Caddy TLS Configuration
|
||||
|
||||
```caddyfile
|
||||
# Automatic HTTPS with security headers
|
||||
(security_headers) {
|
||||
header {
|
||||
# HSTS (HTTP Strict Transport Security)
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
|
||||
# Content Security Policy
|
||||
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
|
||||
|
||||
# Additional security headers
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
X-XSS-Protection "1; mode=block"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
|
||||
# Remove server information
|
||||
-Server
|
||||
}
|
||||
}
|
||||
|
||||
# Apply to all sites
|
||||
*.jnss.me {
|
||||
import security_headers
|
||||
tls {
|
||||
protocols tls1.2 tls1.3
|
||||
curves x25519 secp384r1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### TLS Monitoring
|
||||
|
||||
```bash
|
||||
# Check certificate status
|
||||
curl -vI https://auth.jnss.me/ 2>&1 | grep -E "(certificate|expire|protocol)"
|
||||
|
||||
# Test TLS configuration
|
||||
nmap --script ssl-enum-ciphers -p 443 your-domain.com
|
||||
|
||||
# Monitor certificate renewal
|
||||
ssh root@your-vps "journalctl -u caddy | grep -i cert"
|
||||
```
|
||||
|
||||
## Layer 2: Authentication & Authorization Security
|
||||
|
||||
### Authentik Security Configuration
|
||||
|
||||
#### Password Policy
|
||||
|
||||
```yaml
|
||||
# Authentik password policy
|
||||
password_policy:
|
||||
length_min: 12
|
||||
amount_lowercase: 1
|
||||
amount_uppercase: 1
|
||||
amount_digits: 1
|
||||
amount_symbols: 1
|
||||
password_field: "password"
|
||||
check_static_rules: true
|
||||
check_have_i_been_pwned: true
|
||||
check_zxcvbn: true
|
||||
zxcvbn_score_threshold: 3
|
||||
```
|
||||
|
||||
#### Multi-Factor Authentication
|
||||
|
||||
```yaml
|
||||
# MFA enforcement policies
|
||||
mfa_policies:
|
||||
- name: "Admin MFA Required"
|
||||
bound_to: "group:admins"
|
||||
authenticators: ["totp", "webauthn"]
|
||||
enforce: true
|
||||
|
||||
- name: "Sensitive Services MFA"
|
||||
bound_to: "application:admin_*"
|
||||
authenticators: ["totp"]
|
||||
enforce: true
|
||||
|
||||
- name: "External Access MFA"
|
||||
bound_to: "source_ip:!10.0.0.0/8"
|
||||
authenticators: ["totp", "sms"]
|
||||
enforce: true
|
||||
```
|
||||
|
||||
#### Session Security
|
||||
|
||||
```yaml
|
||||
# Session security settings
|
||||
session_security:
|
||||
cookie_secure: true
|
||||
cookie_httponly: true
|
||||
cookie_samesite: "Strict"
|
||||
session_timeout: 3600 # 1 hour
|
||||
remember_me_timeout: 86400 # 24 hours
|
||||
concurrent_sessions_limit: 3
|
||||
session_fixation_protection: true
|
||||
```
|
||||
|
||||
### Access Control Policies
|
||||
|
||||
#### Time-Based Access Control
|
||||
|
||||
```yaml
|
||||
# Business hours access policy
|
||||
policies:
|
||||
- name: "Business Hours Only"
|
||||
type: "time"
|
||||
parameters:
|
||||
start_time: "08:00"
|
||||
end_time: "18:00"
|
||||
days: ["monday", "tuesday", "wednesday", "thursday", "friday"]
|
||||
timezone: "UTC"
|
||||
applications: ["admin_dashboard", "financial_systems"]
|
||||
```
|
||||
|
||||
#### IP-Based Access Control
|
||||
|
||||
```yaml
|
||||
# Geographic/Network access restrictions
|
||||
policies:
|
||||
- name: "Office Network Only"
|
||||
type: "source_ip"
|
||||
parameters:
|
||||
cidr: ["10.0.0.0/8", "192.168.0.0/16"]
|
||||
applications: ["admin_*", "backup_*"]
|
||||
|
||||
- name: "Block High-Risk Countries"
|
||||
type: "geoip"
|
||||
parameters:
|
||||
countries: ["CN", "RU", "KP"]
|
||||
action: "deny"
|
||||
applications: ["*"]
|
||||
```
|
||||
|
||||
## Layer 3: Container Security
|
||||
|
||||
### Rootless Container Architecture
|
||||
|
||||
#### Security Benefits of Rootless Podman
|
||||
|
||||
```bash
|
||||
# Rootless container verification
|
||||
ssh root@your-vps "sudo -u authentik podman info | grep -A10 'security'"
|
||||
|
||||
# User namespace mapping
|
||||
ssh root@your-vps "sudo -u authentik cat /proc/self/uid_map"
|
||||
ssh root@your-vps "sudo -u authentik cat /proc/self/gid_map"
|
||||
|
||||
# Process tree verification (containers run as unprivileged user)
|
||||
ssh root@your-vps "ps aux | grep -E '(authentik|gitea)'"
|
||||
```
|
||||
|
||||
#### Container User Security
|
||||
|
||||
```ini
|
||||
# Container configuration with security
|
||||
[Container]
|
||||
# Run as specific UID/GID (not root)
|
||||
User=963:963
|
||||
|
||||
# Preserve supplementary groups for socket access
|
||||
Annotation=run.oci.keep_original_groups=1
|
||||
|
||||
# Minimal capabilities
|
||||
AddCapability=IPC_OWNER
|
||||
DropCapability=ALL
|
||||
|
||||
# Security labels
|
||||
SecurityLabelDisable=true
|
||||
SecurityLabelType=container_t
|
||||
```
|
||||
|
||||
### Container Isolation
|
||||
|
||||
#### Filesystem Security
|
||||
|
||||
```yaml
|
||||
# Read-only root filesystem where possible
|
||||
security_settings:
|
||||
read_only_root_fs: true
|
||||
temp_fs_mounts:
|
||||
- "/tmp:rw,noexec,nosuid,size=100M"
|
||||
- "/var/tmp:rw,noexec,nosuid,size=100M"
|
||||
|
||||
# Minimal volume mounts
|
||||
volume_mounts:
|
||||
- "/opt/authentik/data:/data:Z" # SELinux label
|
||||
- "/opt/authentik/media:/media:Z"
|
||||
- "/var/run/postgresql:/var/run/postgresql:Z"
|
||||
- "/var/run/valkey:/var/run/valkey:Z"
|
||||
```
|
||||
|
||||
#### Resource Limits
|
||||
|
||||
```ini
|
||||
# systemd resource controls
|
||||
[Service]
|
||||
# Memory limits
|
||||
MemoryMax=1G
|
||||
MemorySwapMax=0
|
||||
|
||||
# CPU limits
|
||||
CPUQuota=200% # 2 CPU cores max
|
||||
|
||||
# Process limits
|
||||
TasksMax=100
|
||||
LimitNOFILE=1024
|
||||
|
||||
# I/O limits
|
||||
IODeviceWriteBandwidthMax=/dev/sda 50M
|
||||
```
|
||||
|
||||
### SELinux Security
|
||||
|
||||
#### Container Labeling
|
||||
|
||||
```bash
|
||||
# Verify SELinux labels on container volumes
|
||||
ssh root@your-vps "ls -Z /var/run/postgresql/"
|
||||
ssh root@your-vps "ls -Z /opt/authentik/"
|
||||
|
||||
# Check container SELinux context
|
||||
ssh root@your-vps "sudo -u authentik podman exec authentik-server cat /proc/self/attr/current"
|
||||
|
||||
# SELinux audit logs
|
||||
ssh root@your-vps "ausearch -m AVC -ts recent"
|
||||
```
|
||||
|
||||
#### Custom SELinux Policies
|
||||
|
||||
```bash
|
||||
# Generate custom SELinux policy for containers
|
||||
ssh root@your-vps "audit2allow -a -m rick_containers"
|
||||
|
||||
# Apply custom policy
|
||||
ssh root@your-vps "semodule -i rick_containers.pp"
|
||||
```
|
||||
|
||||
## Layer 4: Database & Cache Security
|
||||
|
||||
### Unix Socket Security Model
|
||||
|
||||
#### Socket File Permissions
|
||||
|
||||
```bash
|
||||
# Verify socket permissions
|
||||
ssh root@your-vps "ls -la /var/run/postgresql/"
|
||||
# Should show: srwxrwx--- postgres postgres .s.PGSQL.5432
|
||||
|
||||
ssh root@your-vps "ls -la /var/run/valkey/"
|
||||
# Should show: srwxrwx--- valkey valkey valkey.sock
|
||||
|
||||
# Verify group access
|
||||
ssh root@your-vps "groups authentik"
|
||||
# Should include: postgres valkey
|
||||
```
|
||||
|
||||
#### Network Isolation
|
||||
|
||||
```yaml
|
||||
# Database configuration (no network exposure)
|
||||
postgresql_config:
|
||||
listen_addresses: '' # Unix sockets only
|
||||
port: 0 # Disable TCP port
|
||||
unix_socket_directories: '/var/run/postgresql'
|
||||
unix_socket_permissions: 0770
|
||||
|
||||
valkey_config:
|
||||
bind: '' # No network binding
|
||||
port: 0 # Disable TCP port
|
||||
unixsocket: '/var/run/valkey/valkey.sock'
|
||||
unixsocketperm: 770
|
||||
```
|
||||
|
||||
### Database Security Hardening
|
||||
|
||||
#### PostgreSQL Security
|
||||
|
||||
```sql
|
||||
-- Database security configuration
|
||||
-- Remove public schema permissions
|
||||
REVOKE ALL ON SCHEMA public FROM PUBLIC;
|
||||
|
||||
-- Create application-specific schemas
|
||||
CREATE SCHEMA authentik AUTHORIZATION authentik;
|
||||
CREATE SCHEMA gitea AUTHORIZATION gitea;
|
||||
|
||||
-- Row-level security (if needed)
|
||||
ALTER TABLE authentik.sensitive_data ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY user_data_policy ON authentik.sensitive_data
|
||||
FOR ALL TO authentik USING (user_id = current_setting('app.user_id'));
|
||||
|
||||
-- Audit logging
|
||||
CREATE EXTENSION IF NOT EXISTS pgaudit;
|
||||
ALTER SYSTEM SET pgaudit.log = 'all';
|
||||
```
|
||||
|
||||
#### Database Access Monitoring
|
||||
|
||||
```bash
|
||||
# Monitor database connections
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT datname, usename, application_name, client_addr FROM pg_stat_activity;'"
|
||||
|
||||
# Check for suspicious queries
|
||||
ssh root@your-vps "sudo -u postgres psql -h /var/run/postgresql -c 'SELECT query, query_start, state FROM pg_stat_activity WHERE state != '\''idle'\'';'"
|
||||
|
||||
# Review authentication logs
|
||||
ssh root@your-vps "grep -i 'authentication\|connection' /var/log/postgresql/postgresql.log"
|
||||
```
|
||||
|
||||
### Cache Security
|
||||
|
||||
#### Valkey/Redis Security Configuration
|
||||
|
||||
```bash
|
||||
# Valkey security settings
|
||||
CONFIG SET requirepass "strong_password"
|
||||
CONFIG SET rename-command FLUSHDB ""
|
||||
CONFIG SET rename-command FLUSHALL ""
|
||||
CONFIG SET rename-command DEBUG ""
|
||||
CONFIG SET rename-command CONFIG "CONFIG_b3a0f6c8"
|
||||
|
||||
# Disable dangerous commands
|
||||
CONFIG SET protected-mode yes
|
||||
CONFIG SET save "" # Disable automatic snapshots
|
||||
```
|
||||
|
||||
#### Cache Access Control
|
||||
|
||||
```bash
|
||||
# Verify cache authentication
|
||||
ssh root@your-vps "redis-cli -s /var/run/valkey/valkey.sock -a \$VALKEY_PASSWORD ping"
|
||||
|
||||
# Monitor cache operations
|
||||
ssh root@your-vps "redis-cli -s /var/run/valkey/valkey.sock -a \$VALKEY_PASSWORD monitor"
|
||||
|
||||
# Check cache configuration
|
||||
ssh root@your-vps "redis-cli -s /var/run/valkey/valkey.sock -a \$VALKEY_PASSWORD CONFIG GET '*'"
|
||||
```
|
||||
|
||||
## Layer 5: Application Security
|
||||
|
||||
### Secret Management
|
||||
|
||||
#### Ansible Vault Security
|
||||
|
||||
```yaml
|
||||
# Vault encryption verification
|
||||
vault_security:
|
||||
encryption_method: "AES256"
|
||||
key_derivation: "PBKDF2"
|
||||
vault_password_source: "prompt" # Never store in files
|
||||
|
||||
# Vault best practices
|
||||
vault_practices:
|
||||
- rotate_vault_password: "quarterly"
|
||||
- separate_vault_files: "by_environment"
|
||||
- backup_encrypted_vaults: "securely"
|
||||
- audit_vault_access: "regularly"
|
||||
```
|
||||
|
||||
#### Environment Variable Security
|
||||
|
||||
```bash
|
||||
# Verify secrets are not in process environment
|
||||
ssh root@your-vps "sudo -u authentik cat /proc/\$(pgrep -f authentik-server)/environ | tr '\0' '\n' | grep -v SECRET"
|
||||
|
||||
# Check for secrets in logs
|
||||
ssh root@your-vps "journalctl --user -M authentik@ -u authentik-server | grep -i 'password\|secret\|token'"
|
||||
```
|
||||
|
||||
### Secure Headers and Middleware
|
||||
|
||||
#### Application-Level Security Headers
|
||||
|
||||
```python
|
||||
# Example application security middleware
|
||||
security_middleware = {
|
||||
'SECURE_BROWSER_XSS_FILTER': True,
|
||||
'SECURE_CONTENT_TYPE_NOSNIFF': True,
|
||||
'SECURE_HSTS_SECONDS': 31536000,
|
||||
'SECURE_HSTS_INCLUDE_SUBDOMAINS': True,
|
||||
'SECURE_HSTS_PRELOAD': True,
|
||||
'SECURE_REDIRECT_EXEMPT': [],
|
||||
'SECURE_SSL_REDIRECT': True,
|
||||
'SESSION_COOKIE_SECURE': True,
|
||||
'SESSION_COOKIE_HTTPONLY': True,
|
||||
'SESSION_COOKIE_SAMESITE': 'Strict',
|
||||
'CSRF_COOKIE_SECURE': True,
|
||||
'X_FRAME_OPTIONS': 'DENY'
|
||||
}
|
||||
```
|
||||
|
||||
#### Content Security Policy
|
||||
|
||||
```http
|
||||
# Strict CSP for web applications
|
||||
Content-Security-Policy: default-src 'self';
|
||||
script-src 'self' 'unsafe-inline' https://cdn.example.com;
|
||||
style-src 'self' 'unsafe-inline';
|
||||
img-src 'self' data: https:;
|
||||
font-src 'self' https://fonts.gstatic.com;
|
||||
connect-src 'self' https://api.example.com;
|
||||
frame-ancestors 'none';
|
||||
base-uri 'self';
|
||||
form-action 'self'
|
||||
```
|
||||
|
||||
### Audit Logging and Monitoring
|
||||
|
||||
#### System-Wide Audit Configuration
|
||||
|
||||
```bash
|
||||
# auditd configuration for security events
|
||||
auditctl -w /etc/passwd -p wa -k user_modification
|
||||
auditctl -w /etc/shadow -p wa -k password_modification
|
||||
auditctl -w /opt/authentik -p wa -k authentik_access
|
||||
auditctl -w /var/run/postgresql -p wa -k database_access
|
||||
auditctl -w /var/run/valkey -p wa -k cache_access
|
||||
|
||||
# Monitor systemd service changes
|
||||
auditctl -w /etc/systemd/system -p wa -k service_modification
|
||||
auditctl -w /home/*/.*config/containers/systemd -p wa -k container_modification
|
||||
```
|
||||
|
||||
#### Application Audit Logging
|
||||
|
||||
```yaml
|
||||
# Application-level audit events
|
||||
audit_events:
|
||||
authentication:
|
||||
- user_login_success
|
||||
- user_login_failure
|
||||
- password_change
|
||||
- mfa_enrollment
|
||||
- session_timeout
|
||||
|
||||
authorization:
|
||||
- access_granted
|
||||
- access_denied
|
||||
- privilege_escalation
|
||||
- policy_violation
|
||||
|
||||
data_access:
|
||||
- sensitive_data_access
|
||||
- data_export
|
||||
- configuration_change
|
||||
- backup_access
|
||||
```
|
||||
|
||||
### Security Monitoring and Alerting
|
||||
|
||||
#### Real-Time Security Monitoring
|
||||
|
||||
```bash
|
||||
# Security monitoring scripts
|
||||
#!/bin/bash
|
||||
# security-monitor.sh
|
||||
|
||||
# Monitor failed authentication attempts
|
||||
FAILED_LOGINS=$(grep "Failed password" /var/log/auth.log | wc -l)
|
||||
if [ $FAILED_LOGINS -gt 10 ]; then
|
||||
echo "ALERT: High number of failed login attempts: $FAILED_LOGINS"
|
||||
fi
|
||||
|
||||
# Monitor unusual database connections
|
||||
DB_CONNECTIONS=$(sudo -u postgres psql -h /var/run/postgresql -t -c "SELECT count(*) FROM pg_stat_activity WHERE application_name NOT IN ('authentik', 'gitea');")
|
||||
if [ $DB_CONNECTIONS -gt 5 ]; then
|
||||
echo "ALERT: Unusual database connections: $DB_CONNECTIONS"
|
||||
fi
|
||||
|
||||
# Monitor container security violations
|
||||
SELINUX_VIOLATIONS=$(ausearch -m AVC -ts recent 2>/dev/null | wc -l)
|
||||
if [ $SELINUX_VIOLATIONS -gt 0 ]; then
|
||||
echo "ALERT: SELinux violations detected: $SELINUX_VIOLATIONS"
|
||||
fi
|
||||
```
|
||||
|
||||
#### Log Aggregation and Analysis
|
||||
|
||||
```yaml
|
||||
# Log analysis configuration
|
||||
log_analysis:
|
||||
sources:
|
||||
- /var/log/auth.log # SSH and system authentication
|
||||
- /var/log/audit/audit.log # System audit events
|
||||
- /opt/authentik/logs/ # Application logs
|
||||
- /var/log/caddy/ # Web server logs
|
||||
- /var/log/postgresql/ # Database logs
|
||||
|
||||
alerts:
|
||||
- pattern: "Failed password.*from.*"
|
||||
threshold: 5
|
||||
timeframe: "5m"
|
||||
action: "block_ip"
|
||||
|
||||
- pattern: "AUTHENTICATION_FAILED.*authentik"
|
||||
threshold: 10
|
||||
timeframe: "10m"
|
||||
action: "alert_admin"
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Regular Security Maintenance
|
||||
|
||||
#### Security Updates
|
||||
|
||||
```bash
|
||||
# Automated security updates (weekly)
|
||||
#!/bin/bash
|
||||
# security-updates.sh
|
||||
|
||||
# System package updates
|
||||
pacman -Syu --noconfirm
|
||||
|
||||
# Container image updates
|
||||
for user in authentik gitea; do
|
||||
sudo -u $user podman auto-update
|
||||
done
|
||||
|
||||
# Certificate renewal check
|
||||
systemctl reload caddy
|
||||
|
||||
# Restart services if security updates require it
|
||||
if [ -f /var/run/reboot-required ]; then
|
||||
systemctl reboot
|
||||
fi
|
||||
```
|
||||
|
||||
#### Security Auditing
|
||||
|
||||
```bash
|
||||
# Monthly security audit checklist
|
||||
#!/bin/bash
|
||||
# security-audit.sh
|
||||
|
||||
echo "=== Security Audit Report $(date) ==="
|
||||
|
||||
# Check for unauthorized users
|
||||
echo "Checking system users:"
|
||||
awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd
|
||||
|
||||
# Check sudo access
|
||||
echo "Checking sudo access:"
|
||||
grep -v '^#' /etc/sudoers
|
||||
|
||||
# Check listening services
|
||||
echo "Checking listening services:"
|
||||
netstat -tulpn | grep LISTEN
|
||||
|
||||
# Check file permissions on critical files
|
||||
echo "Checking critical file permissions:"
|
||||
ls -la /etc/shadow /etc/passwd /etc/ssh/sshd_config
|
||||
|
||||
# Check for SUID/SGID files
|
||||
echo "Checking SUID/SGID files:"
|
||||
find /usr -perm /6000 -type f 2>/dev/null
|
||||
|
||||
# Check container security
|
||||
echo "Checking container security:"
|
||||
for user in authentik gitea; do
|
||||
echo "User: $user"
|
||||
sudo -u $user podman ps --format "table {{.Names}}\t{{.RunningFor}}\t{{.Status}}"
|
||||
done
|
||||
|
||||
# Check database security
|
||||
echo "Checking database connections:"
|
||||
sudo -u postgres psql -h /var/run/postgresql -c "SELECT datname, usename, client_addr FROM pg_stat_activity;"
|
||||
```
|
||||
|
||||
### Incident Response Procedures
|
||||
|
||||
#### Security Incident Response Plan
|
||||
|
||||
```yaml
|
||||
incident_response:
|
||||
detection:
|
||||
- automated_alerts: "fail2ban, audit logs, monitoring"
|
||||
- manual_review: "daily log review, weekly security audit"
|
||||
|
||||
assessment:
|
||||
- severity_levels: ["low", "medium", "high", "critical"]
|
||||
- response_time:
|
||||
critical: "15 minutes"
|
||||
high: "1 hour"
|
||||
medium: "4 hours"
|
||||
low: "24 hours"
|
||||
|
||||
containment:
|
||||
- isolate_affected_systems: "fail2ban, iptables blocks"
|
||||
- preserve_evidence: "log snapshots, memory dumps"
|
||||
- maintain_operations: "failover procedures"
|
||||
|
||||
eradication:
|
||||
- remove_threats: "malware removal, account cleanup"
|
||||
- patch_vulnerabilities: "system updates, configuration fixes"
|
||||
- strengthen_defenses: "additional monitoring, access controls"
|
||||
|
||||
recovery:
|
||||
- restore_services: "service restart, data restoration"
|
||||
- monitor_operations: "enhanced monitoring period"
|
||||
- validate_security: "penetration testing, vulnerability scans"
|
||||
```
|
||||
|
||||
#### Emergency Response Commands
|
||||
|
||||
```bash
|
||||
# Emergency security response toolkit
|
||||
#!/bin/bash
|
||||
# emergency-response.sh
|
||||
|
||||
case "$1" in
|
||||
"isolate")
|
||||
# Emergency network isolation
|
||||
iptables -I INPUT -j DROP
|
||||
iptables -I OUTPUT -j DROP
|
||||
echo "System isolated from network"
|
||||
;;
|
||||
|
||||
"lockdown")
|
||||
# Lock all user accounts except emergency admin
|
||||
for user in $(cat /etc/passwd | cut -d: -f1); do
|
||||
if [ "$user" != "root" ] && [ "$user" != "emergency" ]; then
|
||||
usermod -L $user
|
||||
fi
|
||||
done
|
||||
echo "All user accounts locked"
|
||||
;;
|
||||
|
||||
"audit")
|
||||
# Emergency audit collection
|
||||
mkdir -p /tmp/emergency-audit
|
||||
cp -r /var/log/* /tmp/emergency-audit/
|
||||
journalctl --no-pager > /tmp/emergency-audit/journalctl.log
|
||||
netstat -tulpn > /tmp/emergency-audit/network.log
|
||||
ps auxf > /tmp/emergency-audit/processes.log
|
||||
echo "Audit data collected in /tmp/emergency-audit/"
|
||||
;;
|
||||
|
||||
"restore")
|
||||
# Restore from isolation
|
||||
iptables -F
|
||||
iptables -P INPUT ACCEPT
|
||||
iptables -P OUTPUT ACCEPT
|
||||
echo "Network access restored - apply proper firewall rules"
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
## Compliance and Standards
|
||||
|
||||
### Security Standards Alignment
|
||||
|
||||
#### CIS (Center for Internet Security) Benchmarks
|
||||
|
||||
```yaml
|
||||
cis_compliance:
|
||||
level_1_controls:
|
||||
- filesystem_configuration: "implemented"
|
||||
- software_updates: "automated"
|
||||
- secure_boot_settings: "implemented"
|
||||
- additional_process_hardening: "implemented"
|
||||
- mandatory_access_controls: "selinux_enforcing"
|
||||
|
||||
level_2_controls:
|
||||
- address_space_layout_randomization: "enabled"
|
||||
- prelink_disabled: "implemented"
|
||||
- activate_gpg_check: "implemented"
|
||||
- disable_automounting: "implemented"
|
||||
```
|
||||
|
||||
#### NIST Cybersecurity Framework
|
||||
|
||||
```yaml
|
||||
nist_framework:
|
||||
identify:
|
||||
- asset_management: "complete inventory of systems and services"
|
||||
- risk_assessment: "quarterly risk assessments"
|
||||
|
||||
protect:
|
||||
- access_control: "authentik SSO with MFA"
|
||||
- awareness_training: "security documentation and procedures"
|
||||
- data_security: "encryption at rest and in transit"
|
||||
|
||||
detect:
|
||||
- anomalies_events: "automated monitoring and alerting"
|
||||
- security_monitoring: "continuous monitoring of security events"
|
||||
|
||||
respond:
|
||||
- response_planning: "documented incident response procedures"
|
||||
- communications: "stakeholder notification procedures"
|
||||
|
||||
recover:
|
||||
- recovery_planning: "documented recovery procedures"
|
||||
- improvements: "lessons learned and security enhancements"
|
||||
```
|
||||
|
||||
### Documentation and Training
|
||||
|
||||
#### Security Documentation
|
||||
|
||||
```yaml
|
||||
required_documentation:
|
||||
policies:
|
||||
- information_security_policy
|
||||
- access_control_policy
|
||||
- incident_response_policy
|
||||
- backup_recovery_policy
|
||||
|
||||
procedures:
|
||||
- user_onboarding_offboarding
|
||||
- security_incident_response
|
||||
- vulnerability_management
|
||||
- change_management
|
||||
|
||||
technical_guides:
|
||||
- system_hardening_guide
|
||||
- application_security_guide
|
||||
- network_security_guide
|
||||
- monitoring_alerting_guide
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This comprehensive security hardening guide implements defense-in-depth security across all layers of the rick-infra stack, emphasizing the security benefits of native database services, Unix socket IPC, rootless containers, and centralized authentication.
|
||||
|
||||
## References
|
||||
|
||||
- **[Authentication Architecture](authentication-architecture.md)** - Detailed authentication and authorization
|
||||
- **[Architecture Decisions](architecture-decisions.md)** - Security-focused architectural choices
|
||||
- **[Authentik Deployment Guide](authentik-deployment-guide.md)** - Secure authentication deployment
|
||||
- **[Service Integration Guide](service-integration-guide.md)** - Secure service integration patterns
|
||||
|
||||
@@ -301,6 +301,499 @@ If you get permission denied errors:
|
||||
- Check service logs for connection errors
|
||||
- Verify group memberships after user changes
|
||||
|
||||
## Authentication Integration with Authentik
|
||||
|
||||
### Overview
|
||||
|
||||
All services in rick-infra should integrate with Authentik for centralized authentication and authorization. This section covers the authentication integration patterns available.
|
||||
|
||||
### Authentication Integration Patterns
|
||||
|
||||
#### Pattern 1: Forward Authentication (Recommended)
|
||||
|
||||
**Use Case**: HTTP services that don't need to handle authentication internally
|
||||
|
||||
**Benefits**:
|
||||
- No application code changes required
|
||||
- Consistent authentication across all services
|
||||
- Centralized session management
|
||||
- Service receives user identity via HTTP headers
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```yaml
|
||||
# Service role task to deploy Caddy configuration
|
||||
- name: Deploy service Caddy configuration with Authentik forward auth
|
||||
template:
|
||||
src: myservice.caddy.j2
|
||||
dest: "{{ caddy_sites_enabled_dir }}/myservice.caddy"
|
||||
owner: root
|
||||
group: "{{ caddy_user }}"
|
||||
mode: '0644'
|
||||
backup: true
|
||||
notify: reload caddy
|
||||
tags: [caddy, auth]
|
||||
```
|
||||
|
||||
```caddyfile
|
||||
# templates/myservice.caddy.j2
|
||||
{{ service_domain }} {
|
||||
# Forward authentication to Authentik
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
# Your service backend
|
||||
reverse_proxy {{ service_backend }}
|
||||
|
||||
# Optional: Restrict access by group
|
||||
@not_authorized {
|
||||
not header Remote-Groups "*{{ required_group }}*"
|
||||
}
|
||||
respond @not_authorized "Access denied: insufficient privileges" 403
|
||||
}
|
||||
```
|
||||
|
||||
**Service Code Example** (Python Flask):
|
||||
```python
|
||||
# Application receives authentication information via headers
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/dashboard')
|
||||
def dashboard():
|
||||
# Extract user information from headers (provided by Authentik)
|
||||
username = request.headers.get('Remote-User')
|
||||
user_name = request.headers.get('Remote-Name')
|
||||
user_email = request.headers.get('Remote-Email')
|
||||
user_groups = request.headers.get('Remote-Groups', '').split(',')
|
||||
|
||||
# Authorization based on groups
|
||||
if not username:
|
||||
return "Authentication required", 401
|
||||
|
||||
if 'service_users' not in user_groups:
|
||||
return "Access denied: insufficient privileges", 403
|
||||
|
||||
return render_template('dashboard.html',
|
||||
username=username,
|
||||
name=user_name,
|
||||
groups=user_groups)
|
||||
|
||||
@app.route('/admin')
|
||||
def admin():
|
||||
user_groups = request.headers.get('Remote-Groups', '').split(',')
|
||||
|
||||
if 'admins' not in user_groups:
|
||||
return "Admin access required", 403
|
||||
|
||||
return render_template('admin.html')
|
||||
```
|
||||
|
||||
#### Pattern 2: OAuth2/OIDC Integration
|
||||
|
||||
**Use Case**: Applications that can implement OAuth2 client functionality
|
||||
|
||||
**Benefits**:
|
||||
- Fine-grained scope control
|
||||
- API access tokens
|
||||
- Better integration with application user models
|
||||
- Support for mobile/SPA applications
|
||||
|
||||
**Service Configuration**:
|
||||
|
||||
```yaml
|
||||
# Service environment configuration
|
||||
oauth2_config:
|
||||
client_id: "{{ service_oauth_client_id }}"
|
||||
client_secret: "{{ vault_service_oauth_secret }}"
|
||||
discovery_url: "https://auth.jnss.me/application/o/{{ service_slug }}/.well-known/openid_configuration"
|
||||
scopes: "openid email profile groups"
|
||||
redirect_uri: "https://{{ service_domain }}/oauth/callback"
|
||||
```
|
||||
|
||||
```python
|
||||
# OAuth2 integration example (Python)
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
|
||||
oauth = OAuth(app)
|
||||
oauth.register(
|
||||
'authentik',
|
||||
client_id=app.config['OAUTH_CLIENT_ID'],
|
||||
client_secret=app.config['OAUTH_CLIENT_SECRET'],
|
||||
server_metadata_url=app.config['OAUTH_DISCOVERY_URL'],
|
||||
client_kwargs={
|
||||
'scope': 'openid email profile groups'
|
||||
}
|
||||
)
|
||||
|
||||
@app.route('/login')
|
||||
def login():
|
||||
redirect_uri = url_for('oauth_callback', _external=True)
|
||||
return oauth.authentik.authorize_redirect(redirect_uri)
|
||||
|
||||
@app.route('/oauth/callback')
|
||||
def oauth_callback():
|
||||
token = oauth.authentik.authorize_access_token()
|
||||
user_info = oauth.authentik.parse_id_token(token)
|
||||
|
||||
# Store user information in session
|
||||
session['user'] = {
|
||||
'id': user_info['sub'],
|
||||
'username': user_info['preferred_username'],
|
||||
'email': user_info['email'],
|
||||
'name': user_info['name'],
|
||||
'groups': user_info.get('groups', [])
|
||||
}
|
||||
|
||||
return redirect('/dashboard')
|
||||
```
|
||||
|
||||
#### Pattern 3: API-Only Authentication
|
||||
|
||||
**Use Case**: REST APIs, microservices, machine-to-machine communication
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```python
|
||||
# API service with token validation
|
||||
import requests
|
||||
from flask import Flask, request, jsonify
|
||||
|
||||
def validate_token(token):
|
||||
"""Validate Bearer token with Authentik introspection endpoint"""
|
||||
try:
|
||||
response = requests.post(
|
||||
'https://auth.jnss.me/application/o/introspect/',
|
||||
headers={
|
||||
'Authorization': f'Bearer {app.config["API_CLIENT_TOKEN"]}'
|
||||
},
|
||||
data={'token': token},
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return None
|
||||
except Exception as e:
|
||||
app.logger.error(f"Token validation error: {e}")
|
||||
return None
|
||||
|
||||
@app.route('/api/data')
|
||||
def api_data():
|
||||
auth_header = request.headers.get('Authorization')
|
||||
|
||||
if not auth_header or not auth_header.startswith('Bearer '):
|
||||
return jsonify({'error': 'Missing or invalid Authorization header'}), 401
|
||||
|
||||
token = auth_header[7:] # Remove 'Bearer ' prefix
|
||||
token_info = validate_token(token)
|
||||
|
||||
if not token_info or not token_info.get('active'):
|
||||
return jsonify({'error': 'Invalid or expired token'}), 401
|
||||
|
||||
# Extract user information from token
|
||||
username = token_info.get('username')
|
||||
scope = token_info.get('scope', '').split()
|
||||
|
||||
# Check required scope
|
||||
if 'api:read' not in scope:
|
||||
return jsonify({'error': 'Insufficient permissions'}), 403
|
||||
|
||||
return jsonify({
|
||||
'message': f'Hello {username}',
|
||||
'data': 'Your API response data here'
|
||||
})
|
||||
```
|
||||
|
||||
### Authentik Provider Configuration
|
||||
|
||||
For each service integration, configure the appropriate provider in Authentik:
|
||||
|
||||
#### Forward Auth Provider (Pattern 1)
|
||||
|
||||
```yaml
|
||||
# Authentik provider configuration (via admin interface)
|
||||
provider_config:
|
||||
name: "{{ service_name }} Forward Auth"
|
||||
type: "Proxy Provider"
|
||||
authorization_flow: "default-provider-authorization-implicit-consent"
|
||||
external_host: "https://{{ service_domain }}"
|
||||
internal_host: "http://localhost:{{ service_port }}"
|
||||
skip_path_regex: "^/(health|metrics|static).*"
|
||||
```
|
||||
|
||||
#### OAuth2 Provider (Pattern 2)
|
||||
|
||||
```yaml
|
||||
# Authentik OAuth2 provider configuration
|
||||
oauth_provider_config:
|
||||
name: "{{ service_name }} OAuth2"
|
||||
type: "OAuth2/OpenID Provider"
|
||||
authorization_flow: "default-provider-authorization-explicit-consent"
|
||||
client_type: "confidential"
|
||||
client_id: "{{ service_oauth_client_id }}"
|
||||
redirect_uris:
|
||||
- "https://{{ service_domain }}/oauth/callback"
|
||||
post_logout_redirect_uris:
|
||||
- "https://{{ service_domain }}/"
|
||||
```
|
||||
|
||||
#### API Provider (Pattern 3)
|
||||
|
||||
```yaml
|
||||
# Authentik API provider configuration
|
||||
api_provider_config:
|
||||
name: "{{ service_name }} API"
|
||||
type: "OAuth2/OpenID Provider"
|
||||
authorization_flow: "default-provider-authorization-implicit-consent"
|
||||
client_type: "confidential"
|
||||
client_id: "{{ service_api_client_id }}"
|
||||
include_claims_in_id_token: true
|
||||
issuer_mode: "per_provider"
|
||||
```
|
||||
|
||||
### Group-Based Authorization
|
||||
|
||||
#### Service-Specific Groups
|
||||
|
||||
```yaml
|
||||
# Create service-specific groups in Authentik
|
||||
service_groups:
|
||||
- name: "{{ service_name }}_users"
|
||||
description: "Users who can access {{ service_name }}"
|
||||
is_superuser: false
|
||||
|
||||
- name: "{{ service_name }}_admins"
|
||||
description: "Administrators for {{ service_name }}"
|
||||
is_superuser: false
|
||||
parent: "{{ service_name }}_users"
|
||||
|
||||
- name: "{{ service_name }}_readonly"
|
||||
description: "Read-only access to {{ service_name }}"
|
||||
is_superuser: false
|
||||
parent: "{{ service_name }}_users"
|
||||
```
|
||||
|
||||
#### Policy-Based Access Control
|
||||
|
||||
```yaml
|
||||
# Authentik policies for service access
|
||||
service_policies:
|
||||
- name: "{{ service_name }} Group Access"
|
||||
policy_type: "Group Membership Policy"
|
||||
groups: ["{{ service_name }}_users"]
|
||||
|
||||
- name: "{{ service_name }} Business Hours"
|
||||
policy_type: "Time-based Policy"
|
||||
parameters:
|
||||
start_time: "08:00"
|
||||
end_time: "18:00"
|
||||
days: ["monday", "tuesday", "wednesday", "thursday", "friday"]
|
||||
|
||||
- name: "{{ service_name }} IP Restriction"
|
||||
policy_type: "Source IP Policy"
|
||||
parameters:
|
||||
cidr: "10.0.0.0/8"
|
||||
```
|
||||
|
||||
### Service Role Template with Authentication
|
||||
|
||||
Here's a complete service role template that includes authentication integration:
|
||||
|
||||
```yaml
|
||||
# roles/myservice/defaults/main.yml
|
||||
---
|
||||
# Service configuration
|
||||
service_name: "myservice"
|
||||
service_domain: "myservice.jnss.me"
|
||||
service_port: 8080
|
||||
service_backend: "localhost:{{ service_port }}"
|
||||
|
||||
# Authentication configuration
|
||||
auth_enabled: true
|
||||
auth_pattern: "forward_auth" # forward_auth, oauth2, api_only
|
||||
required_group: "myservice_users"
|
||||
|
||||
# OAuth2 configuration (if auth_pattern is oauth2)
|
||||
oauth_client_id: "{{ service_name }}-oauth-client"
|
||||
oauth_client_secret: "{{ vault_myservice_oauth_secret }}"
|
||||
|
||||
# Dependencies
|
||||
postgresql_db_name: "{{ service_name }}"
|
||||
valkey_db_number: 2
|
||||
```
|
||||
|
||||
```yaml
|
||||
# roles/myservice/tasks/main.yml
|
||||
---
|
||||
- name: Create service user and setup
|
||||
include_tasks: user.yml
|
||||
tags: [user, setup]
|
||||
|
||||
- name: Setup database access
|
||||
include_tasks: database.yml
|
||||
tags: [database, setup]
|
||||
|
||||
- name: Setup cache access
|
||||
include_tasks: cache.yml
|
||||
tags: [cache, setup]
|
||||
|
||||
- name: Deploy service configuration
|
||||
template:
|
||||
src: myservice.env.j2
|
||||
dest: "{{ service_home }}/.env"
|
||||
owner: "{{ service_user }}"
|
||||
group: "{{ service_group }}"
|
||||
mode: '0600'
|
||||
tags: [config]
|
||||
|
||||
- name: Deploy container configuration
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ service_quadlet_dir }}/{{ item.dest }}"
|
||||
owner: "{{ service_user }}"
|
||||
group: "{{ service_group }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'myservice.pod', dest: 'myservice.pod' }
|
||||
- { src: 'myservice.container', dest: 'myservice.container' }
|
||||
become: true
|
||||
become_user: "{{ service_user }}"
|
||||
notify:
|
||||
- reload systemd user
|
||||
- restart myservice
|
||||
tags: [containers]
|
||||
|
||||
- name: Deploy Caddy configuration with authentication
|
||||
template:
|
||||
src: myservice.caddy.j2
|
||||
dest: "{{ caddy_sites_enabled_dir }}/{{ service_name }}.caddy"
|
||||
owner: root
|
||||
group: "{{ caddy_user }}"
|
||||
mode: '0644'
|
||||
backup: true
|
||||
notify: reload caddy
|
||||
tags: [caddy, auth]
|
||||
when: auth_enabled
|
||||
|
||||
- name: Start and enable service
|
||||
systemd:
|
||||
name: "{{ service_name }}"
|
||||
enabled: true
|
||||
state: started
|
||||
scope: user
|
||||
daemon_reload: true
|
||||
become: true
|
||||
become_user: "{{ service_user }}"
|
||||
tags: [service]
|
||||
```
|
||||
|
||||
```caddyfile
|
||||
# roles/myservice/templates/myservice.caddy.j2
|
||||
{{ service_domain }} {
|
||||
{% if auth_enabled and auth_pattern == 'forward_auth' %}
|
||||
# Forward authentication to Authentik
|
||||
forward_auth https://auth.jnss.me {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
|
||||
}
|
||||
|
||||
{% if required_group %}
|
||||
# Restrict access to specific group
|
||||
@not_authorized {
|
||||
not header Remote-Groups "*{{ required_group }}*"
|
||||
}
|
||||
respond @not_authorized "Access denied: {{ required_group }} group required" 403
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# Service backend
|
||||
reverse_proxy {{ service_backend }}
|
||||
|
||||
# Health check endpoint (no auth required)
|
||||
handle /health {
|
||||
reverse_proxy {{ service_backend }}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
|
||||
#### Authentication Integration Tests
|
||||
|
||||
```yaml
|
||||
# Service authentication tests
|
||||
authentication_tests:
|
||||
- name: "Test unauthenticated access denied"
|
||||
uri: "https://{{ service_domain }}/"
|
||||
method: "GET"
|
||||
expected_status: [302, 401] # Redirect to login or unauthorized
|
||||
|
||||
- name: "Test authenticated access allowed"
|
||||
uri: "https://{{ service_domain }}/"
|
||||
method: "GET"
|
||||
headers:
|
||||
Cookie: "authentik_session={{ valid_session_cookie }}"
|
||||
expected_status: [200]
|
||||
|
||||
- name: "Test group authorization"
|
||||
uri: "https://{{ service_domain }}/admin"
|
||||
method: "GET"
|
||||
headers:
|
||||
Cookie: "authentik_session={{ admin_session_cookie }}"
|
||||
expected_status: [200]
|
||||
|
||||
- name: "Test insufficient privileges"
|
||||
uri: "https://{{ service_domain }}/admin"
|
||||
method: "GET"
|
||||
headers:
|
||||
Cookie: "authentik_session={{ user_session_cookie }}"
|
||||
expected_status: [403]
|
||||
```
|
||||
|
||||
#### Automated Testing Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# test-service-auth.sh
|
||||
|
||||
SERVICE_DOMAIN="myservice.jnss.me"
|
||||
|
||||
echo "Testing service authentication for $SERVICE_DOMAIN"
|
||||
|
||||
# Test 1: Unauthenticated access should redirect or deny
|
||||
echo "Test 1: Unauthenticated access"
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "https://$SERVICE_DOMAIN/")
|
||||
if [[ "$RESPONSE" == "302" || "$RESPONSE" == "401" ]]; then
|
||||
echo "✓ PASS: Unauthenticated access properly denied ($RESPONSE)"
|
||||
else
|
||||
echo "✗ FAIL: Unauthenticated access allowed ($RESPONSE)"
|
||||
fi
|
||||
|
||||
# Test 2: Health endpoint should be accessible
|
||||
echo "Test 2: Health endpoint access"
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "https://$SERVICE_DOMAIN/health")
|
||||
if [[ "$RESPONSE" == "200" ]]; then
|
||||
echo "✓ PASS: Health endpoint accessible"
|
||||
else
|
||||
echo "✗ FAIL: Health endpoint not accessible ($RESPONSE)"
|
||||
fi
|
||||
|
||||
# Test 3: Authentik forward auth endpoint exists
|
||||
echo "Test 3: Authentik forward auth endpoint"
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "https://auth.jnss.me/outpost.goauthentik.io/auth/caddy")
|
||||
if [[ "$RESPONSE" == "401" ]]; then
|
||||
echo "✓ PASS: Forward auth endpoint responding"
|
||||
else
|
||||
echo "✗ FAIL: Forward auth endpoint not responding correctly ($RESPONSE)"
|
||||
fi
|
||||
|
||||
echo "Authentication tests completed"
|
||||
```
|
||||
|
||||
## Example Integration
|
||||
|
||||
See the `authentik` role for a complete example of this pattern:
|
||||
@@ -310,3 +803,38 @@ See the `authentik` role for a complete example of this pattern:
|
||||
- **Documentation**: `roles/authentik/README.md`
|
||||
|
||||
This provides a working reference implementation for Unix socket integration.
|
||||
|
||||
## Authentication Integration Examples
|
||||
|
||||
For practical authentication integration examples, see:
|
||||
|
||||
- **[Authentication Architecture](authentication-architecture.md)** - Complete authentication patterns and examples
|
||||
- **[Authentik Deployment Guide](authentik-deployment-guide.md)** - Authentik-specific configuration
|
||||
- **[Architecture Decisions](architecture-decisions.md)** - Authentication model rationale
|
||||
|
||||
## Quick Start Checklist
|
||||
|
||||
When integrating a new service with rick-infra:
|
||||
|
||||
### Infrastructure Integration
|
||||
- [ ] Create dedicated system user for the service
|
||||
- [ ] Add user to `postgres` and `valkey` groups for database access
|
||||
- [ ] Configure Unix socket connections in service environment
|
||||
- [ ] Set up Quadlet container configuration with proper user/group settings
|
||||
- [ ] Test database and cache connectivity
|
||||
|
||||
### Authentication Integration
|
||||
- [ ] Choose authentication pattern (forward auth recommended for most services)
|
||||
- [ ] Create Caddy configuration with Authentik forward auth
|
||||
- [ ] Create Authentik provider and application configuration
|
||||
- [ ] Set up service-specific groups and policies in Authentik
|
||||
- [ ] Test authentication flow and authorization
|
||||
|
||||
### Deployment Integration
|
||||
- [ ] Add service role dependencies in `meta/main.yml`
|
||||
- [ ] Configure service in `site.yml` with appropriate tags
|
||||
- [ ] Set up vault variables for secrets
|
||||
- [ ] Deploy and verify service functionality
|
||||
- [ ] Add monitoring and backup procedures
|
||||
|
||||
This comprehensive integration approach ensures all services benefit from the security, performance, and operational advantages of the rick-infra architecture.
|
||||
@@ -303,3 +303,22 @@ This solution is:
|
||||
- ✅ **Secure**: Maintains container isolation where it matters
|
||||
- ✅ **Standard**: Uses documented Podman/OCI features
|
||||
|
||||
## Documentation References
|
||||
|
||||
### Comprehensive Guides
|
||||
- **[Authentik Deployment Guide](../../docs/authentik-deployment-guide.md)** - Complete step-by-step deployment instructions
|
||||
- **[Authentication Architecture](../../docs/authentication-architecture.md)** - High-level authentication strategy and integration patterns
|
||||
- **[Architecture Decisions](../../docs/architecture-decisions.md)** - Technical decision rationale and trade-offs
|
||||
- **[Security Hardening](../../docs/security-hardening.md)** - Multi-layer security implementation
|
||||
|
||||
### Integration Resources
|
||||
- **[Service Integration Guide](../../docs/service-integration-guide.md)** - How to integrate new services with authentik
|
||||
- **[Deployment Guide](../../docs/deployment-guide.md)** - Infrastructure deployment procedures
|
||||
- **[Caddy Configuration](../../docs/caddy-service-configuration.md)** - Reverse proxy and forward auth setup
|
||||
|
||||
### Quick Links
|
||||
- **Deployment**: For complete deployment procedures, see [Authentik Deployment Guide](../../docs/authentik-deployment-guide.md#step-by-step-deployment)
|
||||
- **Troubleshooting**: For comprehensive troubleshooting, see [Authentik Deployment Guide](../../docs/authentik-deployment-guide.md#troubleshooting-guide)
|
||||
- **Security Model**: For security architecture details, see [Architecture Decisions](../../docs/architecture-decisions.md#adr-004-forward-authentication-security-model)
|
||||
- **Service Integration**: For adding new services, see [Service Integration Guide](../../docs/service-integration-guide.md#authentication-integration-with-authentik)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ authentik_valkey_db: 1 # Use database 1 for Authentik
|
||||
|
||||
authentik_domain: "auth.jnss.me"
|
||||
authentik_http_port: 9000
|
||||
authentik_bind_address: "127.0.0.1"
|
||||
authentik_bind_address: "0.0.0.0"
|
||||
|
||||
# =================================================================
|
||||
# Authentik Core Configuration
|
||||
@@ -89,6 +89,17 @@ authentik_user_quadlet_dir: "{{ authentik_home }}/.config/containers/systemd"
|
||||
# User session variables (set dynamically during deployment)
|
||||
authentik_uid: ""
|
||||
|
||||
# =================================================================
|
||||
# User Namespace Configuration
|
||||
# =================================================================
|
||||
|
||||
# Subuid/subgid ranges for authentik user containers
|
||||
# Range: 200000-265535 (65536 IDs)
|
||||
authentik_subuid_start: 200000
|
||||
authentik_subuid_size: 65536
|
||||
authentik_subgid_start: 200000
|
||||
authentik_subgid_size: 65536
|
||||
|
||||
# =================================================================
|
||||
# Caddy Integration
|
||||
# =================================================================
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
---
|
||||
# Authentik Container Deployment - Podman Quadlets
|
||||
|
||||
- name: Deploy authentik environment file
|
||||
template:
|
||||
src: authentik.env.j2
|
||||
dest: "{{ authentik_home }}/.config/containers/authentik.env"
|
||||
owner: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
mode: '0600'
|
||||
notify: restart authentik pod
|
||||
|
||||
- name: Deploy authentik pod quadlet
|
||||
template:
|
||||
src: authentik.pod.j2
|
||||
dest: "{{ authentik_home }}/.config/containers/systemd/{{ authentik_pod_name }}.pod"
|
||||
owner: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
mode: '0644'
|
||||
notify:
|
||||
- reload user systemd for authentik
|
||||
- restart authentik pod
|
||||
|
||||
- name: Deploy authentik server container quadlet
|
||||
template:
|
||||
src: authentik-server.container.j2
|
||||
dest: "{{ authentik_home }}/.config/containers/systemd/authentik-server.container"
|
||||
owner: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
mode: '0644'
|
||||
notify:
|
||||
- reload user systemd for authentik
|
||||
- restart authentik pod
|
||||
|
||||
- name: Deploy authentik worker container quadlet
|
||||
template:
|
||||
src: authentik-worker.container.j2
|
||||
dest: "{{ authentik_home }}/.config/containers/systemd/authentik-worker.container"
|
||||
owner: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
mode: '0644'
|
||||
notify:
|
||||
- reload user systemd for authentik
|
||||
- restart authentik pod
|
||||
|
||||
- name: Reload user systemd to recognize quadlets
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
scope: user
|
||||
become: yes
|
||||
become_user: "{{ authentik_user }}"
|
||||
|
||||
- name: Enable and start authentik pod
|
||||
systemd:
|
||||
name: "{{ authentik_pod_name }}-pod"
|
||||
enabled: "{{ authentik_service_enabled }}"
|
||||
state: "{{ authentik_service_state }}"
|
||||
scope: user
|
||||
become: yes
|
||||
become_user: "{{ authentik_user }}"
|
||||
|
||||
- name: Wait for Authentik to be ready
|
||||
uri:
|
||||
url: "http://127.0.0.1:{{ authentik_http_port }}/if/flow/initial-setup/"
|
||||
method: GET
|
||||
status_code: [200, 302]
|
||||
retries: 30
|
||||
delay: 2
|
||||
when: authentik_service_state == "started"
|
||||
@@ -2,55 +2,9 @@
|
||||
# Authentik Authentication Role - Main Tasks
|
||||
# Self-contained deployment with Podman and Unix sockets
|
||||
|
||||
- name: Create authentik group
|
||||
group:
|
||||
name: "{{ authentik_group }}"
|
||||
system: true
|
||||
|
||||
- name: Create authentik system user
|
||||
user:
|
||||
name: "{{ authentik_user }}"
|
||||
system: true
|
||||
shell: /bin/bash
|
||||
home: "{{ authentik_home }}"
|
||||
create_home: true
|
||||
group: "{{ authentik_group }}"
|
||||
|
||||
- name: Create authentik directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "{{ authentik_home }}"
|
||||
- "{{ authentik_data_dir }}"
|
||||
- "{{ authentik_media_dir }}"
|
||||
- "{{ authentik_user_quadlet_dir }}"
|
||||
- "{{ authentik_log_dir }}"
|
||||
|
||||
|
||||
- name: Enable lingering for authentik user (services persist without login)
|
||||
command: loginctl enable-linger {{ authentik_user }}
|
||||
register: linger_result
|
||||
changed_when: linger_result.rc == 0
|
||||
|
||||
|
||||
|
||||
- name: Get authentik user UID and GID for container configuration
|
||||
shell: |
|
||||
echo "uid=$(id -u {{ authentik_user }})"
|
||||
echo "gid=$(id -g {{ authentik_user }})"
|
||||
register: authentik_user_info
|
||||
changed_when: false
|
||||
tags: [setup]
|
||||
|
||||
- name: Set authentik UID/GID facts for container templates
|
||||
set_fact:
|
||||
authentik_uid: "{{ authentik_user_info.stdout_lines[0] | regex_replace('uid=', '') }}"
|
||||
authentik_gid: "{{ authentik_user_info.stdout_lines[1] | regex_replace('gid=', '') }}"
|
||||
tags: [setup]
|
||||
- name: Setup authentik user and container namespaces
|
||||
include_tasks: user.yml
|
||||
tags: [user, setup]
|
||||
|
||||
- name: Setup database access and permissions
|
||||
include_tasks: database.yml
|
||||
@@ -60,6 +14,26 @@
|
||||
include_tasks: cache.yml
|
||||
tags: [cache, setup]
|
||||
|
||||
- name: Pull authentik container image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ authentik_image }}:{{ authentik_version }}"
|
||||
state: present
|
||||
become: true
|
||||
become_user: "{{ authentik_user }}"
|
||||
tags: [containers, image-pull]
|
||||
|
||||
- name: Create media directory structure
|
||||
file:
|
||||
path: "{{ authentik_media_dir }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- public
|
||||
- private
|
||||
tags: [setup, media]
|
||||
|
||||
- name: Deploy environment configuration
|
||||
template:
|
||||
src: authentik.env.j2
|
||||
@@ -154,13 +128,12 @@
|
||||
|
||||
- name: Wait for Authentik to be ready
|
||||
uri:
|
||||
url: "https://{{ authentik_domain }}/if/health/live/"
|
||||
url: "http://127.0.0.1:{{ authentik_http_port }}/"
|
||||
method: GET
|
||||
status_code: [200]
|
||||
status_code: [200, 302]
|
||||
timeout: 30
|
||||
validate_certs: true
|
||||
retries: 10
|
||||
delay: 30
|
||||
delay: 15
|
||||
register: authentik_health_check
|
||||
tags: [verification, health-check]
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
# Authentik Container Networking - Bridge Network Setup
|
||||
|
||||
- name: Create authentik bridge network
|
||||
containers.podman.podman_network:
|
||||
name: "{{ authentik_network_name }}"
|
||||
driver: bridge
|
||||
internal: false
|
||||
state: present
|
||||
become: yes
|
||||
become_user: "{{ authentik_user }}"
|
||||
|
||||
- name: Check if authentik network exists
|
||||
command: podman network ls --format json
|
||||
become: yes
|
||||
become_user: "{{ authentik_user }}"
|
||||
register: network_list
|
||||
changed_when: false
|
||||
|
||||
- name: Ensure host gateway is available in network
|
||||
debug:
|
||||
msg: "Network {{ authentik_network_name }} configured for host.containers.internal access"
|
||||
when: authentik_enable_host_gateway | default(true)
|
||||
@@ -4,30 +4,30 @@
|
||||
- name: Create authentik group
|
||||
group:
|
||||
name: "{{ authentik_group }}"
|
||||
system: yes
|
||||
system: true
|
||||
|
||||
- name: Create authentik user
|
||||
user:
|
||||
name: "{{ authentik_user }}"
|
||||
group: "{{ authentik_group }}"
|
||||
system: yes
|
||||
system: true
|
||||
shell: /bin/bash
|
||||
home: "{{ authentik_home }}"
|
||||
create_home: yes
|
||||
create_home: true
|
||||
comment: "Authentik authentication service"
|
||||
|
||||
- name: Set up subuid for authentik user
|
||||
lineinfile:
|
||||
path: /etc/subuid
|
||||
line: "{{ authentik_user }}:{{ authentik_subuid_start }}:{{ authentik_subuid_size }}"
|
||||
create: yes
|
||||
create: true
|
||||
mode: '0644'
|
||||
|
||||
- name: Set up subgid for authentik user
|
||||
lineinfile:
|
||||
path: /etc/subgid
|
||||
line: "{{ authentik_user }}:{{ authentik_subgid_start }}:{{ authentik_subgid_size }}"
|
||||
create: yes
|
||||
create: true
|
||||
mode: '0644'
|
||||
|
||||
- name: Create authentik directories
|
||||
@@ -46,6 +46,7 @@
|
||||
- "{{ authentik_home }}/.config/containers/systemd"
|
||||
- "{{ authentik_home }}/data"
|
||||
- "{{ authentik_home }}/media"
|
||||
- "{{ authentik_home }}/logs"
|
||||
|
||||
- name: Enable lingering for authentik user
|
||||
command: loginctl enable-linger {{ authentik_user }}
|
||||
@@ -54,7 +55,19 @@
|
||||
|
||||
- name: Initialize user systemd for authentik
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
daemon_reload: true
|
||||
scope: user
|
||||
become: yes
|
||||
become: true
|
||||
become_user: "{{ authentik_user }}"
|
||||
|
||||
- name: Get authentik user UID and GID for container configuration
|
||||
shell: |
|
||||
echo "uid=$(id -u {{ authentik_user }})"
|
||||
echo "gid=$(id -g {{ authentik_user }})"
|
||||
register: authentik_user_info
|
||||
changed_when: false
|
||||
|
||||
- name: Set authentik UID/GID facts for container templates
|
||||
set_fact:
|
||||
authentik_uid: "{{ authentik_user_info.stdout_lines[0] | regex_replace('uid=', '') }}"
|
||||
authentik_gid: "{{ authentik_user_info.stdout_lines[1] | regex_replace('gid=', '') }}"
|
||||
@@ -11,6 +11,11 @@ EnvironmentFile={{ authentik_home }}/.env
|
||||
User={{ authentik_uid }}:{{ authentik_gid }}
|
||||
Annotation=run.oci.keep_original_groups=1
|
||||
|
||||
# Security configuration for shared memory and IPC
|
||||
Volume=/dev/shm:/dev/shm:rw
|
||||
SecurityLabelDisable=true
|
||||
AddCapability=IPC_OWNER
|
||||
|
||||
# Logging configuration
|
||||
LogDriver=k8s-file
|
||||
LogOpt=path={{ authentik_home }}/logs/server.log
|
||||
|
||||
@@ -11,6 +11,11 @@ EnvironmentFile={{ authentik_home }}/.env
|
||||
User={{ authentik_uid }}:{{ authentik_gid }}
|
||||
Annotation=run.oci.keep_original_groups=1
|
||||
|
||||
# Security configuration for shared memory and IPC
|
||||
Volume=/dev/shm:/dev/shm:rw
|
||||
SecurityLabelDisable=true
|
||||
AddCapability=IPC_OWNER
|
||||
|
||||
# Logging configuration
|
||||
LogDriver=k8s-file
|
||||
LogOpt=path={{ authentik_home }}/logs/worker.log
|
||||
|
||||
@@ -3,6 +3,7 @@ Description=Authentik Authentication Pod
|
||||
|
||||
[Pod]
|
||||
PublishPort=0.0.0.0:{{ authentik_http_port }}:{{ authentik_http_port }}
|
||||
ShmSize=256m
|
||||
PodmanArgs=
|
||||
|
||||
[Service]
|
||||
|
||||
8
site.yml
8
site.yml
@@ -19,9 +19,9 @@
|
||||
# tags: ['caddy', 'infrastructure', 'web']
|
||||
|
||||
# Application services
|
||||
- role: sigvild-gallery
|
||||
tags: ['sigvild', 'gallery', 'wedding']
|
||||
- role: authentik
|
||||
tags: ['authentik']
|
||||
# - role: sigvild-gallery
|
||||
# tags: ['sigvild', 'gallery', 'wedding']
|
||||
- role: gitea
|
||||
tags: ['gitea', 'git', 'development']
|
||||
- role: authentik
|
||||
tags: ['authentik']
|
||||
|
||||
Reference in New Issue
Block a user