feat: add Authelia SSO authentication service

- Add Authelia service to NET stack for centralized SSO
- Create configuration.yml with PostgreSQL storage
- Create users_database.yml for file-based user management
- Add authelia database to PostgreSQL init script
- Configure Traefik ForwardAuth middleware
- Add environment variables to arty.yml
- Supports TOTP and WebAuthn 2FA
- Email notifications via Mailpit SMTP relay
- Protected services: netdata, mailpit, scrapy, restic, traefik, dev, n8n, asciinema, coolify
This commit is contained in:
2025-11-15 19:53:04 +01:00
parent b19afa6a04
commit f9c953ecbc
5 changed files with 181 additions and 1 deletions

View File

@@ -125,6 +125,9 @@ envs:
# Mailpit SMTP Relay
NET_MAILPIT_IMAGE: axllent/mailpit:latest
NET_MAILPIT_TRAEFIK_HOST: mailpit.pivoine.art
# Authelia SSO
NET_AUTHELIA_IMAGE: authelia/authelia:latest
NET_AUTHELIA_TRAEFIK_HOST: auth.pivoine.art
# AI Stack
AI_TRAEFIK_ENABLED: true
AI_COMPOSE_PROJECT_NAME: ai

View File

@@ -49,6 +49,10 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
SELECT 'CREATE DATABASE coolify'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'coolify')\\gexec
-- Authelia SSO authentication database
SELECT 'CREATE DATABASE authelia'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'authelia')\\gexec
-- Grant privileges to all databases
GRANT ALL PRIVILEGES ON DATABASE directus TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE umami TO $POSTGRES_USER;
@@ -60,11 +64,12 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
GRANT ALL PRIVILEGES ON DATABASE asciinema TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE gitea TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE coolify TO $POSTGRES_USER;
GRANT ALL PRIVILEGES ON DATABASE authelia TO $POSTGRES_USER;
-- Log success
SELECT 'Compose databases initialized:' AS status;
SELECT datname FROM pg_database
WHERE datname IN ('directus', 'umami', 'n8n', 'linkwarden', 'joplin', 'mattermost', 'tandoor', 'asciinema', 'gitea', 'coolify')
WHERE datname IN ('directus', 'umami', 'n8n', 'linkwarden', 'joplin', 'mattermost', 'tandoor', 'asciinema', 'gitea', 'coolify', 'authelia')
ORDER BY datname;
EOSQL
@@ -83,4 +88,5 @@ echo " • tandoor - Recipe manager database"
echo " • asciinema - Terminal recording server database"
echo " • gitea - Self-hosted Git service database"
echo " • coolify - Deployment platform database"
echo " • authelia - SSO authentication database"
echo ""

View File

@@ -0,0 +1,116 @@
---
###############################################################
# Authelia Configuration #
###############################################################
theme: auto
server:
host: 0.0.0.0
port: 9091
path: ""
asset_path: /config/assets/
headers:
csp_template: ""
log:
level: info
format: text
totp:
issuer: pivoine.art
period: 30
skew: 1
webauthn:
disable: false
display_name: Pivoine Auth
attestation_conveyance_preference: indirect
user_verification: preferred
timeout: 60s
ntp:
address: "time.cloudflare.com:123"
version: 4
max_desync: 3s
disable_startup_check: false
disable_failure: false
authentication_backend:
password_reset:
disable: false
refresh_interval: 5m
file:
path: /etc/authelia/users_database.yml
password:
algorithm: argon2
argon2:
variant: argon2id
iterations: 3
memory: 65536
parallelism: 4
key_length: 32
salt_length: 16
access_control:
default_policy: deny
rules:
# Authelia portal itself
- domain: auth.pivoine.art
policy: bypass
# Services that should be publicly accessible
- domain:
- "pivoine.art"
- "www.pivoine.art"
policy: bypass
# Protected services - require authentication
- domain:
- "netdata.pivoine.art"
- "mailpit.pivoine.art"
- "scrapy.pivoine.art"
- "restic.pivoine.art"
- "traefik.pivoine.art"
policy: two_factor
# Development services
- domain:
- "dev.pivoine.art"
- "n8n.pivoine.art"
- "asciinema.pivoine.art"
- "coolify.pivoine.art"
policy: two_factor
session:
name: authelia_session
domain: pivoine.art
same_site: lax
expiration: 1h
inactivity: 5m
remember_me_duration: 1M
regulation:
max_retries: 3
find_time: 2m
ban_time: 5m
storage:
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
postgres:
host: postgres
port: 5432
database: authelia
username: valknar
password: ${DB_PASSWORD}
schema: public
notifier:
disable_startup_check: false
smtp:
host: net_mailpit
port: 1025
sender: auth@pivoine.art
identifier: auth.pivoine.art
disable_require_tls: true
disable_html_emails: false

View File

@@ -0,0 +1,16 @@
---
###############################################################
# Users Database #
###############################################################
# This file can be used if you do not have an LDAP set up.
# List of users
users:
valknar:
displayname: "Valknar"
password: "$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0$4oCb4oCh4oCd4oCi4oCl4oCm" # CHANGE THIS - use: docker run --rm authelia/authelia:latest authelia crypto hash generate argon2 --password 'yourpassword'
email: valknar@pivoine.art
groups:
- admins
- dev

View File

@@ -265,6 +265,43 @@ services:
# Watchtower
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
# Authelia - SSO and authentication portal
authelia:
image: ${NET_AUTHELIA_IMAGE:-authelia/authelia:latest}
container_name: ${NET_COMPOSE_PROJECT_NAME}_authelia
restart: unless-stopped
environment:
TZ: ${TIMEZONE:-Europe/Berlin}
AUTHELIA_JWT_SECRET: ${AUTHELIA_JWT_SECRET}
AUTHELIA_SESSION_SECRET: ${AUTHELIA_SESSION_SECRET}
AUTHELIA_STORAGE_ENCRYPTION_KEY: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
volumes:
- authelia_config:/config
- ./authelia:/etc/authelia:ro
networks:
- compose_network
labels:
- 'traefik.enable=${NET_TRAEFIK_ENABLED}'
# HTTP to HTTPS redirect
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure.redirectscheme.scheme=https'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.entrypoints=web'
# HTTPS router
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.tls.certresolver=resolver'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.entrypoints=web-secure'
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.middlewares=security-headers@file'
# Service
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.loadbalancer.server.port=9091'
- 'traefik.docker.network=${NETWORK_NAME}'
# ForwardAuth middleware for other services
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.address=http://authelia:9091/api/verify?rd=https://${NET_AUTHELIA_TRAEFIK_HOST}'
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.trustForwardHeader=true'
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email'
# Watchtower
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
volumes:
letsencrypt_data:
name: ${NET_COMPOSE_PROJECT_NAME}_letsencrypt_data
@@ -276,6 +313,8 @@ volumes:
name: ${NET_COMPOSE_PROJECT_NAME}_netdata_cache
mailpit_data:
name: ${NET_COMPOSE_PROJECT_NAME}_mailpit_data
authelia_config:
name: ${NET_COMPOSE_PROJECT_NAME}_authelia_config
networks:
compose_network: