benoegen

Smarthome auf RaspberryPi - Traefik2 Update

30 Mar 2023 - benoegen

Als Hilfe für andere und auch als Gedankenstütze für mich selber möchte ich dokumentieren, wie man ein Smarthome in homeassistant mit weiteren features auf einem RaspberryPi (inzwischen Futro 740) mittels docker-compose aufsetzt.

Mehr Sicherheit mit crowdsec

Update zu meinem Traefik setup: Um weiterhin Bitwarden guten Gewissens verwenden zu können, soll mein Server abgesicherte werden. Dazu gibt es die Möglichkeit, Logins von verdächtigen Ips zu unterbinden, mittels crowdsec und einem sogenannten Bouncer. Ich möchte dafür dem Tutorial von Goneuland folgen. Dafür muss aber die Konfiguration von Traefik etwas umgebaut werden, die Einstellungen sollen in Zukunft nicht mehr in der docker-compose Datei, sondern in einer traefik.yml vorgenommen werden (es geht nur entweder oder) , die aber weiterhin den use case mit duckdns als Domain-Provider abbildet. Durch einen Serverumzug liegen meine Container nicht mehr unter /opt/containers, sondern unter /home/containers ab.

Die neue docker-compose sieht so aus:

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      proxy
    ports:
      - "80:80"
      - "443:443"
    environment:
      - DUCKDNS_TOKEN=XXXXXX
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/containers/traefik/data/acme.json:/acme.json
      - /home/containers/traefik/data/traefik.yml:/traefik.yml:ro
      - /home/containers/traefik/data/dynamic_conf.yml:/dynamic_conf.yml
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`xxx.xxx.duckdns.org`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.middlewares=traefikAuth@file,default@file"
      - "traefik.http.services.dashboard.loadbalancer.server.port=80"
      - "traefik.http.services.dashboard.loadbalancer.sticky.cookie.httpOnly=true"
      - "traefik.http.services.dashboard.loadbalancer.sticky.cookie.secure=true"
      - "traefik.http.routers.dashboard.tls.certresolver=myresolver"
    extra_hosts:
      - host.docker.internal:172.17.0.1

Die traefik.yml sieht so aus und ersetzt damit alle Konfigurationsflags, die vorher in der docker-compose standen:

api:
  dashboard: true
  
global:
  checknewversion: true
  sendanonymoususage: false

certificatesResolvers:
  myresolver:
    acme:
      email: "XXX@XXX.de"
      storage: "acme.json"
      dnsChallenge:
        provider: "duckdns"
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: "websecure"
          scheme: "https"
          
  websecure:
    address: ":443"
    http:
#      middlewares:
#        - "crowdsec-bouncer@file"
      tls:
        certResolver: myresolver
        domains:
          main: XXX.duckdns.org
          sans:
            - "*.XXX.duckdns.org"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: "proxy"
  file:
    filename: "./dynamic_conf.yml"
    watch: true
  providersThrottleDuration: 10

log:
  level: "INFO"
  filePath: "/var/log/traefik/traefik.log"

accessLog:
  filePath: "/var/log/traefik/access.log"
  bufferingSize: 100

Die dynamic folgt den Empfehlungen von goneuland:

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_AES_128_GCM_SHA256
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
      curvePreferences:
        - CurveP521
        - CurveP384
      sniStrict: true

http:
  middlewares:
    traefikAuth:
      basicAuth:
        users:
          - "user:passwort"

    default:
      chain:
        middlewares:
          - default-security-headers
          - gzip

    secHeaders:
      chain:
        middlewares:
          - default-security-headers
          - gzip

    # Standard Header
    default-security-headers:
      headers:
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        frameDeny: true
#       Deprecated
#       sslRedirect: true
        #HSTS Configuration
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 31536000
        customFrameOptionsValue: "SAMEORIGIN"
    # Gzip Kompression
    gzip:
      compress: {}

Mit diesen Anpassungen ist es nun möglich, das goneulandTutorial nahezu 1:1 zu befolgen.

Was dort nicht beschrieben ist, dass man den bouncer am Ende testen kann, indem man seine IP manuell auf die Blacklist setzt. Die IP wird zunächst über whatismyipaddress.com oder eine ähnliche Website ermittelt.

Anschließend setzt man sich mit dem Befehl

docker exec crowdsec-example cscli decisions add --ip xxx.xxx.xxx.xxx

auf die Blockliste. Beim aufrufen der Dienste über traefik müsste nun bei korrekter Konfiguration forbidden angezeigt werden.

Anschließend nimmt man sich selber mit

docker exec crowdsec-example cscli decisions delete --ip xxx.xxx.xxx.xxx

wieder von der Blockliste.

Tags: it