@xataz Je reviens vers toi pour une suggestion que j'ai appliquée à mon traefik. Par défaut, l'image traefik utilise root. C'est pas idéal pour quelque chose d'exposé comme ça. Dans le docker-compose on peut ajouter la directive :

user: 1234:1234

Pouf, plus de root !

Problème n°1 : traefik ne peut pas utiliser les ports 80/443 dans le conteneur.
Solution : utiliser 8080/4430 et le port remapping (+ modifier les entrypoints) pour que ce soit 80/443 sur l'host.

Problème n°2 : pour ceux qui le montaient, on ne peut plus utiliser le socket.
Solution : déployer un proxy pour le socket sur un réseau propre, ce qui est déjà plus sûr.

  socket-proxy:
    image: tecnativa/docker-socket-proxy
    container_name: socket-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - CONTAINERS=1
    networks:
      - socket_network

traefik doit accéder à ce socket_network, et dans la conf on remplace le socket par tcp://socket-proxy:2375. Cette méthode est sympa car en plus l'image tecnativa/docker-socket-proxy verrouille des accès inutiles à l'API.

Voilà voilà, chez moi ça fonctionne bien comme hardening, pourquoi pas répandre ça dans le tuto. 😄

    Wonderfall J'ai une autre solution chez moi, docker tourne avec un usernamespace, comme ça, le root de traefik correspond en faite UID 231072.

    Ensuite pour le socket, y'avais effectivement la solution du proxy, ou alors utiliser les ACLs directement sur le socket.

    J'ai essayer de faire quelques choses de générique, et je pensais justement faire un tuto sur la sécurité de docker, avec justement ces problématiques.

    J'aime bien l'idée du namespace, malheureusement je ne sais pas si c'est adaptable à tous les cas. Jamais essayé pour cette raison, je préfère vérifier conteneur/conteneur ce qu'il s'y passe. Mais c'est une solution aussi !

    Merci pour ces explications c'est vraiment très clair !
    J'ai deux petites remarques :
    Dans le docker-compose tu map /etc/traefik/conf.d mais dans le provider file tu as mis /etc/traefik/conf/
    Dans les exemples de middlewares basicAuth il faut bien mettre le A en majuscule sinon le middleware est invalide

    Je rencontre un problème mais je fouille encore, traefik me dit que mes routeurs utilises un resolver qui n'existe pas... mais une fois réglé tout sera bon !

      Banip Merci pour tes remontés, c'est corrigé

      ça se fait de signaler un sujet parce qu'il est beaucoup trop stylé ? 🤣

      Merci en tout cas ! J'ai trouvé dans les quelques lignes que j'ai lu la motivation nécessaire pour tenter un passage de mon "bon vieux" nginx vers cette v2 fort prometteuse.

      Je teste ça au plus vite et je tenterais un petit retour bien propre ici pour y poser mon avis 😉

      5 jours plus tard

      Hello, avant tout super article ! Je rejoins totalement le fait que tout se ressemble concernant les explications de Traefik sauf cette page ! J'avais déjà appris "à la dure" ( voir très dure ... :p ) mais j'ai pu approfondir voir découvrir des nouvelles choses donc merci !
      J'ai une grosse question concernant les redirections HTTPS ( scheme et redirect to websecure) : Actuellement, nous avons lancé une stack nextcloud sous docker avec la DB sur le host ( non docker donc). Il y a des "lenteurs" concernant les images qui sont balisée en http par ex. Soit c'est lent ou cela n'apparaît tout simplement pas.
      Ces lenteurs n'étaient pas du tout présentes avant traefik ( ca réagissait à la secondes sans "lag"). Faut-il désactiver cette redirection ? Il y a des choses qui se font dans nextcloud vis à vis des proxys mais la c'est du docker .. je pense que cette règle ne s'applique pas. Avez-vous ressentit ce "soucis" ? Bonne soirée

        anoskar salut,

        Si tu ressens des lenteurs, c'est peux être que tu as plusieurs réseaux sous docker, j'ai eu le soucis et en spécifiant le réseaux à utiliser (--traefik.docker.network=traefik-net) ça a corrigé le bug.
        Je pense que dans le cas de plusieurs réseau, il doit tester les réseaux 1 à 1 dans un ordre inconnu.

        Ensuite effectivement tu peux supprimer la redirection, ou créer une règle global (dans les paramètres de lancement de traefik), je n'ai cependant jamais senti de ralentissement du a ceci.

        Autrement si tu étais sous nginx avant, il est possible que le cache soit mieux géré avec qu'avec traefik

        Bonsoir, merci pour cette réponse, je n'ai qu'un seul network de définit. Mais tôt ce matin le problème a été résolu par nos dev. En résumé, les url de certaines images étaient en HTTP et non en HTTPS. Tout est parfaitement réactif. Encore merci ! Bonne soirée

        Merci, un de mes projets était bloqué en traefik 1.7 car j'avais de la diffHHHH flemme pour lire les nouvelles docs, et une fois résumé comme ça, je vais pouvoir m'y remettre 🙂

        12 jours plus tard

        Bonjour,
        Tout d'abord merci pour ce super tuto qui m'a redonné envie de tester "Traefik" que j'avais abandonné !

        J'ai bien suivi à la lettre votre exemple et explications, et lorsque je lance le docker-compose tout se passe bien, les trois services docker sont actifs :

        CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                              NAMES
        7274811ae581        nextcloud:19        "/entrypoint.sh apac…"   45 minutes ago      Up 45 minutes       80/tcp                                                             nextcloud
        844bd0c0cd0a        postgres:12         "docker-entrypoint.s…"   45 minutes ago      Up 45 minutes       5432/tcp                                                           db_nextcloud
        da02512af7ce        traefik             "/entrypoint.sh --gl…"   45 minutes ago      Up 45 minutes       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8080->8080/tcp   traefik

        Toutefois, je rencontre un problème de non génération de certificat SSL, à cause de l'erreur suivante suivante (issue de la log de traefik) :

        time="2020-06-30T18:27:27Z" level=error msg="the router nextcloud-secure@file uses a non-existent resolver: letsencrypt-rsa2048"
        time="2020-06-30T18:27:27Z" level=error msg="the router traefik-secure@file uses a non-existent resolver: letsencrypt-ecdsa"

        Malgré des heures de recherches sur Internet, je n'ai pas résolu le problème.
        Est-ce que vous pourriez m'aider ?
        Par avance, merci.
        Ricardo

          rican Salut,

          Pourrais-tu fournir tes fichiers de configuration pour voir d'où viens le problème, ainsi que la log complète de traefik

          Bonjour,
          Par avance, merci pour votre aide.
          Voici les éléments demandés.

          docker logs traefik
          time="2020-07-02T10:06:19Z" level=info msg="Configuration loaded from flags."
          time="2020-07-02T10:06:19Z" level=info msg="Traefik version 2.2.1 built on 2020-04-29T18:02:09Z"
          time="2020-07-02T10:06:19Z" level=info msg="\nStats collection is disabled.\nHelp us improve Traefik by turning this feature on :)\nMore details on: https://docs.traefik.io/contributing/data-collection/\n"
          time="2020-07-02T10:06:19Z" level=info msg="Starting provider aggregator.ProviderAggregator {}"
          time="2020-07-02T10:06:19Z" level=info msg="Starting provider *file.Provider {\"directory\":\"/etc/traefik/conf.d/\",\"watch\":true}"
          time="2020-07-02T10:06:19Z" level=info msg="Starting provider *traefik.Provider {}"
          time="2020-07-02T10:06:19Z" level=error msg="the router nextcloud-secure@file uses a non-existent resolver: letsencrypt-rsa2048"
          time="2020-07-02T10:06:19Z" level=error msg="the router traefik-secure@file uses a non-existent resolver: letsencrypt-ecdsa"
          time="2020-07-02T10:06:20Z" level=error msg="the router traefik-secure@file uses a non-existent resolver: letsencrypt-ecdsa"
          time="2020-07-02T10:06:20Z" level=error msg="the router nextcloud-secure@file uses a non-existent resolver: letsencrypt-rsa2048"
          #/srv/docker/traefik/docker-compose.yml
          version: "3.8"
          networks:
            traefik:
          services:
            traefik:
              image: traefik:chevrotin
              container_name: traefik
              volumes:
                - /srv/docker/traefik/acme.json:/etc/traefik/acme.json
                - /srv/docker/traefik/certs:/etc/traefik/certs
                - /var/run/docker.sock:/var/run/docker.sock
                - /srv/docker/traefik/conf.d:/etc/traefik/conf.d
              ports:
                - 80:80
                - 443:443
                - 8080:8080 # le temps de tester
              networks:
                - traefik
              command:
                - "--global.sendanonymoususage=false" # désactivation de l'envoi de donnée
                - "--global.checknewversion=false" # puisque dockerisé, on désactive le check de mise à jour
                - "--accesslog=true" # Pour avoir les logs d'accès
                - "--api=true" # Pour activer l'api
                - "--api.insecure=true" # Activer pour exposer l'api sur 8080
                - "--api.dashboard=true" # Pour activer le dashboard
                - "--log.level=INFO"
                - "--providers.file.directory=/etc/traefik/conf.d/" # Permets de charger les configurations dans le répertoire (tout les yaml et toml)
                - "--providers.file.watch=true" # Permets de surveiller le répertoire précédent pour charger dynamiquement les configurations
                - "--entrypoints.web.address=:80" # Création de l'entrypoint nommé web sur le port 80
                - "--entrypoints.websecure.address=:443" # Création de l'entrypoint nommé websecure sur le port 443
                #- "--entrypoints.web.http.redirections.entrypoint.scheme=https" # Pour créer une redirection vers https
                #- "--entrypoints.web.http.redirections.entrypoint.to=websecure" # Pour rediriger vers l'entrypoint websecure (port 443)
            db_nextcloud:
              image: postgres:12
              container_name: db_nextcloud
              networks:
                - traefik
              volumes:
                - /srv/docker/db_nextcloud/:/var/lib/postgresql/
              environment:
                - POSTGRES_PASSWORD=nextcloud
                - POSTGRES_DB=nextcloud
                - POSTGRES_USER=nextcloud
            nextcloud:
              image: nextcloud:19
              container_name: nextcloud
              networks:
                - traefik
              environment:
                - POSTGRES_HOST=db_nextcloud
                - POSTGRES_DB=nextcloud
                - POSTGRES_USER=nextcloud
                - POSTGRES_PASSWORD=nextcloud
                - NEXTCLOUD_ADMIN_USER=admin
                - NEXTCLOUD_ADMIN_PASSWORD=admin
              volumes:
                - /srv/docker/nextcloud:/var/www/html
          #/serv/docker/traefik/conf.d/auth.yml
          http:
            middlewares:
              admin-users:
                basicAuth:
                  users:
                    - "ricardo:xxxxx" # mot de passe masqué
              dev-users:
                basicAuth:
                  users:
                    - "tata:$apr1$inMBbv02$C/oh3LLEfmmOyloAtqW/V/"
          #/srv/docker/traefik/conf.d/compression.yml
          http:
            middlewares:
              compression:
                compress:
                  excludedContentTypes:
                    - "text/event-stream"
          #/srv/docker/traefik/conf.d/hsts.yml
          http:
            middlewares:
              hsts:
                headers:
                  forceSTSHeader: true
                  stsSeconds: 315360000
                  stsIncludeSubdomains: true
                  stsPreload: true
          #/srv/docker/traefik/conf.d/nextcloud.yml
          http:
            services:
              nextcloud:
                loadBalancer:
                  servers:
                    - url: "http://192.168.1.104:80/cloud"
            routers:
              nextcloud:
                rule: "Host(`xxxxx.ovh`) && PathPrefix(`/cloud`)" # domaine masqué
                entryPoints:
                  - "web"
                middlewares:
                  - "redirect-to-https@file"
                service: "noop@internal"
              nextcloud-secure:
                rule: "Host(`xxxxx.ovh`) && PathPrefix(`/cloud`)" # domaine masqué
                entryPoints:
                  - "websecure"
                middlewares:
                  - "hsts@file"
                  - "security@file"
                  - "compression@file"
                  - "strip-cloud@file"
                service: "nextcloud@file"
                tls:
                  certResolver: letsencrypt-rsa2048
            middlewares:
              strip-cloud:
                stripPrefix:
                  prefixes:
                    - "/cloud"
          #/srv/docker/traefik/conf.d/redirect-to-https.yml
          http:
            middlewares:
              redirect-to-https:
                redirectScheme:
                  scheme: https
                  permanent: true
          #/srv/docker/traefik/conf.d/security.yml
          http:
            middlewares:
              security:
                headers:
                  accessControlMaxAge: 100
                  addVaryHeader: true
                  browserXssFilter: true
                  contentTypeNosniff: true
                  frameDeny: true
                  sslRedirect: true
                  customFrameOptionsValue: "SAMEORIGIN"
                  referrerPolicy: "same-origin"
                  featurePolicy: "vibrate 'self'"
          #/srv/docker/traefik/conf.d/tls.yml
          certificatesResolvers: 
            letsencrypt-ecdsa: # Nom arbitraire, je pourrais mettre toto, ça fonctionne correctement
              acme:
                email: "xxx@xxxxx" # email masqué
                caserver: "https://acme-v02.api.letsencrypt.org/directory"
                storage: "/etc/traefik/acme.json"
                keytype: "EC384"
                httpChallenge:
                  entryPoint: "web"
            letsencrypt-rsa2048: # Nom arbitraire, je pourrais mettre toto, ça fonctionne correctement
              acme:
                email: "xxx@xxxxx" # email masqué
                caserver: "https://acme-v02.api.letsencrypt.org/directory"
                storage: "/etc/traefik/acme.json"
                keytype: "RSA2048"
                httpChallenge:
                  entryPoint: "web"
          tls:
            options:
              default:
                minVersion: "VersionTLS12"
                sniStrict: true
                cipherSuites:
                  - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
                  - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
                  - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
                  - "TLS_ECDHE_RSA_WITH_AES_128_CBC_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:
                  - X25519
                  - CurveP521
                  - CurveP384
                  - CurveP256
              mintls13: # Arbitraire également, toto fonctionne aussi
                minVersion: "VersionTLS13"
          #/serv/docker/traefik/conf.d/traefik.yml
          http:
            services:
              traefik:
                loadBalancer:
                  servers:
                    - url: "http://192.168.1.104:8080"
            routers:
              traefik:
                rule: "Host(`xxxxx.ovh`)" # domaine masqué
                entryPoints:
                  - "web"
                middlewares:
                  - "redirect-to-https@file"
                service: "noop@internal"
              traefik-secure:
                rule: "Host(`xxxxx.ovh`)" # domaine masqué
                entryPoints:
                  - "websecure"
                middlewares:
                  - "hsts@file"
                  - "security@file"
                  - "compression@file"
                  - "admin-users@file"
                service: "traefik@file"
                tls:
                  certResolver: letsencrypt-ecdsa
                  options: mintls13

          Enfin, je précise que la procédure a généré deux dossiers vides

          /serv/docker/traefik/acme.json
          /serv/docker/traefik/certs

            rican Ah le problème viens peux être du acme.json, c'est normalement un fichier, et bizarrement traefik est incapable de le créer.

            Essaie en supprimant le dossier acme.json et en créant un fichier vide (touch acme.json)

            Dans un test précédent, à partir d'un autre tuto, j'avais déjà rencontré le problème du "acme.json" et je l'avais résolu avec les commandes suivantes (trouvées sur Internet)

            sudo touch /srv/docker/traefik/acme.json
            sudo chmod 600 /srv/docker/traefik/acme.json

            Désolé, mais avec ton tuto ça ne fonctionne pas, j'obtiens la même anomalie 😃 !

            Ah merde, je viens de trouver le problème, c'est effectivement un soucis avec mon tuto.

            J'avais la configuration des certResolvers en double, dans le cli, et dans le tls.yml. Mais les certResolver ne fonctionne que dans la configuration static (yml, toml ou cli), et pas dans le providers file.

            Puisque je l'avais en double, forcément dans la rédaction du tuto, ça marchait. Je corrige ça dès que possible

              xataz J'ai vu à l'initialisation de traefik qu'il cherchait un traefik.toml ou yml dans /etc/traefik/, j'ai donc essayé de passer uniquement la config des certResolver dedans mais avoir un fichier lu au démarrage supplante les option passées en CLI donc impossible de faire cohabiter les deux.

              J'ai donc décidé de passer la conf présente dans le docker-compose vers le fichier yml dans /etc/traefik/traefik.yml (penser à ajouter /opt/docker/traefikV2/traefik.yml:/etc/traefik/traefik.yml pour monter le fichier) :

              ## Fichier traefik.yml lu au démarrage
              global:
                checkNewVersion: false
                sendAnonymousUsage: false
              
              providers:
                file:
                  directory: /etc/traefik/conf/
                  watch: true
              
              api:
                insecure: false
                dashboard: true
              
              log:
                level: INFO
                filePath: /etc/traefik/traefik.log
              
              accessLog: true
              
              entryPoints:
                web:
                  address: ":80"
                websecure:
                  address: ":443"
              
              certificatesResolvers:
                letsencrypt-ecdsa:
                  acme:
                    email: test@domain.tld
                    caserver: https://acme-v02.api.letsencrypt.org/directory
                    storage: /etc/traefik/acme.json
                    keytype: EC384
                    httpChallenge:
                      entryPoint: web
                letsencrypt-rsa2048:
                  acme:
                    email: test@domain.tld
                    caserver: https://acme-v02.api.letsencrypt.org/directory
                    storage: /etc/traefik/acme.json
                    keytype: RSA2048
                    httpChallenge:
                      entryPoint: web

              Tout fonctionne, même si j'aurai préféré que traefik puisse gérer les certificatesresolver dynamiquement.

              un mois plus tard

              J'ai modifier le tuto sur la partie Resolver, effectivement impossible de les modifier dynamiquement, dommage

              5 mois plus tard

              Bonjour,

              Pourrais tu revoir le tutorial car il est mal fait en termes d'ordre car je but sur pas mal de chose

              8 jours plus tard

              Bonjour,
              Merci pour le tuto.
              J'ai juste deux petites erreurs que je n'arrive pas à résoudre.

              level=error msg="servers transport not found default@internal" entryPointName=websecure routerName=traefik-secure@file
              
              level=error msg="Unable to obtain ACME certificate for domains \"traefik..xx.xx\": unable to generate a certificate for the domains [traefik.xx.xx]: error: one or more domains had a problem:\n[traefik.xx.xx] [traefik.xx.xx] acme: error presenting token: timeout 2021-01-24 15:41:36.984015158 +0000 UTC m=+54.997971025\n" rule="Host(`traefik.xx.xx`)" routerName=traefik-secure@file providerName=letsencrypt-ecdsa.acme
              

              Merci d'avance