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:
331
roles/vaultwarden/README.md
Normal file
331
roles/vaultwarden/README.md
Normal 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
|
||||
171
roles/vaultwarden/VAULT_VARIABLES.md
Normal file
171
roles/vaultwarden/VAULT_VARIABLES.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Vaultwarden Role - Required Vault Variables
|
||||
|
||||
This document lists all vault-encrypted variables required by the Vaultwarden role.
|
||||
|
||||
## Required Variables
|
||||
|
||||
These variables **must** be defined in your vault file (e.g., `group_vars/homelab/vault.yml`):
|
||||
|
||||
### Database Credentials
|
||||
|
||||
```yaml
|
||||
# PostgreSQL database password for vaultwarden user
|
||||
vault_vaultwarden_db_password: "your-secure-database-password-here"
|
||||
```
|
||||
|
||||
**Generation**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
### Admin Panel Access
|
||||
|
||||
```yaml
|
||||
# Plain text admin token (will be hashed during deployment)
|
||||
vault_vaultwarden_admin_token: "your-secret-admin-token"
|
||||
```
|
||||
|
||||
**Generation**:
|
||||
```bash
|
||||
# Generate a secure random token
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
**Important**:
|
||||
- Store as **plain text** in vault (the role will hash it automatically)
|
||||
- Use the same token to access `/admin` panel
|
||||
- The token is automatically hashed on the **control node** using argon2id
|
||||
- Hashing uses OWASP recommended settings (m=19456, t=2, p=1)
|
||||
- Hashing is **idempotent**: same token always produces same hash
|
||||
- The `argon2` package is automatically installed if not present on control node
|
||||
- Never commit the vault file unencrypted to git
|
||||
|
||||
## Optional Variables
|
||||
|
||||
These variables are only needed if you enable specific features:
|
||||
|
||||
### SMTP Configuration
|
||||
|
||||
Required if `vaultwarden_smtp_enabled: true`:
|
||||
|
||||
```yaml
|
||||
# SMTP password for sending emails
|
||||
vault_vaultwarden_smtp_password: "smtp-password-here"
|
||||
```
|
||||
|
||||
### SSO Integration (Authentik)
|
||||
|
||||
> ⚠️ **SSO Feature Status (December 2025)**
|
||||
>
|
||||
> SSO is only available in `vaultwarden/server:testing` images (not in stable yet).
|
||||
> This role is configured with SSO ready for when it reaches stable release.
|
||||
>
|
||||
> Current deployment uses `vaultwarden_version: "latest"` (stable) - SSO credentials
|
||||
> below are configured but SSO will not appear until feature reaches stable.
|
||||
|
||||
Required if `vaultwarden_sso_enabled: true`:
|
||||
|
||||
```yaml
|
||||
# OAuth2 Client ID from Authentik
|
||||
vault_vaultwarden_sso_client_id: "your-client-id-here"
|
||||
|
||||
# OAuth2 Client Secret from Authentik
|
||||
vault_vaultwarden_sso_client_secret: "your-client-secret-here"
|
||||
```
|
||||
|
||||
**Setup** (following [Authentik integration guide](https://integrations.goauthentik.io/security/vaultwarden/)):
|
||||
1. Create OAuth2/OpenID Provider in Authentik:
|
||||
- Redirect URI: `https://vault.jnss.me/identity/connect/oidc-signin` (exact match)
|
||||
- Add scope mappings: `openid`, `email`, `profile`, `offline_access` (required)
|
||||
- Access token validity: > 5 minutes
|
||||
- Note the **application slug** from the provider URL
|
||||
2. Copy Client ID and Secret from Authentik
|
||||
3. Add credentials to vault file
|
||||
4. Set the SSO authority URL in role configuration:
|
||||
```yaml
|
||||
vaultwarden_sso_enabled: true
|
||||
vaultwarden_sso_authority: "https://auth.jnss.me/application/o/<your-slug>/"
|
||||
```
|
||||
5. Deploy the role
|
||||
6. **Wait for SSO to reach stable**, or use `vaultwarden_version: "testing"` to test now
|
||||
|
||||
**Important**:
|
||||
- The SSO authority must include the full path with application slug
|
||||
- The `offline_access` scope mapping is **required** for Vaultwarden SSO
|
||||
- Access token must be valid for more than 5 minutes
|
||||
- SSO is configured and ready but will activate when stable release includes it
|
||||
|
||||
## Example Vault File
|
||||
|
||||
```yaml
|
||||
---
|
||||
# group_vars/homelab/vault.yml (encrypted with ansible-vault)
|
||||
|
||||
# Vaultwarden - Database
|
||||
vault_vaultwarden_db_password: "xK9mP2nR5tY8wQ3vZ7cB6sA4dF1gH0jL"
|
||||
|
||||
# Vaultwarden - Admin Panel (plain text, will be hashed automatically)
|
||||
vault_vaultwarden_admin_token: "MySecureAdminToken123!"
|
||||
|
||||
# Vaultwarden - SMTP (optional)
|
||||
vault_vaultwarden_smtp_password: "smtp-app-password-here"
|
||||
|
||||
# Vaultwarden - SSO (optional)
|
||||
vault_vaultwarden_sso_client_id: "vaultwarden"
|
||||
vault_vaultwarden_sso_client_secret: "sso-secret-from-authentik"
|
||||
```
|
||||
|
||||
## Vault File Management
|
||||
|
||||
### Encrypt Vault File
|
||||
|
||||
```bash
|
||||
ansible-vault encrypt group_vars/homelab/vault.yml
|
||||
```
|
||||
|
||||
### Edit Vault File
|
||||
|
||||
```bash
|
||||
ansible-vault edit group_vars/homelab/vault.yml
|
||||
```
|
||||
|
||||
### Decrypt Vault File (temporary)
|
||||
|
||||
```bash
|
||||
ansible-vault decrypt group_vars/homelab/vault.yml
|
||||
# Make changes
|
||||
ansible-vault encrypt group_vars/homelab/vault.yml
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit unencrypted vault files**
|
||||
2. **Use strong passwords** (32+ characters for database, admin token)
|
||||
3. **Rotate credentials periodically** (especially admin token)
|
||||
4. **Limit vault password access** (use password manager)
|
||||
5. **Use separate passwords** for different services
|
||||
6. **Back up vault password** (secure location, not in git)
|
||||
|
||||
## Verifying Variables
|
||||
|
||||
Test if variables are properly loaded:
|
||||
|
||||
```bash
|
||||
ansible -m debug -a "var=vault_vaultwarden_db_password" homelab --ask-vault-pass
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Variable not found error
|
||||
|
||||
- Ensure vault file is in correct location: `group_vars/homelab/vault.yml`
|
||||
- Verify file is encrypted: `file group_vars/homelab/vault.yml`
|
||||
- Check variable name matches exactly (case-sensitive)
|
||||
- Provide vault password with `--ask-vault-pass`
|
||||
|
||||
### Admin token not working
|
||||
|
||||
- Verify the plain text token in vault matches what you're entering
|
||||
- Check for extra whitespace in vault file
|
||||
- Ensure the token was hashed successfully during deployment (check ansible output)
|
||||
- Try redeploying the role to regenerate the hash
|
||||
109
roles/vaultwarden/defaults/main.yml
Normal file
109
roles/vaultwarden/defaults/main.yml
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
# =================================================================
|
||||
# Vaultwarden Password Manager Role - Default Variables
|
||||
# =================================================================
|
||||
# Self-contained Vaultwarden deployment with Podman and PostgreSQL
|
||||
|
||||
# =================================================================
|
||||
# Service Configuration
|
||||
# =================================================================
|
||||
|
||||
# Service user and directories
|
||||
vaultwarden_user: vaultwarden
|
||||
vaultwarden_group: vaultwarden
|
||||
vaultwarden_home: /opt/vaultwarden
|
||||
vaultwarden_data_dir: "{{ vaultwarden_home }}/data"
|
||||
|
||||
# Container configuration
|
||||
# NOTE: SSO feature is only available in "testing" tag (as of Dec 2025)
|
||||
# Using "latest" (stable) means SSO will not appear even if configured
|
||||
# SSO settings below are configured and ready for when feature reaches stable
|
||||
vaultwarden_version: "latest"
|
||||
vaultwarden_image: "vaultwarden/server"
|
||||
|
||||
# Service management
|
||||
vaultwarden_service_enabled: true
|
||||
vaultwarden_service_state: "started"
|
||||
|
||||
# =================================================================
|
||||
# Database Configuration (Self-managed)
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_db_name: "vaultwarden"
|
||||
vaultwarden_db_user: "vaultwarden"
|
||||
vaultwarden_db_password: "{{ vault_vaultwarden_db_password }}"
|
||||
|
||||
# =================================================================
|
||||
# Network Configuration
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_domain: "vault.jnss.me"
|
||||
vaultwarden_http_port: 8080
|
||||
|
||||
# =================================================================
|
||||
# Vaultwarden Core Configuration
|
||||
# =================================================================
|
||||
|
||||
# Admin panel access token (plain text, will be hashed during deployment)
|
||||
vaultwarden_admin_token_plain: "{{ vault_vaultwarden_admin_token }}"
|
||||
|
||||
# Registration and invitation controls
|
||||
vaultwarden_signups_allowed: false # Disable open registration
|
||||
vaultwarden_invitations_allowed: true # Allow existing users to invite
|
||||
vaultwarden_show_password_hint: false # Don't show password hints
|
||||
|
||||
# WebSocket support for live sync
|
||||
vaultwarden_websocket_enabled: true
|
||||
|
||||
# =================================================================
|
||||
# Email Configuration (Optional)
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_smtp_enabled: true
|
||||
vaultwarden_smtp_host: "smtp.titan.email"
|
||||
vaultwarden_smtp_port: 587
|
||||
vaultwarden_smtp_from: "hello@jnss.me"
|
||||
vaultwarden_smtp_username: "hello@jnss.me"
|
||||
vaultwarden_smtp_password: "{{ vault_vaultwarden_smtp_password | default('') }}"
|
||||
vaultwarden_smtp_security: "starttls" # Options: starttls, force_tls, off
|
||||
|
||||
# =================================================================
|
||||
# SSO Configuration (Optional - Authentik Integration)
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_sso_enabled: false
|
||||
|
||||
# SSO Provider Configuration (Authentik)
|
||||
vaultwarden_sso_client_id: "{{ vault_vaultwarden_sso_client_id | default('') }}"
|
||||
vaultwarden_sso_client_secret: "{{ vault_vaultwarden_sso_client_secret | default('') }}"
|
||||
# Authority must include full path with application slug
|
||||
vaultwarden_sso_authority: "https://{{ authentik_domain }}/application/o/vaultwarden/"
|
||||
vaultwarden_sso_scopes: "openid email profile offline_access"
|
||||
|
||||
# Additional SSO settings (per Authentik integration guide)
|
||||
vaultwarden_sso_only: false # Set to true to disable email+password login and require SSO
|
||||
vaultwarden_sso_signups_match_email: true # Match first SSO login to existing account by email
|
||||
vaultwarden_sso_allow_unknown_email_verification: false
|
||||
vaultwarden_sso_client_cache_expiration: 0
|
||||
|
||||
# Domain whitelist for SSO signups (comma-separated domains, empty = all)
|
||||
vaultwarden_sso_signups_domains_whitelist: ""
|
||||
|
||||
# =================================================================
|
||||
# Caddy Integration
|
||||
# =================================================================
|
||||
|
||||
# Caddy configuration (assumes caddy role provides these variables)
|
||||
caddy_sites_enabled_dir: "/etc/caddy/sites-enabled"
|
||||
caddy_log_dir: "/var/log/caddy"
|
||||
caddy_user: "caddy"
|
||||
|
||||
# =================================================================
|
||||
# Infrastructure Dependencies (Read-only)
|
||||
# =================================================================
|
||||
|
||||
# PostgreSQL socket configuration (managed by postgresql role)
|
||||
postgresql_unix_socket_directories: "/var/run/postgresql"
|
||||
postgresql_client_group: "postgres-clients"
|
||||
postgresql_port: 5432
|
||||
postgresql_unix_socket_enabled: true
|
||||
16
roles/vaultwarden/handlers/main.yml
Normal file
16
roles/vaultwarden/handlers/main.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
# Vaultwarden Password Manager - Service Handlers
|
||||
|
||||
- name: reload systemd
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: restart vaultwarden
|
||||
systemd:
|
||||
name: vaultwarden
|
||||
state: restarted
|
||||
|
||||
- name: reload caddy
|
||||
systemd:
|
||||
name: caddy
|
||||
state: reloaded
|
||||
25
roles/vaultwarden/meta/main.yml
Normal file
25
roles/vaultwarden/meta/main.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# Vaultwarden Password Manager - Role Metadata
|
||||
|
||||
dependencies:
|
||||
- role: postgresql
|
||||
- role: caddy
|
||||
|
||||
galaxy_info:
|
||||
author: Rick Infrastructure Team
|
||||
description: Vaultwarden password manager deployment with PostgreSQL and Caddy
|
||||
license: MIT
|
||||
min_ansible_version: "2.14"
|
||||
|
||||
platforms:
|
||||
- name: ArchLinux
|
||||
versions:
|
||||
- all
|
||||
|
||||
galaxy_tags:
|
||||
- vaultwarden
|
||||
- bitwarden
|
||||
- password-manager
|
||||
- security
|
||||
- postgresql
|
||||
- podman
|
||||
51
roles/vaultwarden/tasks/database.yml
Normal file
51
roles/vaultwarden/tasks/database.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
# Database setup for Vaultwarden - PostgreSQL via Unix Socket
|
||||
|
||||
- name: Test PostgreSQL socket connectivity
|
||||
postgresql_ping:
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: "{{ vaultwarden_user }}"
|
||||
become: true
|
||||
become_user: "{{ vaultwarden_user }}"
|
||||
|
||||
- name: Create Vaultwarden database user via socket
|
||||
postgresql_user:
|
||||
name: "{{ vaultwarden_db_user }}"
|
||||
password: "{{ vaultwarden_db_password }}"
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: postgres
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Create Vaultwarden database via socket
|
||||
postgresql_db:
|
||||
name: "{{ vaultwarden_db_name }}"
|
||||
owner: "{{ vaultwarden_db_user }}"
|
||||
encoding: UTF8
|
||||
template: template0
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: postgres
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Grant Vaultwarden database privileges
|
||||
postgresql_privs:
|
||||
db: "{{ vaultwarden_db_name }}"
|
||||
privs: ALL
|
||||
type: database
|
||||
role: "{{ vaultwarden_db_user }}"
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: postgres
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Display database setup status
|
||||
debug:
|
||||
msg: |
|
||||
Vaultwarden database setup complete!
|
||||
|
||||
Database: {{ vaultwarden_db_name }}
|
||||
User: {{ vaultwarden_db_user }}
|
||||
Connection: Unix socket ({{ postgresql_unix_socket_directories }})
|
||||
|
||||
Ready for Vaultwarden container deployment
|
||||
57
roles/vaultwarden/tasks/hash_admin_token.yml
Normal file
57
roles/vaultwarden/tasks/hash_admin_token.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
# Hash admin token on Ansible control node using argon2
|
||||
|
||||
- name: Check if argon2 is available on control node
|
||||
command: which argon2
|
||||
register: argon2_check
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Install argon2 on control node if not present
|
||||
package:
|
||||
name: argon2
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
when: argon2_check.rc != 0
|
||||
run_once: true
|
||||
|
||||
- name: Generate deterministic salt from domain
|
||||
set_fact:
|
||||
vaultwarden_salt_source: "{{ vaultwarden_domain }}-{{ vaultwarden_sso_authority }}"
|
||||
no_log: true
|
||||
|
||||
- name: Create base64-encoded salt for argon2
|
||||
shell: echo -n "{{ vaultwarden_salt_source }}" | sha256sum | cut -d' ' -f1 | head -c 22
|
||||
register: admin_token_salt
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Hash admin token using argon2 (OWASP preset)
|
||||
shell: echo -n "{{ vaultwarden_admin_token_plain }}" | argon2 "{{ admin_token_salt.stdout }}" -id -t 2 -k 19456 -p 1 -e
|
||||
register: admin_token_hash_result
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Extract hashed admin token
|
||||
set_fact:
|
||||
vaultwarden_admin_token_hashed: "{{ admin_token_hash_result.stdout | trim }}"
|
||||
no_log: true
|
||||
|
||||
- name: Display token hash status
|
||||
debug:
|
||||
msg: |
|
||||
Admin token hashed successfully on control node
|
||||
|
||||
Hash algorithm: argon2id
|
||||
Preset: OWASP (m=19456, t=2, p=1)
|
||||
Format: PHC string (Vaultwarden compatible)
|
||||
Idempotent: Same token always produces same hash
|
||||
|
||||
The hashed token will be used in the environment configuration
|
||||
108
roles/vaultwarden/tasks/main.yml
Normal file
108
roles/vaultwarden/tasks/main.yml
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
# Vaultwarden Password Manager Role - Main Tasks
|
||||
# Self-contained deployment with Podman and Unix sockets
|
||||
|
||||
- name: Setup vaultwarden user and directories
|
||||
include_tasks: user.yml
|
||||
tags: [user, setup]
|
||||
|
||||
- name: Setup database access and permissions
|
||||
include_tasks: database.yml
|
||||
tags: [database, setup]
|
||||
|
||||
- name: Pull vaultwarden container image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ vaultwarden_image }}:{{ vaultwarden_version }}"
|
||||
state: present
|
||||
tags: [containers, image-pull]
|
||||
|
||||
- name: Hash admin token on host
|
||||
include_tasks: hash_admin_token.yml
|
||||
tags: [config, admin-token]
|
||||
|
||||
- name: Deploy environment configuration
|
||||
template:
|
||||
src: vaultwarden.env.j2
|
||||
dest: "{{ vaultwarden_home }}/.env"
|
||||
owner: "{{ vaultwarden_user }}"
|
||||
group: "{{ vaultwarden_group }}"
|
||||
mode: '0600'
|
||||
backup: true
|
||||
notify:
|
||||
- restart vaultwarden
|
||||
tags: [config]
|
||||
|
||||
- name: Create Quadlet systemd directory
|
||||
file:
|
||||
path: /etc/containers/systemd
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy Quadlet container file
|
||||
template:
|
||||
src: vaultwarden.container
|
||||
dest: /etc/containers/systemd/vaultwarden.container
|
||||
mode: '0644'
|
||||
notify:
|
||||
- reload systemd
|
||||
- restart vaultwarden
|
||||
tags: [containers, deployment]
|
||||
|
||||
- name: Deploy Caddy configuration
|
||||
template:
|
||||
src: vaultwarden.caddy.j2
|
||||
dest: "{{ caddy_sites_enabled_dir }}/vaultwarden.caddy"
|
||||
owner: root
|
||||
group: "{{ caddy_user }}"
|
||||
mode: '0644'
|
||||
backup: true
|
||||
notify: reload caddy
|
||||
tags: [caddy, reverse-proxy]
|
||||
|
||||
- name: Ensure PostgreSQL is running
|
||||
systemd:
|
||||
name: postgresql
|
||||
state: started
|
||||
|
||||
- name: Wait for PostgreSQL socket to be ready
|
||||
wait_for:
|
||||
path: "{{ postgresql_unix_socket_directories }}/.s.PGSQL.{{ postgresql_port }}"
|
||||
timeout: 30
|
||||
when: postgresql_unix_socket_enabled
|
||||
|
||||
- name: Enable and start Vaultwarden service (system scope)
|
||||
systemd:
|
||||
name: vaultwarden
|
||||
enabled: "{{ vaultwarden_service_enabled }}"
|
||||
state: "{{ vaultwarden_service_state }}"
|
||||
daemon_reload: true
|
||||
tags: [containers, service]
|
||||
|
||||
- name: Wait for Vaultwarden to be ready
|
||||
uri:
|
||||
url: "http://127.0.0.1:{{ vaultwarden_http_port }}/"
|
||||
method: GET
|
||||
status_code: [200, 302]
|
||||
timeout: 30
|
||||
retries: 10
|
||||
delay: 15
|
||||
register: vaultwarden_health_check
|
||||
tags: [verification, health-check]
|
||||
|
||||
- name: Display Vaultwarden deployment status
|
||||
debug:
|
||||
msg: |
|
||||
Vaultwarden Password Manager deployed successfully!
|
||||
|
||||
Domain: {{ vaultwarden_domain }}
|
||||
Database: {{ vaultwarden_db_name }} (Unix socket)
|
||||
Container: {{ vaultwarden_image }}:{{ vaultwarden_version }}
|
||||
Admin Panel: https://{{ vaultwarden_domain }}/admin
|
||||
|
||||
Ready for user registration and password management!
|
||||
|
||||
Next Steps:
|
||||
- Access https://{{ vaultwarden_domain }}/admin with your admin token
|
||||
- Configure additional settings (SMTP, SSO, etc.)
|
||||
- Invite users or create accounts
|
||||
tags: [verification]
|
||||
28
roles/vaultwarden/tasks/user.yml
Normal file
28
roles/vaultwarden/tasks/user.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
# Vaultwarden User Management - Service-Specific User Setup
|
||||
|
||||
- name: Create vaultwarden group
|
||||
group:
|
||||
name: "{{ vaultwarden_group }}"
|
||||
system: true
|
||||
|
||||
- name: Create vaultwarden user
|
||||
user:
|
||||
name: "{{ vaultwarden_user }}"
|
||||
group: "{{ vaultwarden_group }}"
|
||||
system: true
|
||||
shell: /bin/bash
|
||||
home: "{{ vaultwarden_home }}"
|
||||
create_home: true
|
||||
comment: "Vaultwarden password manager service"
|
||||
|
||||
- name: Create vaultwarden directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ vaultwarden_user }}"
|
||||
group: "{{ vaultwarden_group }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "{{ vaultwarden_home }}"
|
||||
- "{{ vaultwarden_data_dir }}"
|
||||
35
roles/vaultwarden/templates/vaultwarden.caddy.j2
Normal file
35
roles/vaultwarden/templates/vaultwarden.caddy.j2
Normal file
@@ -0,0 +1,35 @@
|
||||
# Vaultwarden Password Manager
|
||||
{{ vaultwarden_domain }} {
|
||||
# Notifications endpoint (WebSocket for live sync)
|
||||
@websocket {
|
||||
path /notifications/hub
|
||||
}
|
||||
reverse_proxy @websocket http://127.0.0.1:{{ vaultwarden_http_port }} {
|
||||
header_up Upgrade {http.request.header.Upgrade}
|
||||
header_up Connection {http.request.header.Connection}
|
||||
}
|
||||
|
||||
# Regular HTTP traffic
|
||||
reverse_proxy http://127.0.0.1:{{ vaultwarden_http_port }} {
|
||||
header_up Host {host}
|
||||
header_up X-Real-IP {remote_host}
|
||||
header_up X-Forwarded-Proto https
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
}
|
||||
|
||||
# Security headers
|
||||
header {
|
||||
X-Frame-Options SAMEORIGIN
|
||||
X-Content-Type-Options nosniff
|
||||
X-XSS-Protection "1; mode=block"
|
||||
Referrer-Policy strict-origin-when-cross-origin
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
}
|
||||
|
||||
# Logging
|
||||
log {
|
||||
output file {{ caddy_log_dir }}/vaultwarden.log
|
||||
level INFO
|
||||
format json
|
||||
}
|
||||
}
|
||||
26
roles/vaultwarden/templates/vaultwarden.container
Normal file
26
roles/vaultwarden/templates/vaultwarden.container
Normal file
@@ -0,0 +1,26 @@
|
||||
[Unit]
|
||||
Description=Vaultwarden Password Manager Container
|
||||
After=network-online.target postgresql.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
ContainerName=vaultwarden
|
||||
Image={{ vaultwarden_image }}:{{ vaultwarden_version }}
|
||||
EnvironmentFile={{ vaultwarden_home }}/.env
|
||||
|
||||
# Volume mounts
|
||||
# Application data (includes database, attachments, sends, icons, etc.)
|
||||
Volume={{ vaultwarden_data_dir }}:/data:Z
|
||||
|
||||
# Infrastructure socket (PostgreSQL access with 777 permissions on host)
|
||||
Volume={{ postgresql_unix_socket_directories }}:{{ postgresql_unix_socket_directories }}:Z
|
||||
|
||||
# Expose HTTP port to localhost only (Caddy will reverse proxy)
|
||||
PublishPort=127.0.0.1:{{ vaultwarden_http_port }}:80
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
TimeoutStartSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
73
roles/vaultwarden/templates/vaultwarden.env.j2
Normal file
73
roles/vaultwarden/templates/vaultwarden.env.j2
Normal file
@@ -0,0 +1,73 @@
|
||||
# Vaultwarden Environment Configuration
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
# =================================================================
|
||||
# Database Configuration (PostgreSQL via Unix Socket)
|
||||
# =================================================================
|
||||
DATABASE_URL=postgresql://{{ vaultwarden_db_user }}:{{ vaultwarden_db_password }}@/{{ vaultwarden_db_name }}?host={{ postgresql_unix_socket_directories }}
|
||||
|
||||
# =================================================================
|
||||
# Domain Configuration
|
||||
# =================================================================
|
||||
DOMAIN=https://{{ vaultwarden_domain }}
|
||||
|
||||
# =================================================================
|
||||
# Admin Configuration
|
||||
# =================================================================
|
||||
ADMIN_TOKEN={{ vaultwarden_admin_token_hashed }}
|
||||
|
||||
# =================================================================
|
||||
# Registration and Invitation Controls
|
||||
# =================================================================
|
||||
SIGNUPS_ALLOWED={{ vaultwarden_signups_allowed | lower }}
|
||||
INVITATIONS_ALLOWED={{ vaultwarden_invitations_allowed | lower }}
|
||||
SHOW_PASSWORD_HINT={{ vaultwarden_show_password_hint | lower }}
|
||||
|
||||
# =================================================================
|
||||
# WebSocket Configuration (for live sync)
|
||||
# =================================================================
|
||||
WEBSOCKET_ENABLED={{ vaultwarden_websocket_enabled | lower }}
|
||||
|
||||
# =================================================================
|
||||
# SMTP Configuration (Optional)
|
||||
# =================================================================
|
||||
{% if vaultwarden_smtp_enabled %}
|
||||
SMTP_HOST={{ vaultwarden_smtp_host }}
|
||||
SMTP_PORT={{ vaultwarden_smtp_port }}
|
||||
SMTP_FROM={{ vaultwarden_smtp_from }}
|
||||
SMTP_SECURITY={{ vaultwarden_smtp_security }}
|
||||
{% if vaultwarden_smtp_username %}
|
||||
SMTP_USERNAME={{ vaultwarden_smtp_username }}
|
||||
SMTP_PASSWORD={{ vaultwarden_smtp_password }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# SSO Configuration (Optional - Authentik Integration)
|
||||
# =================================================================
|
||||
{% if vaultwarden_sso_enabled %}
|
||||
SSO_ENABLED=true
|
||||
SSO_ONLY={{ vaultwarden_sso_only | lower }}
|
||||
SSO_CLIENT_ID={{ vaultwarden_sso_client_id }}
|
||||
SSO_CLIENT_SECRET={{ vaultwarden_sso_client_secret }}
|
||||
SSO_AUTHORITY={{ vaultwarden_sso_authority }}
|
||||
SSO_SCOPES="{{ vaultwarden_sso_scopes }}"
|
||||
SSO_SIGNUPS_MATCH_EMAIL={{ vaultwarden_sso_signups_match_email | lower }}
|
||||
SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION={{ vaultwarden_sso_allow_unknown_email_verification | lower }}
|
||||
SSO_CLIENT_CACHE_EXPIRATION={{ vaultwarden_sso_client_cache_expiration }}
|
||||
{% if vaultwarden_sso_signups_domains_whitelist %}
|
||||
SSO_SIGNUPS_DOMAINS_WHITELIST={{ vaultwarden_sso_signups_domains_whitelist }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# Security and Performance
|
||||
# =================================================================
|
||||
# Disable user registration via email (use admin panel or invitations)
|
||||
SIGNUPS_VERIFY=false
|
||||
|
||||
# Log level (trace, debug, info, warn, error, off)
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Rocket configuration
|
||||
ROCKET_WORKERS=10
|
||||
Reference in New Issue
Block a user