Traefik v2 z certyfikatami TLS/SSL na localhost

Grudzień 12, 2023 | #localhost , #traefik

000100
011010
000000
110001

Krótko o tym co to jest TLS, SSL i HTTPS

TLS, SSL i HTTPS to terminy odnoszące się do protokołów komunikacyjnych używanych w internecie. Każdy z nich pełni kluczową rolę w przesyłaniu danych w sieci.

TLS (Transport Layer Security) to kryptograficzny protokół służący do zapewnienia bezpiecznego przesyłania danych między dwoma systemami komputerowymi. Jest stosowany w takich sytuacjach jak przeglądanie stron internetowych (HTTPS), wysyłanie e-maili (IMAP i SMTP), przesyłanie wiadomości i inne transmisje danych. Protokół ten używa szyfrowania do zabezpieczenia danych przesyłanych między klientem (np. przeglądarką internetową) a serwerem. Obejmuje to proces wymiany kluczy, uwierzytelniania, szyfrowania i utrzymania integralności danych. Jest następcą i ulepszoną wersją SSL (Secure Sockets Layer).

Co do SSL to warto wspomnieć, że współcześnie termin "SSL" jest często używany w kontekście certyfikatów (np. certyfikaty SSL), mimo że rzeczywiste połączenia są zabezpieczane za pomocą protokołu TLS.

HTTPS (Hypertext Transfer Protocol Secure), jest rozszerzeniem HTTP będącego standardowym protokołem używany do przesyłania dokumentów hipertekstowych, takich jak strony WWW i dodaje do HTTP dodatkową warstwę szyfrowania zapewnianą przez TLS.

Dlaczego warto używać TLS/SSL i HTTPS

Krótka odpowiedź brzmi - dla bezpieczeństwa. Pozwolę sobie jednak nieco szerzej omówić kluczową rolę jaką protokoły TLS i HTTPS odgrywają w wiarygodności stron internetowych.

HTTPS zapewnia szyfrowanie danych

Przede wszystkim HTTPS zapewnia szyfrowanie danych przesyłanych między przeglądarką użytkownika a serwerem. Oznacza to, że wszelkie informacje wrażliwe, takie jak dane logowania, informacje osobiste, dane płatności, są chronione przed przechwyceniem przez osoby trzecie.

HTTPS a ataki Man-in-the-Middle i integralność danych

Szyfrowanie zabezpiecza także przed atakami typu "Man-in-the-Middle" (MitM), gdzie atakujący może przechwycić lub zmodyfikować dane przesyłane między użytkownikiem a witryną. Jest to ważne również z punktu widzenia integralności informacji.

Wymagalność szyfrowania dla nowoczesnych funkcji przeglądarek internetowych

W nowoczesnych przeglądarkach kładzie się duży nacisk na bezpieczeństwo i nowe funkcje typu geolokalizacje, czy powiadomienia push są realizowane tylko z użyciem połączeń szyfrowanych.

Regulacje prawne wymuszające zabezpieczanie ruchu sieciowego

Istnieją także powody pozatechniczne takie jak zgodność z regulacjami prawa: Wiele przepisów dotyczących ochrony danych (takich jak ogólne rozporządzenie o ochronie danych osobowych w Unii Europejskiej - GDPR) wymaga odpowiedniego zabezpieczenia danych osobowych, do czego należy zaliczyć również transmisję danych przez internet. HTTPS jest kluczowym elementem spełniania tych wymogów.

Wiarygodność stron zabezpieczonych certyfikatami TLS/SSL

Użytkownicy przyzwyczaili się już do widoku kłódki na pasku adresu w przeglądarce internetowej. Nie tylko strony banków, ale także sklepy czy dowolny inny serwis pozyskujący dane od użytkowników nie może się już dziś obejść bez tej formy zabezpieczenia, która wymiernie wpływa na wiarygodność i zaufanie internautów.

HTTPS wyżej pozycjonowane

