Harden geoblock, remove secrets from config, support dev host
Refs #1 ## Security * Remove the CrowdSec LAPI key from config.yml. Traefik does not interpolate env vars in its YAML config, so the key had to be literal there - which is why the file kept drifting out of version control. It is now defined as a docker-compose label, where compose substitutes ${CROWDSEC_LAPI_KEY} from .env. config.yml is therefore secret-free and stays in git. NOTE: this renames the middleware crowdsec-bouncer@file -> @docker. Site stacks referencing @file must be updated. The old key remains in this repo's history and must still be rotated and scrubbed - removing it here does not un-expose it. * Move the dashboard basic-auth hash out of docker-compose.yml into .env. In .env every '$' must be doubled to '$$', or compose silently collapses the hash to an empty string and the dashboard rejects every password. * Stop publishing port 8080. The API is not insecure-mode, so nothing served there; publishing it only widened exposure. ## Geoblock (the availability fix) * allowUnknownCountries: false -> true. Previously a geojs.io outage made every lookup "unknown" and therefore blocked, taking sites down for US visitors too - a third-party service in the critical path with no degraded mode. Now an outage degrades to "geoblocking ineffective". CrowdSec still blocks actual attackers. * cacheSize: 25 -> 5000. At 25, nearly every visitor triggered a fresh API call, adding up to 750ms and risking rate limits. ## Dev host support * Add traefik.dev.yml, selected by TRAEFIK_STATIC_CONFIG in .env (defaults to traefik.yml, so prod behaviour is unchanged). It differs from traefik.yml ONLY in the ACME challenge type: public port 80 forwards to prod for its renewals, so an HTTP-01 challenge for a dev hostname hits prod's Traefik, matches no router, and 404s. Dev uses DNS-01 via Route 53 instead, which needs no inbound connectivity. * Add .env.example documenting every variable. ## Captured from prod's working tree Prod had uncommitted drift; these were running but never committed: plugin bumps (bouncer v1.3.3->v1.3.5, geoblock v0.2.7->v0.2.8), the entryPoints HTTP->HTTPS redirect with priority 1, and httpClientTimeout: 0. The priority: 1 on that redirect is load-bearing - it keeps the redirect below normal routers so basil's Host(`localhost`) HTTP route still serves. Do not raise it. ## Verified on dev (prkl10), Traefik 3.7.10 7 routers / 8 middlewares, 0 warnings, 0 errors. Certificates issued via DNS-01. pihole and technitium routers preserved. Sites serving 200.
This commit is contained in:
81
traefik.dev.yml
Normal file
81
traefik.dev.yml
Normal file
@@ -0,0 +1,81 @@
|
||||
# Traefik static configuration — DEV host (prkl10) ONLY.
|
||||
#
|
||||
# Identical to traefik.yml except for the ACME challenge type. Select it with
|
||||
# TRAEFIK_STATIC_CONFIG=./traefik.dev.yml in .env.
|
||||
#
|
||||
# Keep any other change in BOTH files, or dev stops mirroring prod.
|
||||
|
||||
api:
|
||||
dashboard: true
|
||||
debug: false
|
||||
|
||||
experimental:
|
||||
plugins:
|
||||
bouncer:
|
||||
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
|
||||
version: v1.3.5
|
||||
geoblock:
|
||||
moduleName: github.com/PascalMinder/geoblock
|
||||
version: v0.2.8
|
||||
|
||||
entryPoints:
|
||||
http:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: https
|
||||
scheme: https
|
||||
permanent: true
|
||||
# priority 1 keeps this redirect BELOW normal routers, which default
|
||||
# to a priority derived from rule length. That is what allows basil's
|
||||
# Host(`localhost`) HTTP router to keep serving without redirecting.
|
||||
# Do not raise this value.
|
||||
priority: 1
|
||||
https:
|
||||
address: ":443"
|
||||
|
||||
# Backends here use self-signed certs (harbor, etc). This disables verification
|
||||
# of upstream TLS for ALL services — matches prod, but it is a real weakening.
|
||||
# Prefer per-service serversTransport if you ever narrow this.
|
||||
serversTransport:
|
||||
insecureSkipVerify: true
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
network: traefik
|
||||
httpClientTimeout: 0
|
||||
file:
|
||||
filename: /config.yml
|
||||
watch: true
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: pkartch@gmail.com
|
||||
storage: acme.json
|
||||
# DNS-01, not HTTP-01. Public port 80 forwards to prod (10.20.10.18) so
|
||||
# that it can renew production certs, which means an HTTP-01 challenge for
|
||||
# a dev hostname lands on prod's Traefik, finds no matching router, and
|
||||
# returns 404. DNS-01 proves control via a Route 53 TXT record instead and
|
||||
# needs no inbound connectivity at all.
|
||||
#
|
||||
# Credentials come from AWS_* in .env (IAM user traefik-dev-dns01, scoped
|
||||
# to the backyardhoneycomb.com and pkartchner.com zones).
|
||||
dnsChallenge:
|
||||
provider: route53
|
||||
# Check propagation against public resolvers. The LAN resolvers
|
||||
# (Pi-hole / Technitium) answer authoritatively for internal names and
|
||||
# will not see the _acme-challenge TXT records, so leaving this unset
|
||||
# makes the pre-check hang until it times out.
|
||||
resolvers:
|
||||
- "1.1.1.1:53"
|
||||
- "8.8.8.8:53"
|
||||
|
||||
log:
|
||||
level: INFO
|
||||
|
||||
accessLog:
|
||||
filePath: "/var/log/traefik/access.log"
|
||||
Reference in New Issue
Block a user