• tatterdemalion@programming.dev
    link
    fedilink
    English
    arrow-up
    2
    ·
    12 hours ago

    Secrets

    • Encrypted secrets file. All repo-managed credentials live in secrets/secrets.yaml, encrypted with SOPS/age.
    • Encrypted OpenTofu state. State and plans are encrypted client-side (PBKDF2 + AES-GCM) with a passphrase from TF_VAR_state_passphrase.

    Network perimeter

    • Default-drop firewall on the router. I use a hand-written nftables ruleset with policy drop on both input and forward. Only lo, lan0 and wg0 are trusted. WAN accepts only established traffic, WireGuard UDP and HTTP/HTTPS.
    • No SSH from the WAN. sshd on the router is not exposed to the internet at all.
    • WireGuard for remote access.
    • Forced DNS. NAT redirects all LAN and VPN port-53 traffic to the router’s AdGuard. AdGuard uses Quad9 over DoT upstream, with blocklists and safe search.
    • Second-level ACL in nginx. Private .home vhosts and Grafana carry allow LAN; allow VPN; deny all;.
    • TLS everywhere. Every public vhost sets forceSSL with recommendedTlsSettings. Certificates come from ACME DNS-01, so issuance needs no inbound port 80. Cloudflare is DNS-only with no proxy, so no third party sees plaintext.

    Host access

    • SSH hardening. Password and keyboard-interactive auth are off, PermitRootLogin = “no”, and logins are key-only.
    • Dedicated deployer system user. It uses a CI-only keypair, separate from the interactive keys. Everything it does through sudo is logged with LOG_INPUT/LOG_OUTPUT to /var/log/sudo-deployer.log.