Google i inne wyszukiwarki preferują witryny zabezpieczone HTTPS, traktując je jako jeden z czynników rankingowych. Oznacza to, że strony z HTTPS mogą być wyżej pozycjonowane w wynikach wyszukiwania a tego nie powinni ignorować nawet autorzy amatorskich witryn.

Developing aplikacji na na localhost z HTTPS

Instalowanie certyfikatów TLS/SSL na localhost wymaga dodatkowego wysiłku i zrozumienia i może wydawać się nadmiarowe, ponieważ komunikacja odbywa się wewnątrz lokalnego komputera, a nie przez internet. Ponadto przeglądarki traktują http://localhost w specjalny sposób. Pomimo tego że odwołujesz się jawnie do protokołu HTTP jest on dla tej domeny traktowany jak HTTPS.

Jednakże istnieje kilka ważnych powodów, dla których deweloperzy mogą chcieć to robić:

Gdy nie używasz na komputerze lokalnym domeny localhost

Przede wszystkim będziesz potrzebował tego jeśli rozwijasz aplikację na komputerze lokalnym i zamiast http://localhost używasz niestandardowej domeny np. http://myproject.local. W takim przypadku wiele z nowoczesnych mechanizmów przeglądarek wymagających określonych gwarancji bezpieczeństwa jak choćby interfejs uwierzytelniania płatności nie będzie działać.

Zrozumienie procesu certyfikacji

Kolejnym z powodów jest możliwość nauczenia się jak zapewnić bezpieczne połączenia. Obejmuje to skonfigurowanie odpowiednich portów (domyślnie HTTPS używa portu 443) , instalację i konfigurację certyfikatu SSL/TLS, ustawienie przekierowań, aby wszelki ruch sieciowy kierowany na stronę za pomocą HTTP był automatycznie przekierowywany na bezpieczne połączenie HTTPS. Deweloperzy mogą potrzebować testować logikę i zachowanie aplikacji związaną z certyfikatami, np. odnowienie certyfikatu, reakcję na niezaufane certyfikaty itp.

Symulacja środowiska produkcyjnego

Większość aplikacji webowych używa szyfrowania w produkcji, więc testowanie ich z użyciem TLS/SSL na lokalnym komputerze pozwala na wykrycie problemów związanych z szyfrowaniem przed wdrożeniem.

Bezpieczne ciasteczka

Ustawianie bezpiecznych plików cookie oznaczonych flagami Secure (ale nie tylko), wymaga bezpiecznego połączenia. Skonfigurowanie certyfikatów może okazać się niezbędne bo różne przeglądarki, różnie się zachowują w tym zakresie i na czas pisania tego artykułu Chromie i Safari nie wspierały tej funkcjonalności na localhost.

Mieszana zawartość

Aby zapewnić bezpieczeństwo serwisowi nie wystarczy podpiąć certyfikaty do domeny, pod którą będzie bezpieczny należy także zaktualizować wszystkie wewnętrzne linki i odwołania do zasobów (takie jak obrazy, arkusze stylów CSS, skrypty JavaScript) tak, aby korzystały z HTTPS. Dotyczy to również zewnętrznych zasobów, które powinny być ładowane przez HTTPS, aby uniknąć ostrzeżeń o mieszanej zawartości. Na http://localhost nie jesteśmy w stanie zdiagnozować tego problemu i może on nas zaskoczyć dopiero po opublikowaniu na serwerze.

Zalety protokołu HTTP/2

Protokół HTTPS dzięki HTTP/2, działa wydajniej i szybciej ładuje strony w przeglądarce. Chcąc przetestować lub odtworzyć jakieś charakterystyczne zachowania dla tego protokołu trzeba go użyć.

Zewnętrzne zasoby wymagające HTTPS-a

Wdrożenia bibliotek lub lub interfejsów API innych firm wymagających protokołu HTTPS (na przykład OAuth) także może nas zmusić do zainstalowania certyfikatów TLS/SSL na komputerze lokalnym.

Skonfigurowanie bezpiecznego połączenia HTTPS na localhost z użyciem Traefika i Mkcert

Skoro już wiemy dlaczego moglibyśmy chcieć rozwijać nasze oprogramowanie webowe w środowisku lokalnym z użyciem HTTPS-a warto dowiedzieć się jak to zrobić w prosty sposób.

Projekt zakłada następującą strukturę katalogów i plików

> traefik
  > certs
  | | local-cert.pem
  | | local-key.pem
  > config
  | | dynamic.yml
  | | traefik.yml
  | docker-compose.yml
  | docker-compose.whoami.yml

Na początek wypada zainstalować Mkcert i w tym punkcie odsyłam do instrukcji na oficjalnej stronie tego narzędzia.

Jeśli jesteś przed pierwszym użyciem Mkcert wywołaj jeszcze

mkcert -install

Zakładam, że jesteś w katalogu ./traefik i możesz teraz wygenerować certyfikaty dla domen docker.localhost i domain.local i ich subdomen.

mkcert -cert-file ./certs/local-cert.pem -key-file ./certs/local-key.pem \
"docker.localhost" "*.docker.localhost" "domain.local" "*.domain.local"

Resztę plików musimy stworzyć sami:

Zaczniemy od docker-compose.yml

version: '3'

services:
  reverse-proxy:
    # Oficjalny obraz Dokera z Traefik v2
    image: traefik:v2.10
    security_opt:
      - no-new-privileges:true
    ports:
      # Numer portu dla HTTP
      - "80:80"
      # Numer portu dla HTTPS
      - "443:443"
    volumes:
      # Aby Traefik mógł słuchać zdarzeń Dockera
      - /var/run/docker.sock:/var/run/docker.sock:ro
      # Podmapowanie statycznej konfiguracji
      - ./config/traefik.yml:/etc/traefik/traefik.yml:ro
      # Podmapowanie dynamicznej konfiguracji
      - ./config/dynamic.yml:/etc/traefik/dynamic.yml:ro
      # Podmapowanie certyfikatów
      - ./certs:/etc/certs:ro
    networks:
      - traefik_network

networks:
  traefik_network:
    external: true

Potrzebna jest jeszcze konfiguracja

Statyczna traefik.yml

global:
  # Jeśli chcesz pomóc w rozwoju Traefika możesz nie negować tej opcji,
  # ale logi z użycia na localhost mają ograniczoną wartość.
  sendAnonymousUsage: false

api:
  # Włącza dashboard Traefika
  dashboard: true
  # Umożliwia dostęp do dashboardu za pośrednictwem
  # punktu końcowego o nazwie traefik.
  # Domyślnie dostępny pod portem 8080 ale w pliku 
  # dynamic.yml zostało to przekonfigurowane.
  insecure: true

providers:
  docker:
    # Punkt końcowy serwera Docker. 
    # Może to być punkt końcowy protokołu TCP lub gniazda Unix. 
    endpoint: "unix:///var/run/docker.sock"
    # Chcemy aby Traefik obserwował zmiany w Dokcerze
    watch: true
    # Dzięki temu kontenery, które nie mają etykiety
    # `traefik.enable=true` będą ignorowane.
    exposedByDefault: false

  file:
    # Odniesienie do dynamicznej konfiguracji
    filename: /etc/traefik/dynamic.yml
    watch: true

log:
  # Poziom i format logowania 
  level: INFO
  format: common

entryPoints:
  # Nazwa endpointa
  web:
    address: ":80"
    http:
      # Chcemy aby połączenia po HTTP były
      # przekierowywane na endpoint websecure
      # używającego protokołu HTTPS.
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

Dynamiczna dynamic.yml

http:
  routers:
    traefik:
      # Pod tym adresem jest dostępny dashboard Traefik-a
      rule: "Host(`traefik.docker.localhost`)"
      service: "api@internal"
      tls:
        # Wskazuje jakie domeny będą dostępne w trybie bezpiecznym
        domains:
          - main: "docker.localhost"
            sans:
              - "*.docker.localhost"
          - main: "domain.local"
            sans:
              - "*.domain.local"

