ťařina
Obsah Soubory
markdown

Docker-a-firewall.md

markdown
# Docker a firewall Tohle je nejdůležitější stránka celé sekce o firewallu. Popisuje chování, které skoro nikdo nečeká a které tiše otevře služby do internetu. ## Problém v jedné větě **Když publikuješ port přes Docker, ufw ho nezablokuje.** ```bashufw default deny incomingufw enabledocker run -d -p 8080:80 nginx``` Port 8080 je teď dostupný z internetu. `ufw status` tvrdí, že příchozí provoz je zakázaný. Obojí je pravda a to je celý ten problém. ## Proč se to děje Docker si sám zapisuje pravidla do netfilteru a dělá to v místě, kam se paket dostane **dřív**, než na něj sáhne ufw. ```mermaidflowchart LR    P[paket na port 8080] --> PRE[PREROUTING<br/>Docker sem dá DNAT]    PRE --> R{pro tenhle stroj?}    R -->|ne, je pro kontejner| FWD[FORWARD<br/>DOCKER-USER, DOCKER]    R -->|ano| INP[INPUT<br/>tady sedí ufw]    FWD --> K[kontejner]``` Docker udělá DNAT už v `PREROUTING`, čímž z paketu udělá provoz **skrz** stroj místo provozu **na** stroj. Ten pak jde přes `FORWARD`, kde ufw žádná pravidla nemá — ufw pracuje v `INPUT`. Souvislosti jsou v [Linux firewall](Linux-firewall). Není to chyba Dockeru ani ufw. Je to důsledek toho, že spolu nekomunikují a oba mají pravdu ze svého pohledu. ## Ověř si to Než tomu uvěříš, změř to. Z jiného stroje nebo z mobilu na datech: ```bashnmap -Pn -p 8080 adresa.serveru``` Nebo se podívej na skutečná pravidla místo na to, co tvrdí ufw: ```bashiptables -L -n -v | grep -A20 DOCKERnft list ruleset | grep -i docker``` ## Řešení 1: nepublikuj na všechna rozhraní Nejjednodušší a nejúčinnější. Řekni Dockeru, aby port vystavil jen na loopback: ```bashdocker run -d -p 127.0.0.1:8080:80 nginx``` V Compose: ```yamlservices:  web:    image: nginx    ports:      - "127.0.0.1:8080:80"``` Služba je pak dostupná jen ze samotného stroje. Ven ji pustíš přes [reverse proxy](Reverse-proxy), která běží taky na tom stroji a je zajištěná normálně přes ufw. **Tohle je správná odpověď pro naprostou většinu případů.** Nic dalšího řešit nemusíš. Zapamatuj si rozdíl: | Zápis | Dostupné z ||---|---|| `-p 8080:80` | odkudkoliv, včetně internetu || `-p 127.0.0.1:8080:80` | jen z tohoto stroje || `-p 192.168.1.5:8080:80` | jen přes konkrétní rozhraní || `expose: 80` (Compose) | jen z jiných kontejnerů | ## Řešení 2: DOCKER-USER Docker záměrně nechává prázdný řetězec `DOCKER-USER`, který se vyhodnocuje **před** jeho vlastními pravidly. Sem patří tvoje omezení. ```bash# povolit jen z domácí sítě a z VPNiptables -I DOCKER-USER -i eth0 ! -s 192.168.1.0/24 -j DROPiptables -I DOCKER-USER -i eth0 -s 10.10.0.0/24 -j RETURN``` Pravidlo přežije restart Dockeru, ale ne restart stroje — ulož ho stejně jako ostatní, viz [iptables](iptables). Na IPv6 nezapomeň, je to samostatný řetězec: ```baship6tables -I DOCKER-USER -i eth0 -j DROP``` ## Řešení 3: vypnout Dockeru správu iptables ```json/etc/docker/daemon.json{  "iptables": false}``` **Nedělej to, pokud přesně nevíš proč.** Kontejnerům tím rozbiješ odchozí síť a musíš si NAT a forwarding napsat celý ručně. Je to legitimní volba na routeru, kde firewall stavíš od základu, a špatná volba všude jinde. ## Compose a `expose` Když spolu kontejnery komunikují ve stejné síti Compose, **nepotřebují publikované porty vůbec**. Oslovují se jménem služby: ```yamlservices:  app:    image: mojeapp    expose:      - "3000"  db:    image: postgres    # žádné ports, databáze není zvenku vidět  proxy:    image: caddy    ports:      - "80:80"      - "443:443"``` Aplikace se na databázi připojí přes `db:5432`. Ven čouhá jen proxy. Tohle je zdravý vzor: **jediný kontejner s publikovanými porty je reverse proxy.** Všechno ostatní zůstane vnitřní. Viz [sítě v Dockeru](Site-v-Dockeru). ## Kontrolní seznam Když ti na stroji běží Docker: 1. Zjisti, co je skutečně vystavené: `docker ps --format "table {{.Names}}\t{{.Ports}}"`2. Cokoliv ve tvaru `0.0.0.0:port->` je veřejné3. Ověř zvenku pomocí `nmap`4. Přidej `127.0.0.1:` všude, kde služba nemá být veřejná5. Zkontroluj IPv6 zvlášť Ten první příkaz stojí za spuštění hned teď. Většina lidí je překvapená. ## Proxmox a další Stejný problém, jiný viník. Proxmox, libvirt a další systémy, které dělají virtuální sítě, si taky zapisují vlastní pravidla a `ufw status` je neukáže. Univerzální pravidlo: **věř `nft list ruleset`, ne nadstavbě.** Viz [Proxmox a sítě](Proxmox-site).