Add Vaultwarden password manager role with PostgreSQL and SSO support

- Implement complete Vaultwarden deployment using Podman Quadlet
- PostgreSQL backend via Unix socket with 777 permissions
- Caddy reverse proxy with WebSocket support for live sync
- Control-node admin token hashing using argon2 (OWASP preset)
- Idempotent token hashing with deterministic salt generation
- Full Authentik SSO integration following official guide
- SMTP email configuration support (optional)
- Invitation-only user registration by default
- Comprehensive documentation with setup and troubleshooting guides

Technical Details:
- Container: vaultwarden/server:latest from Docker Hub
- Database: PostgreSQL via /var/run/postgresql socket
- Port: 8080 (localhost only, proxied by Caddy)
- Domain: vault.jnss.me
- Admin token: Hashed on control node with argon2id
- SSO: OpenID Connect with offline_access scope support

Role includes automatic argon2 installation on control node if needed.
This commit is contained in:
2025-12-21 16:13:25 +01:00
parent 89b43180fc
commit bfd6f22f0e
14 changed files with 1346 additions and 3 deletions

331
roles/vaultwarden/README.md Normal file
View File

@@ -0,0 +1,331 @@
# Vaultwarden Password Manager Role
Self-contained Vaultwarden (Bitwarden-compatible) password manager deployment using Podman and PostgreSQL.
## Overview
This role deploys Vaultwarden as a Podman Quadlet container with:
- **PostgreSQL backend** via Unix socket (777 permissions)
- **Caddy reverse proxy** with HTTPS and WebSocket support
- **SSO integration** ready (Authentik OpenID Connect)
- **SMTP support** for email notifications (optional)
- **Admin panel** for management
## Architecture
```
Internet → Caddy (HTTPS) → Vaultwarden Container → PostgreSQL (Unix socket)
/data volume
```
### Components
- **Container Image**: `vaultwarden/server:latest` (Docker Hub)
- **User**: System user `vaultwarden` (non-root)
- **Port**: 8080 (localhost only)
- **Domain**: `vault.jnss.me`
- **Database**: PostgreSQL via Unix socket at `/var/run/postgresql`
- **Data**: `/opt/vaultwarden/data`
## Dependencies
**Managed Hosts:**
- `postgresql` role (provides database and Unix socket)
- `caddy` role (provides reverse proxy)
**Control Node:**
- `argon2` command-line tool (automatically installed if not present)
- Used to hash the admin token securely on the control node
- Available in most package managers: `pacman -S argon2`, `apt install argon2`, etc.
## Configuration
### Required Variables
Must be defined in vault (e.g., `group_vars/homelab/vault.yml`):
```yaml
# Database password
vault_vaultwarden_db_password: "secure-database-password"
# Admin token (plain text - will be hashed automatically during deployment)
vault_vaultwarden_admin_token: "your-secure-admin-token"
# SMTP password (if using email)
vault_vaultwarden_smtp_password: "smtp-password" # optional
# SSO credentials (if using Authentik integration)
vault_vaultwarden_sso_client_id: "vaultwarden" # optional
vault_vaultwarden_sso_client_secret: "sso-secret" # optional
```
### Optional Variables
Override in `group_vars` or `host_vars`:
```yaml
# Domain
vaultwarden_domain: "vault.jnss.me"
# Container version
vaultwarden_version: "latest"
# Registration controls
vaultwarden_signups_allowed: false # Disable open registration
vaultwarden_invitations_allowed: true # Allow existing users to invite
# SMTP Configuration
vaultwarden_smtp_enabled: true
vaultwarden_smtp_host: "smtp.example.com"
vaultwarden_smtp_port: 587
vaultwarden_smtp_from: "vault@jnss.me"
vaultwarden_smtp_username: "smtp-user"
# SSO Configuration (Authentik)
vaultwarden_sso_enabled: true
vaultwarden_sso_authority: "https://auth.jnss.me"
```
## Usage
### Deploy Vaultwarden
```bash
# Full deployment
ansible-playbook rick-infra.yml --tags vaultwarden
# Or via site.yml
ansible-playbook site.yml --tags vaultwarden -l homelab
```
### Access Admin Panel
1. Set admin token in vault file (plain text):
```yaml
# Generate a secure token
vault_vaultwarden_admin_token: "$(openssl rand -base64 32)"
```
2. The role automatically hashes the token during deployment:
- Hashing occurs on the **control node** using `argon2` CLI
- Uses OWASP recommended settings (19MiB memory, 2 iterations, 1 thread)
- Idempotent: same token always produces the same hash
- The `argon2` package is automatically installed if not present
3. Access: `https://vault.jnss.me/admin` (use the plain text token from step 1)
### Configure SSO (Authentik Integration)
> ⚠️ **IMPORTANT: SSO Feature Status (as of December 2025)**
>
> SSO is currently **only available in `vaultwarden/server:testing` images**.
> The stable release (v1.34.3) does **NOT** include SSO functionality.
>
> **Current Deployment Status:**
> - This role is configured with SSO settings ready for when SSO reaches stable release
> - Using `vaultwarden_version: "latest"` (stable) - SSO will not appear
> - To test SSO now: Set `vaultwarden_version: "testing"` (not recommended for production)
> - To wait for stable: Keep current configuration, SSO will activate automatically when available
>
> **References:**
> - [Vaultwarden Wiki - SSO Documentation](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect)
> - [Vaultwarden Testing Features](https://github.com/dani-garcia/vaultwarden/wiki#testing-features)
>
> **Decision:** This deployment keeps SSO configured but uses stable image until SSO feature is production-ready.
Following the [Authentik integration guide](https://integrations.goauthentik.io/security/vaultwarden/):
1. **In Authentik**: Create OAuth2/OpenID Provider
- **Name**: `Vaultwarden`
- **Client Type**: `Confidential`
- **Redirect URIs**: `https://vault.jnss.me/identity/connect/oidc-signin` (must be strict/exact match)
- **Scopes**: Under "Advanced protocol settings", ensure these scope mappings are selected:
- `authentik default OAuth Mapping: OpenID 'openid'`
- `authentik default OAuth Mapping: OpenID 'email'`
- `authentik default OAuth Mapping: OpenID 'profile'`
- `authentik default OAuth Mapping: OpenID 'offline_access'` ⚠️ **Required**
- **Access token validity**: Set to more than 5 minutes
- **Note the Client ID, Client Secret, and application slug** (from URL or provider settings)
2. **Update Vault Variables**:
```yaml
vault_vaultwarden_sso_client_id: "<client-id-from-authentik>"
vault_vaultwarden_sso_client_secret: "<client-secret-from-authentik>"
```
3. **Enable SSO and set authority** in `group_vars/homelab/main.yml`:
```yaml
vaultwarden_sso_enabled: true
# Replace 'vaultwarden' with your actual application slug
vaultwarden_sso_authority: "https://auth.jnss.me/application/o/vaultwarden/"
```
4. **Optional: SSO-Only Mode** (disable password login):
```yaml
vaultwarden_sso_only: true # Requires SSO, disables email+password
```
5. **Redeploy**:
```bash
ansible-playbook rick-infra.yml --tags vaultwarden
```
6. **Test**: Log out, enter a verified email on login page, click "Use single sign-on"
- **Note**: With `vaultwarden_version: "latest"`, SSO button will not appear (feature not in stable yet)
## Security Considerations
### Database Access
- Uses PostgreSQL Unix socket with **777 permissions**
- Security maintained via password authentication (scram-sha-256)
- See: `docs/socket-permissions-architecture.md`
### Admin Token
- **Never commit plain admin token to git**
- Use Ansible Vault for `vault_vaultwarden_admin_token`
- Rotate periodically via admin panel
### User Registration
- Default: **Disabled** (`vaultwarden_signups_allowed: false`)
- Users must be invited by existing users or created via admin panel
- Prevents unauthorized account creation
## Maintenance
### Backup
Backup the following:
```bash
# Database backup (via PostgreSQL role)
sudo -u postgres pg_dump vaultwarden > vaultwarden-backup.sql
# Data directory (attachments, icons, etc.)
tar -czf vaultwarden-data-backup.tar.gz /opt/vaultwarden/data
```
### Update Container
```bash
# Pull new image and restart
ansible-playbook rick-infra.yml --tags vaultwarden
```
### View Logs
```bash
# Service logs
journalctl -u vaultwarden -f
# Container logs
podman logs vaultwarden -f
```
### Restart Service
```bash
systemctl restart vaultwarden
```
## Troubleshooting
### Container won't start
```bash
# Check container status
systemctl status vaultwarden
# Check container directly
podman ps -a
podman logs vaultwarden
# Verify database connectivity
sudo -u vaultwarden psql -h /var/run/postgresql -U vaultwarden -d vaultwarden -c "SELECT 1;"
```
### Database connection errors
1. Verify PostgreSQL is running: `systemctl status postgresql`
2. Check socket exists: `ls -la /var/run/postgresql/.s.PGSQL.5432`
3. Verify socket permissions: Should be `srwxrwxrwx` (777)
4. Test connection as vaultwarden user (see above)
### Can't access admin panel
1. Verify admin token is set in vault file (plain text)
2. Check that the token was hashed successfully during deployment
3. Ensure you're using the plain text token to log in
4. Redeploy to regenerate hash if needed
### SSO not appearing / not working
**Most Common Issue: Using Stable Image**
SSO is only available in testing images. Check your deployment:
```bash
# Check current image version
podman inspect vaultwarden --format '{{.ImageName}}'
# Check API config for SSO support
curl -s http://127.0.0.1:8080/api/config | grep -o '"sso":"[^"]*"'
# Empty string "" = SSO not available in this image
# URL present = SSO is available
```
**If using `vaultwarden_version: "latest"`**: SSO will not appear (feature not in stable yet)
- **To test SSO**: Set `vaultwarden_version: "testing"` in role defaults or group/host vars
- **For production**: Wait for SSO to reach stable release (recommended)
**If using `vaultwarden_version: "testing"` and SSO still not working**:
1. Verify Authentik provider configuration:
- Check that `offline_access` scope mapping is added
- Verify redirect URI matches exactly: `https://vault.jnss.me/identity/connect/oidc-signin`
- Ensure access token validity is > 5 minutes
2. Verify SSO authority URL includes full path with slug:
- Should be: `https://auth.jnss.me/application/o/<your-slug>/`
- Not just: `https://auth.jnss.me`
3. Check client ID and secret in vault match Authentik
4. Verify all required scopes: `openid email profile offline_access`
5. Check Vaultwarden logs for SSO-related errors:
```bash
podman logs vaultwarden 2>&1 | grep -i sso
```
6. Test SSO flow: Log out, enter verified email, click "Use single sign-on"
## File Structure
```
roles/vaultwarden/
├── defaults/
│ └── main.yml # Default variables
├── handlers/
│ └── main.yml # Service restart handlers
├── meta/
│ └── main.yml # Role dependencies
├── tasks/
│ ├── main.yml # Main orchestration
│ ├── user.yml # User and directory setup
│ └── database.yml # PostgreSQL setup
├── templates/
│ ├── vaultwarden.container # Quadlet container definition
│ ├── vaultwarden.env.j2 # Environment configuration
│ └── vaultwarden.caddy.j2 # Caddy reverse proxy config
└── README.md # This file
```
## References
- [Vaultwarden Documentation](https://github.com/dani-garcia/vaultwarden/wiki)
- [PostgreSQL Backend Guide](https://github.com/dani-garcia/vaultwarden/wiki/Using-the-PostgreSQL-Backend)
- [SSO Configuration](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect)
- [Socket Permissions Architecture](../../docs/socket-permissions-architecture.md)
## License
MIT