tls:
  # Wskazuje umiejscowienie certyfikatów
  certificates:
    - certFile: "/etc/certs/local-cert.pem"
      keyFile: "/etc/certs/local-key.pem"

Czas to wszystko uruchomić. Najpierw utworzymy sieć traefik_network. Ponieważ jest to sieć zewnętrzna nie zostanie utworzona wraz z kontenerami tylko trzeba ją utworzyć osobno.

docker network create traefik_network

Uruchamiamy Traefika

docker compose up -d reverse-proxy

Dashboard Traefika dostępny jest pod adresem: traefik.docker.localhost.

Traefik sam wykryje nowy serwis i utworzy dla niego punkt końcowy dostępny za pośrednictwem HTTPS

Przyszedł czas na plik docker-compose.whoami.yml

version: '3'

services:

  whoami:
    image: traefik/whoami
    networks:
      - traefik_network
    labels:
      # Aby kontener nie był ignorowany przez Traefika
      - "traefik.enable=true"
      # Wskazujemy, która sieć ma być użyta do komunikacji z Traefikiem
      # zwłaszcza jeśli do kontenera podpiętych jest więcej niż jedna sieć.
      - "traefik.docker.network=traefik_network"
      # Definiujemy adres URL pod jakim serwis ma być dostępny
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
      # Wskazujemy, że chcemy używać bezpiecznego protokołu TLS
      - "traefik.http.routers.whoami.tls=true"

networks:
  traefik_network:
    # Chcemy się łączyć z zewnętrznym serwisem
    # więc sieć musi wychodzić poza zakres tej konfiguracji.
    external: true

Odpalamy serwis whoami ...

docker compose -f docker-compose.whoami.yml up -d

... i pod adresem whoami.docker.localhost sprawdzamy czy działa.

Uruchomienie Django na localhost po HTTPS z użyciem Traefika

O tym jak szybko odpalić projekt bazujący na pythonowym frameworku Django pisałem już w artykule o zastosowaniu Traefika na potrzeby developmentu na localhost, dlatego odsyłam Cię do niego jeśli chcesz zobaczyć krok po kroku jak to zrobić. Tutaj pokarzę jedynie jak zmodyfikować konfigurację docker-compose.yml, aby móc skorzystać z połączeń szyfrowanych.

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    networks:
      - traefik_network
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_network"
      - "traefik.http.routers.web.rule=Host(`web.docker.localhost`)"
      - "traefik.http.services.web.loadbalancer.server.port=8000"
      # Wskazujemy, że chcemy używać bezpiecznego protokołu TLS 
      - "traefik.http.routers.web.tls=true"

networks:
  traefik_network:
    external: true

Jak widać o ile zmian w konfiguracji Traefika było trochę o tyle w definicji samych serwisów nie zmieniło się wiele.

Wystarczy http://localhost

Do większości prac developerskich localhost wystarcza mi w zupełności i nie czuję potrzeby uruchamiania aplikacji pod niestandardową domeną, a zwłaszcza konfigurowania dla niej certyfikatów TLS. Nie mniej zdarzyło mi się osobiście odczuć skutki zignorowania potrzeby przetestowania połączeń po protokole HTTPS na swoim lokalnym komputerze, kiedy coś co bez zarzutu działało bez szyfrowania, nagle zapalało kilka czerwonych lampek oznaczających mniejsze bądź większe kłopoty. Na devie czy stagingu nie stanowi to zwykle dużego problemu. Może jedynie testerzy irytują się, że wrzucasz na serwer nie przetestowane zmiany. Pamiętaj jednak, że masz taką możliwość i zawsze możesz z niej skorzystać, a ja starałem się Ci to ułatwić.

Akceptuję Ta strona zapisuje niewielkie pliki tekstowe, nazywane ciasteczkami (ang. cookies) na Twoim urządzeniu w celu lepszego dostosowania treści oraz dla celów statystycznych. Możesz wyłączyć możliwość ich zapisu, zmieniając ustawienia Twojej przeglądarki. Korzystanie z tej strony bez zmiany ustawień oznacza zgodę na przechowywanie cookies w Twoim urządzeniu.