Compare commits

...

12 Commits

8 changed files with 323 additions and 129 deletions

15
.gitignore vendored
View File

@@ -1,7 +1,10 @@
traefik/acme.json **/*
traefik/certs/ !.gitignore
traefik/traefik.log
authelia/db.sqlite3 !README.md
authelia/notification.txt !docker-compose.yaml
authelia/users_database.yml
!traefik/traefik.yaml
!traefik/config/*
!authelia/configuration.yaml

72
README.md Normal file
View File

@@ -0,0 +1,72 @@
# Server
Configuration for traefik 2 and authelia
## Environment variables
This setup uses two global environment variables: `PRIVATE_DOMAIN` and `PUBLIC_DOMAIN`. Those are two registered domain names I use for public and private services.
There is also an `.env` file which defines a few more variables:
```
AUTHELIA_JWT_SECRET=...
AUTHELIA_SESSION_SECRET=...
AUTHELIA_SESSION_DOMAIN=...
AUTHELIA_TOTP_ISSUER=...
TRAEFIK_CERTIFICATERESOLVERS_LE_ACME_EMAIL=...
```
The value of those depend on your setup and can be found in the Traefik and Authelia documentation.
## Networks
For the docker setup of my home server, I have create four specific docker networks
### LAN
A macvlan network with full network and internet access
Containers on this network will be provided an IP on my local home LAN and have direct access to it as if they were using the Host network setting.
Containers get IPs in the range 192.168.1.128-192.168.1.254
```
subnet: 192.168.1.0/23
range: 192.168.1.128/25
gateway: 192.168.0.1
parent: eno1
```
### IOT
A macvlan set to my VLAN for IOT things. Machines on this do not have access to the LAN or to the internet, with a few exceptions (ex. NTP server access).
Containers get IPs in the range 192.168.2.9-192.168.2.127
```
subnet: 192.168.2.0/24
range: 192.168.2.0/25
gateway: 192.168.2.1
parent: eno1:10
```
### GUEST
A macvlan set to my VLAN for guest WIFI. Machines on this have access to the internet, but not to the local LAN.
```
subnet: 192.168.5.0/24
range: 192.168.5.0/26
gateway: 192.168.2.1
parent: eno1:20
```
### WEB
A bridge network for containers that shall be accessible by web interface. Routed by Traefik.
## Lessons learned
- Authelia will ONLY work with https. Both the authelia url itself and the one being authenticated must be https.
- The authorization link should NOT end with `/#/` or `/%2F/` or anything, just `/`. Otherwise it will not redirect you back after authorizing.
# Docker-compose pieces that depend on this
- [SSH entrypoint](/thomas/docker-ssh/)
- [Home Automation](/thomas/docker-ha/)
- [GIT server](/thomas/docker-git/)
- [Plex media server](/thomas/docker-plex/)

View File

@@ -1,36 +1,38 @@
host: 0.0.0.0 # log:
port: 9091 # level: debug
logs_level: trace
jwt_secret: {{ env.Getenv "PRIVATE_DOMAIN" }}-jwt-secret theme: auto
authentication_backend: authentication_backend:
file: file:
path: /opt/authelia/users_database.yml path: /config/users_database.yml
# {{ env.Getenv "ROOT_DOMAIN" }}
session: session:
name: authelia_session # domain: SET BY ENV VARIABLE AUTHELIA_SESSION_DOMAIN
secret: {{ env.Getenv "PRIVATE_DOMAIN" }}-token-secret # secret: SET BY ENV VARIABLE AUTHELIA_SESSION_SECRET
domain: {{ env.Getenv "PRIVATE_DOMAIN" }}
expiration: 3600
inactivity: 300
storage: storage:
local: local:
path: /opt/authelia/db.sqlite3 path: /config/db.sqlite3
totp:
issuer: {{ env.Getenv "PRIVATE_DOMAIN" }}
access_control: access_control:
default_policy: one_factor default_policy: two_factor
networks:
- name: internal
networks:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/18
rules:
regulation: # Allow free access from local network
max_retries: 1000 - domain:
find_time: 120 - "*.se"
ban_time: 300 - "*.com"
networks:
- internal
policy: bypass
notifier: notifier:
filesystem: filesystem:
filename: /opt/authelia/notification.txt filename: /config/notification.txt

View File

@@ -1,98 +1,150 @@
version: "3.5" version: "2.4"
networks: networks:
web: web:
external: false # All containers that are routed through traefik needs to be on this network
name: web external: true
volumes:
authelia-config:
services: services:
proxy:
container_name: traefik # Autheal will restart any container that has the label
image: traefik:v2.1 # autoheal: true
# and fail their healthcheck
autoheal:
container_name: autoheal
restart: always restart: always
image: willfarrell/autoheal
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Traefik reverse proxy. Routes http and ssh trafic to the righ containers
# Controlled by container labels, see bottom of this compose file
traefik:
container_name: traefik
image: traefik
restart: always
depends_on:
- authelia
environment: environment:
- EMAIL - EMAIL
- PRIVATE_DOMAIN - PRIVATE_DOMAIN
- PUBLIC_DOMAIN - PUBLIC_DOMAIN
- TRAEFIK_CERTIFICATERESOLVERS_LE_ACME_EMAIL
networks: networks:
- web web:
ipv4_address: 172.18.1.2
command: command:
- "--configFile=/data/traefik.yaml" - "--configFile=/data/traefik.yaml"
ports: ports:
- "80:80" - 80:80
- "443:443" - 443:443
- "8080:8080" # Open port 8080 for debugging emergencies
- 8080:8080
volumes: volumes:
- "/var/run/docker.sock:/var/run/docker.sock" - /var/run/docker.sock:/var/run/docker.sock
- "./traefik:/data" - ./traefik:/data
- /var/log/traefik:/log
healthcheck:
# Sometimes, traefik loses connection to authelia. The only thing that works then is a restart, handled by autoheal.
# I haven't checked for quite a while if this is still a problem, but might as well leave it in there.
test: ["CMD", "wget", "-O", "-", "authelia:9091/api/state"]
labels: labels:
- "traefik.enable=true" traefik.enable: true
- "traefik.http.services.traefik.loadbalancer.server.port=8080" traefik.http.services.traefik.loadbalancer.server.port: 8080
traefik.http.routers.traefik.rule: Host(`traefik.${PRIVATE_DOMAIN}`)
traefik.http.routers.traefik.middlewares: auth@file
traefik.http.routers.traefik.tls.certResolver: le
autoheal: "true"
- "traefik.http.routers.traefik.rule=Host(`traefik.${PRIVATE_DOMAIN}`)" # Authelia handles access control with 2FA
- "traefik.http.routers.traefik.middlewares=auth@file"
- "traefik.http.routers.traefik.tls.certResolver=le"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redir@file"
authelia-config:
image: hairyhenderson/gomplate
environment:
- PRIVATE_DOMAIN
- PUBLIC_DOMAIN
volumes:
- ./authelia/configuration.yml:/data/input:ro
- authelia-config:/data/output
command: '--file=/data/input --out=/data/output/configuration.yml'
authelia: authelia:
container_name: authelia container_name: authelia
image: authelia/authelia image: authelia/authelia
restart: always restart: always
links:
- authelia-config
volumes: volumes:
- ./authelia:/opt/authelia - ./authelia:/config
- authelia-config:/etc/authelia/
environment: environment:
- ENVIRONMENT=dev # - ENVIRONMENT=dev
- NODE_TLS_REJECT_UNAUTHORIZED=1 - NODE_TLS_REJECT_UNAUTHORIZED=1
- AUTHELIA_JWT_SECRET
- AUTHELIA_SESSION_SECRET
- AUTHELIA_SESSION_DOMAIN
- AUTHELIA_TOTP_ISSUER
- TZ=Europe/Stockholm
networks: networks:
- web web:
healthcheck:
test: ["CMD", "wget", "-O", "-", "127.0.0.1:9091/api/state"]
labels: labels:
- "traefik.enable=true" traefik.enable: true
- "traefik.http.routers.authelia.rule=Host(`auth.${PRIVATE_DOMAIN}`)" traefik.http.routers.authelia.rule: Host(`auth.${PRIVATE_DOMAIN}`)
- "traefik.http.routers.authelia.tls=true" traefik.http.routers.authelia.tls.certResolver: le
- "traefik.http.routers.authelia.tls.certResolver=le" traefik.http.routers.authelia.entrypoints: websecure
- "traefik.http.routers.authelia.entrypoints=websecure" autoheal: "true"
# whoami-http: # Homer provides a dashboard for all services. Configured through ./homer/config.yml
# image: containous/whoami homer:
# networks: container_name: homer
# - web image: b4bz/homer
# labels: restart: always
# - "traefik.enable=true" volumes:
# - "traefik.http.routers.whoami2.rule=Host(`wai-http.${PRIVATE_DOMAIN}`)" - ./homer:/www/assets
# environment:
# whoami-https: UID: 1000
# image: containous/whoami GID: 1001
# networks: networks:
# - web web:
# labels: labels:
# - "traefik.enable=true" traefik.enable: true
# - "traefik.http.routers.whoami.rule=Host(`wai-https.${PRIVATE_DOMAIN}`)" traefik.http.routers.homer.rule: Host(`${PRIVATE_DOMAIN}`) || Host(`www.${PRIVATE_DOMAIN}`)
# - "traefik.http.routers.whoami.tls.certResolver=le" traefik.http.routers.homer.tls.certResolver: le
# whoami-auth: # Dozzle is an easy way to view docker logs through a web interface
# image: containous/whoami dozzle:
# networks: image: amir20/dozzle
# - web restart: always
# labels: volumes:
# - "traefik.enable=true" - /var/run/docker.sock:/var/run/docker.sock
# - "traefik.http.routers.wai.rule=Host(`wai-auth.${PRIVATE_DOMAIN}`)" networks:
# - "traefik.http.routers.wai.tls.certResolver=le" web:
# - "traefik.http.routers.wai.middlewares=auth@file" labels:
traefik.enable: true
traefik.http.routers.dozzle.rule: Host(`logs.${PRIVATE_DOMAIN}`)
traefik.http.routers.dozzle.tls.certResolver: le
traefik.http.routers.dozzle.middlewares: auth@file
analytics:
image: gregyankovoy/goaccess
volumes:
- ./analytics:/config
- /var/log/traefik:/opt/log
networks:
web:
labels:
traefik.enable: true
traefik.http.routers.analytics.rule: Host(`analytics.${PRIVATE_DOMAIN}`)
traefik.http.routers.analytics.tls.certResolver: le
traefik.http.routers.analytics.middlewares: auth@file
# labels:
# The following three labels are always needed. Make sure to replace <SERVICE> with a unique name
# traefik.enable: true
# traefik.http.routers.<SERVICE>.tls.certResolver: le
# traefik.http.routers.<SERVICE>.rule: Host(`<SERVICE>.${PRIVATE_DOMAIN}`)
# Alternatives:
# traefik.http.routers.<SERVICE>.rule: Host(`<SERVICE>.${PUBLIC_DOMAIN}`)
# traefik.http.routers.<SERVICE>.rule: Host(`<SERVICE>.${PRIVATE_DOMAIN}`) || HOST(`<SERVICE>.${PUBLIC_DOMAIN}`)
# Require authentication:
# traefik.http.routers.<SERVICE>.middlewares: auth@file
# If more than one port is exposed by the container:
# traefik.http.services.<SERVICE>.loadbalancer.server.port: <PORT>
# If container uses more than one network:
# traefik.docker.network: web
# Restart automatically if healthchech fails:
# autoheal: "true"

View File

@@ -0,0 +1,45 @@
# This file contains routing rules for netwok services that are not running on the same host as traefik
http:
services:
pfsense:
loadBalancer:
servers:
- url: http://192.168.0.1:80
proxmox:
loadBalancer:
servers:
- url: https://192.168.0.10:8006
prusa:
loadBalancer:
servers:
- url: http://192.168.0.14
routers:
pfsense:
service: pfsense
rule: Host(`pfsense.{{ env "PRIVATE_DOMAIN" }}`)
middlewares:
- auth
tls:
certResolver: le
proxmox:
service: proxmox
rule: Host(`proxmox.{{ env "PRIVATE_DOMAIN" }}`)
middlewares:
- auth
tls:
certResolver: le
prusa:
service: prusa
rule: Host(`prusa.{{env "PRIVATE_DOMAIN"}}`)
middlewares:
- auth
tls:
certResolver: le

View File

@@ -0,0 +1,39 @@
# This file contains services for security and authorization
http:
services:
http-catchall:
# A dummy service for the http-catchall rule
loadBalancer:
servers:
- url: http://dummy-url
routers:
http-catchall:
# Catch all requests to the http entrypoint and redirect them to https
service: http-catchall
rule: hostregexp(`{host:.+}`)
entryPoints:
- web
middlewares:
- redir
middlewares:
redir:
# Redirect to https
redirectScheme:
scheme: https
permanent: true
auth:
# Go through authelia for authorization
forwardAuth:
address: http://authelia:9091/api/verify?rd=https://auth.{{ env "PRIVATE_DOMAIN" }}/
trustForwardHeader: true
authResponseHeaders:
- X-Remote-User
- Remote-User
- X-Remote-Groups
- Remote-Groups
tls:
insecureSkipVerify: true

View File

@@ -1,28 +0,0 @@
http:
middlewares:
redir:
redirectScheme:
scheme: https
permanent: true
auth:
forwardAuth:
address: http://authelia:9091/api/verify?rd=https://auth.{{ env "PRIVATE_DOMAIN" }}/%23/
trustForwardHeader: true
authResponseHeaders:
- X-Forwarded-User
insecureSkipVerify: true
services:
hass:
loadBalancer:
servers:
- url: http://192.168.0.10:8123
routers:
hass:
service: hass
rule: Host(`avagen.{{ env "PRIVATE_DOMAIN" }}`)
middleware: redir
tls:
certResolver: le

View File

@@ -1,15 +1,22 @@
api: api:
insecure: true insecure: true
serversTransport:
insecureSkipVerify: true
providers: providers:
file: file:
filename: /data/tls.yaml directory: /data/config
docker: docker:
exposedByDefault: false exposedByDefault: false
log: log:
filePath: /data/traefik.log filePath: /data/traefik.log
level: DEBUG level: INFO
# level: DEBUG
accessLog:
filePath: /log/access.log
entryPoints: entryPoints:
web: web:
@@ -20,7 +27,9 @@ entryPoints:
certificatesResolvers: certificatesResolvers:
le: le:
acme: acme:
email: '{{ env "EMAIL" }}' # email: SET BY ENV VARIABLE TRAEFIK_CERTIFICATERESOLVERS_LE_ACME_EMAIL
storage: /data/acme.json storage: /data/acme.json
httpChallenge: httpChallenge:
entrypoint: web entrypoint: web
# UNCOMMENT NEXT ROW FOR EXPERIMENTATION
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory