# ADR 20260407: Network Architecture ## Status Proposed ## Context The home lab requires a secure and resilient network architecture to support: - Internal services (`.lab` domain). - External services (`.arcodange.fr` domain). - DNS resolution and ad-blocking (Pi-hole). - TLS certificate management (Step CA). - Ingress routing (Traefik). - CDN and DDoS protection (Cloudflare). ## Decision We will implement a **multi-layered network architecture** with the following components: ### 1. External Layer (Internet) - **Cloudflare**: CDN, DDoS protection, and DNS for `.arcodange.fr`. - **DuckDNS**: Dynamic DNS for external access. - **Livebox**: ISP-provided gateway (NAT, DHCP, firewall). ### 2. Internal Layer (Home Lab) - **Pi-hole (pi1, pi3)**: DNS sinkhole for ad-blocking and internal DNS resolution. - **Step CA (pi1)**: Internal certificate authority for `.lab` domain. - **Traefik (k3s)**: Ingress controller with TLS termination. - **k3s Cluster**: Hosts internal services with Longhorn storage. ### 3. DNS Architecture - **Pi-hole**: Primary DNS for internal clients. - Forwards `.lab` queries to Step CA. - Forwards external queries to Cloudflare (1.1.1.1). - **Step CA**: Issues certificates for `.lab` services. - **Cloudflare**: Manages `.arcodange.fr` DNS records. ### 4. Ingress and TLS - **Traefik**: Terminates TLS for both `.lab` and `.arcodange.fr` domains. - Uses Let's Encrypt for `.arcodange.fr`. - Uses Step CA for `.lab`. - **Helm Chart Annotations**: - `traefik.ingress.kubernetes.io/router.entrypoints: websecure` - `traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt` - `traefik.ingress.kubernetes.io/router.middlewares: localIp@file` ### 5. Security - **Cloudflare Tunnel**: Securely exposes internal services without port forwarding. - **CrowdSec**: Intrusion detection and banning. - **Traefik Middlewares**: IP filtering, rate limiting, and authentication. - **Cloudflare Turnstile**: CAPTCHA protection for public-facing services. ## Architecture Diagrams ### 0. High-Level Network Architecture (Architecture Beta) ```mermaid %%{init: {'theme': 'neutral', 'themeVariables': { 'primaryColor': '#f0f0f0', 'primaryBorderColor': '#333333', 'primaryTextColor': '#333333', 'lineColor': '#333333', 'tertiaryColor': '#e67e22' }}}%% architectureBeta %% External Layer box "Internet" #f9f9f9 component Cloudflare["Cloudflare\n(CDN/DNS)"] #f9f9f9 component DuckDNS["DuckDNS\n(DDNS)"] #f9f9f9 end %% External Gateway box "External Gateway" #e6e6e6 component Livebox["Livebox\n(NAT/Firewall)"] #e6e6e6 end %% Internal Layer box "Internal Network\n(192.168.1.0/24)" #d4d4d4 %% DNS Layer box "DNS" #ffff99 component PiHole1["Pi-hole\n(pi1)"] #ffff99 component PiHole3["Pi-hole\n(pi3)"] #ffff99 component StepCA["Step CA\n(pi1)"] #ccccff end %% k3s Layer box "k3s Cluster" #ff9999 component Traefik["Traefik\n(Ingress)"] #ff9999 component CrowdSec["CrowdSec\n(Security)"] #ff9999 component Gitea["Gitea\n(pi2)"] #ffcc99 component Vault["Vault\n(Secrets)"] #ccccff end end %% Connections Cloudflare --> Livebox : "DNS" DuckDNS --> Livebox : "DDNS" Livebox --> PiHole1 : "NAT" Livebox --> PiHole3 : "NAT" Livebox --> Traefik : "NAT" PiHole1 --> StepCA : "Forward .lab" PiHole1 --> Cloudflare : "Forward External" PiHole3 --> StepCA : "Forward .lab" PiHole3 --> Cloudflare : "Forward External" Traefik --> Cloudflare : "TLS (Let's Encrypt)" Traefik --> StepCA : "TLS (Step CA)" CrowdSec --> Traefik : "Ban IPs" Traefik --> Gitea : "Route" Traefik --> Vault : "Route" ``` ### 1. High-Level Network Architecture ```mermaid %%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#333333', 'edgeLabelBackground':'#f0f0f0', 'tertiaryColor': '#f89136'}}}%% graph TD %% Styles classDef internet fill:#f9f9f9,stroke:#999,color:#333; classDef external fill:#e6e6e6,stroke:#555,color:#333; classDef internal fill:#d4d4d4,stroke:#777,color:#333; classDef security fill:#ff9999,stroke:#cc0000,color:#333; classDef dns fill:#ffff99,stroke:#cccc00,color:#333; classDef ca fill:#ccccff,stroke:#6666cc,color:#333; %% Internet subgraph "Internet" Cloudflare["Cloudflare (CDN/DNS)"]:::internet DuckDNS["DuckDNS (DDNS)"]:::internet end %% External Gateway subgraph "External Gateway" Livebox["Livebox (NAT/Firewall)"]:::external end %% Internal Network subgraph "Internal Network (192.168.1.0/24)" %% Pi-hole DNS PiHole1["Pi-hole (pi1)"]:::dns PiHole3["Pi-hole (pi3)"]:::dns %% Step CA StepCA["Step CA (pi1)"]:::ca %% k3s Cluster k3s["k3s Cluster"]:::internal Traefik["Traefik (k3s)"]:::internal CrowdSec["CrowdSec (k3s)"]:::security %% Services Gitea["Gitea (pi2)"]:::internal Vault["Vault (k3s)"]:::internal end %% Connections Cloudflare -->|DNS| Livebox DuckDNS -->|DDNS| Livebox Livebox -->|NAT| PiHole1 Livebox -->|NAT| PiHole3 Livebox -->|NAT| k3s %% Internal DNS PiHole1 -->|Forward .lab| StepCA PiHole1 -->|Forward External| Cloudflare PiHole3 -->|Forward .lab| StepCA PiHole3 -->|Forward External| Cloudflare %% Ingress Traefik -->|"TLS (Let's Encrypt)"| Cloudflare Traefik -->|"TLS (Step CA)"| StepCA CrowdSec -->|Ban IPs| Traefik %% Service Access Traefik -->|Route| Gitea Traefik -->|Route| Vault ``` ### 2. DNS Resolution Flow ```mermaid sequenceDiagram participant Client participant PiHole participant StepCA participant Cloudflare participant ExternalDNS Client->>PiHole: Query example.lab PiHole->>StepCA: Forward .lab query StepCA-->>PiHole: Return A record PiHole-->>Client: Return response Client->>PiHole: Query example.com PiHole->>Cloudflare: Forward to 1.1.1.1 Cloudflare->>ExternalDNS: Resolve externally ExternalDNS-->>Cloudflare: Return response Cloudflare-->>PiHole: Return response PiHole-->>Client: Return response ``` ### 3. Ingress and TLS Flow ```mermaid sequenceDiagram participant User participant Cloudflare participant Traefik participant StepCA participant Service User->>Cloudflare: HTTPS Request (webapp.arcodange.fr) Cloudflare->>Traefik: Forward to internal IP Traefik->>Let's Encrypt: Request Certificate Let's Encrypt-->>Traefik: Issue Certificate Traefik->>Service: Route request Service-->>Traefik: Return response Traefik-->>Cloudflare: Return HTTPS response Cloudflare-->>User: Return response User->>Traefik: HTTPS Request (webapp.arcodange.lab) Traefik->>StepCA: Request Certificate StepCA-->>Traefik: Issue Certificate Traefik->>Service: Route request Service-->>Traefik: Return response Traefik-->>User: Return HTTPS response ``` ### 4. Security Flow (CrowdSec + Traefik) ```mermaid sequenceDiagram participant Attacker participant Traefik participant CrowdSec participant BannedIPs Attacker->>Traefik: Malicious Request Traefik->>CrowdSec: Log suspicious activity CrowdSec->>BannedIPs: Add IP to ban list BannedIPs-->>Traefik: Update middleware Traefik-->>Attacker: Block request (403) ``` ## Playbook and Role Analysis ### 1. Pi-hole Deployment - **Playbook**: `playbooks/system/pihole.yml` - **Role**: `arcodange.factory.pihole` - **Configuration**: - Upstream DNS: Cloudflare (1.1.1.1) and Step CA for `.lab`. - Blocklists: Ad-blocking and malware domains. ### 2. Step CA Deployment - **Playbook**: `playbooks/ssl/ssl.yml` - **Role**: `step_ca` - **Configuration**: - Internal CA for `.lab` domain. - Short-lived certificates (default: 24h). ### 3. Traefik Deployment - **Playbook**: `playbooks/system/system_k3s.yml` (via k3s) - **Helm Chart**: `traefik` (installed via k3s) - **Key Annotations**: ```yaml traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt traefik.ingress.kubernetes.io/router.middlewares: localIp@file ``` ### 4. CrowdSec Deployment - **Playbook**: `playbooks/tools/crowdsec.yml` - **Role**: `arcodange.factory.crowdsec` - **Configuration**: - Bouncer integration with Traefik. - Custom scenarios for brute-force and bot detection. ## Consequences ### Positive - **Resilient DNS**: Pi-hole provides ad-blocking and internal DNS resolution. - **Secure TLS**: Step CA for internal services, Let's Encrypt for external. - **DDoS Protection**: Cloudflare absorbs external attacks. - **Intrusion Detection**: CrowdSec bans malicious IPs automatically. ### Negative - **Complexity**: Multiple layers require careful configuration. - **Single Point of Failure**: Pi-hole is critical for internal DNS. - **Certificate Management**: Step CA requires maintenance for `.lab` domain. ## Alternatives Considered ### Alternative 1: Public DNS for `.lab` - **Rejected**: Exposing internal domains is a security risk. ### Alternative 2: No Ad-Blocking - **Rejected**: Pi-hole provides essential security and privacy. ### Alternative 3: Self-Signed Certificates - **Rejected**: Step CA provides better usability with short-lived certs. ### 5. Cloudflare Turnstile + CrowdSec Flow ```mermaid sequenceDiagram participant User participant Cloudflare participant Turnstile participant Traefik participant CrowdSec participant BannedIPs User->>Cloudflare: Request protected endpoint Cloudflare->>Turnstile: Challenge (CAPTCHA) Turnstile-->>Cloudflare: Return token Cloudflare->>Traefik: Forward request with token alt Valid Token Traefik->>Service: Route request Service-->>Traefik: Return response Traefik-->>Cloudflare: Return response Cloudflare-->>User: Return success else Invalid Token Traefik->>CrowdSec: Log suspicious activity CrowdSec->>BannedIPs: Add IP to ban list BannedIPs-->>Traefik: Update middleware Traefik-->>Cloudflare: Block request (403) Cloudflare-->>User: Return "Access Denied" end ``` ## Success Metrics - Pi-hole blocks >50% of ads and trackers. - Step CA issues certificates without downtime. - Traefik routes 100% of external traffic via Cloudflare. - CrowdSec bans >10 malicious IPs per day. - Cloudflare Turnstile blocks >90% of bot traffic.