check / check (push) Successful in 2m14s
BREAKING CHANGE: PASSWORD is gone and AUTH and CERTRESOLVER are required. The server's compose.yaml and .env must be updated in the same deploy — the new image ignores PASSWORD, and the old one refuses to start without it. Authelia now sits in front of Traefik, so the app was asking for a second password at the same door. Two prompts, and the weaker of the two was the one holding a single shared secret with no sessions, no MFA and no revocation. Deleting it is the whole change: Authelia already does this properly, once, for every service on the host. Gone: auth(), challenge(), the whole of throttle.go and its tests, and golang.org/x/time with them. routes() returns the bare mux, /healthz is an ordinary route on it, and the smoke script drops sixty -u flags. Roughly 230 lines removed and nothing written to replace them. What holds the app up now, both asserted in compose.yaml: - The router names the Authelia middleware through AUTH. Traefik takes a router out of service when its middleware does not resolve, so a typo or an unset variable fails shut rather than serving the app open. - The container still publishes no ports, so the proxy is the only thing that can reach it. Publishing 8080 would now bypass authentication outright, not merely TLS — the comment there says so. certresolver replaces the bare tls=true, parameterised as CERTRESOLVER: the server had been carrying that label by hand since the first deploy. Naming a resolver implies tls=true, so it stays one label. TestAuth and TestHealthzSkipsAuth are replaced by one test asserting every route answers without credentials — a 401 from here would now mean auth had crept back in.
45 lines
1.8 KiB
YAML
45 lines
1.8 KiB
YAML
services:
|
|
app:
|
|
image: ${REPO:?set REPO in .env}:${TAG:-latest}
|
|
restart: unless-stopped
|
|
|
|
# A bind mount rather than a named volume: the database sits in ./data on
|
|
# the host, where it can be listed, copied and backed up without going
|
|
# through the container engine. The image runs as UID 65534, so the
|
|
# container has to be told which host user owns that directory.
|
|
#
|
|
# PUID/PGID rather than UID/GID: UID is a read-only variable in bash, so a
|
|
# value set here would be silently replaced by the invoking shell's own.
|
|
user: "${PUID:-1000}:${PGID:-1000}"
|
|
volumes:
|
|
- ./data:/data
|
|
|
|
environment:
|
|
DB: /data/foodster.db
|
|
ENV: ${ENV:-prod}
|
|
TZ: ${TZ:-Europe/Helsinki}
|
|
|
|
# No published ports: Traefik reaches the container over the shared
|
|
# network. Publishing 8080 as well would put an unencrypted copy of the
|
|
# app on the host, bypassing TLS — and, now that the app has no login of
|
|
# its own, bypassing authentication entirely.
|
|
#
|
|
# The middleware is the only thing standing in front of the app. If AUTH
|
|
# is unset or names a middleware Traefik does not know, Traefik takes the
|
|
# router out of service rather than serving it open, so a typo fails shut.
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.http.routers.foodster.entrypoints=websecure
|
|
- traefik.http.routers.foodster.rule=Host(`${HOST:?set HOST in .env}`)
|
|
# Naming a resolver implies tls=true, so this is one label, not two.
|
|
- traefik.http.routers.foodster.tls.certresolver=${CERTRESOLVER:?set CERTRESOLVER in .env}
|
|
- traefik.http.routers.foodster.middlewares=${AUTH:?set AUTH in .env, e.g. authelia@docker}
|
|
- traefik.http.services.foodster.loadbalancer.server.port=8080
|
|
- traefik.docker.network=traefik
|
|
networks:
|
|
- traefik
|
|
|
|
networks:
|
|
traefik:
|
|
external: true
|