DEVELOPMENT ENVIRONMENT

~liljamo/nix-arta

9fde61d8a1d9bc86457f3cdd48338fdd6a63169b — Jonni Liljamo 2 months ago 429a72a
feat: add proxy
M .sops.yaml => .sops.yaml +7 -0
@@ 9,6 9,7 @@ keys:
  - &cloud age17cw2ynlaw0ruga0u5678vas50k7neevuufk7gsqn8y8673g0mu8szhx4lr
  - &dns age1m5ktjargxxu04dn9c2uhvaw79z74mxsc4vdrkalxjn4aa8c86plqg0hyyw
  - &metrics age1m8u3a7rzyx2n6zjxjnfkla34yk3v77egxzd3lv9umt69lsynlaqqqfpt05
  - &proxy age19pj62rpxdh90q7zjvld8u6a7207ar0vmkkp5757j29xvx5e0f5kqjc9y8a
  - &social age173lqcfnq2a3xwdjkdua6uqyskfhpdqp2lt4jskdkg3rfqv23vu2sgplq98
    # VMs
  - &sqbuilds age1wgzza5upq4tcpanmx3p9tg9swltz58ycufcapq9s45wpq8mtvepsr0lnzk


@@ 56,6 57,12 @@ creation_rules:
      - *liljamo_gpg
      age:
      - *metrics
  - path_regex: secrets/proxy/[^/]+\.yaml$
    key_groups:
    - pgp:
      - *liljamo_gpg
      age:
      - *proxy
  - path_regex: secrets/social/[^/]+\.yaml$
    key_groups:
    - pgp:

A hosts/proxy/default.nix => hosts/proxy/default.nix +17 -0
@@ 0,0 1,17 @@
{config, ...}: {
  sops.secrets.rootPwd.neededForUsers = true;
  sops.secrets.liljamoPwd.neededForUsers = true;

  roles.base = {
    root.hashedPasswordFile = config.sops.secrets.rootPwd.path;
    primaryUser = {
      username = "liljamo";
      hashedPasswordFile = config.sops.secrets.liljamoPwd.path;
    };
  };

  roles.tailscale = {
    enable = true;
    enableSSH = true;
  };
}

A secrets/proxy/secrets.yaml => secrets/proxy/secrets.yaml +38 -0
@@ 0,0 1,38 @@
rootPwd: ENC[AES256_GCM,data:qoKUOPPB4uuK8Wykn+OI+DZdFg/IQOO354MiQUzwWeP8FEGJzY75lHPOB/fGXq9OqjmAHoFQLRa8XjNaHmpGBQpU2v737z+w3I4fHLA4fBOtDykFTKqCXXL5yccj1LKRmZ+yewvU18LAag==,iv:XhFEFxYrhCXqb01xzIoPEYfhwcZaQ+TOABgpLh+kI4E=,tag:qZSp+UAlGaIWjR377nRJxA==,type:str]
liljamoPwd: ENC[AES256_GCM,data:xdTpyxoELOTVxSqkKiR62fVsykfhpKLAfBsJKzILkNbCiPLSHKpGl/VWO5+nxv+eM8UNIMSDjf5P55BRfKc+b/1IPrkY65Va33KIcJGlvE+e9wkCdDiBcCLj3v9+Q1kIjPtptsBMm1o1DQ==,iv:Ay0JWUBH+hrnSubaaJFlqvYYLz3+fAizaR92O2J1NBw=,tag:doaRHFx68JO5zEygrCyOAg==,type:str]
wg1PrivateKey: ENC[AES256_GCM,data:XdWjyy3yNkkY1prXmhQ+pJkMzl67HCvo0Niy8WhslsNVsykHOpz4FvgighI=,iv:TUYEu46Ee91V2Ahu+MM/li7q8Sl5yM0u2ZU9nasto2Q=,tag:ylpq8QHFjLuuwZ5Xp02DCg==,type:str]
wg1PresharedKey: ENC[AES256_GCM,data:Nj9sCxDahq6jOo3dMyWGWhebjL7dwqTrGhNG3dbNQJ+AJNhjvqrnbZMCSG0=,iv:s2GldprFLFP3A10X+q2KqHZhiUSLCoagDOcAbq6TXgM=,tag:MdrLpXu9aDfHwiFuZIU3JQ==,type:str]
wg0PrivateKey: ENC[AES256_GCM,data:0GXueiosfoS0MUVpvL7Pb3qXhVoLchC2ZgelQ64MRWnQhiawMZp3JJ24Elc=,iv:wwcbySleh/ST/Dm1qBYe9dHjC573LslkFdReyZj1K6w=,tag:d6c59m4QPBMlZtFP+toFAw==,type:str]
wg0PresharedKey: ENC[AES256_GCM,data:isNyNSjJwpvWpCBCE19PE+VL/pqD6K5ho5TPPNCEdizAjxBDBFdWUlRTnaY=,iv:twOcys1cliE5hV8cUGqYh+EPOOiyvmnsbKbsWUZgZsY=,tag:H5G9Rh+OI/SWSPoGLCEciQ==,type:str]
sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    hc_vault: []
    age:
        - recipient: age19pj62rpxdh90q7zjvld8u6a7207ar0vmkkp5757j29xvx5e0f5kqjc9y8a
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSeFlmb0hZUXZwRmxOWjk1
            RXJIc21NU1pkOGovWUNYb0NNVWFIdTB5RmlNCnpxaXgvc1R6UE1wMDhzUTNOQ3RT
            bnlXVm1uTG1lNVdheFdudVpJVG1pamsKLS0tIGdzZHJpRFdNbUhMZGhIK2pIR3Vx
            L1ZCL0FpRnh6d0VldjAvOTlLb0tjUXcKMrvDltAuOVNF7w4CDot4wuRsLzlsgoDG
            DZj/utJB/2lbNn+1dlIcAGPG9QYR7peoI3vooer+FWA2bX2JvUnifA==
            -----END AGE ENCRYPTED FILE-----
    lastmodified: "2024-09-14T08:15:50Z"
    mac: ENC[AES256_GCM,data:bCWFrubXi+p/p0QzCEUNANU2hdHpmAdvNafyWG7Gq8RBnMnArAIdLr+gicUy1f5FB32O5ffSh1wkBKJVjGVJoMOiusJhpJfvEC8apLY1ApB/6LqkDeqtyRlZOy+1AR5W2GUG0JFr9bYM4VLINPjsvLqcIlxzo1cYCYYJ/8cMyTc=,iv:Ffez5U/2pgpC1nFDI0Ouz5DZNQ+lytDlGOAnoRbGPtM=,tag:znUXYZxfbSzKHLREcvo1KA==,type:str]
    pgp:
        - created_at: "2024-09-14T08:14:09Z"
          enc: |-
            -----BEGIN PGP MESSAGE-----

            hF4D8ab0ENzkR4wSAQdA1sS3901oRw8Jo2D+4GZZ29Yh5cHf/unaqNfJiNjKUzww
            pKVmg1Dk0lv5d2/Wj6Ary9clNgDjm51Wvpv6VPH6mKb1+foA5sWGLjPm2TsMcvNY
            1GYBCQIQ3GBTHpwAh7zCm5WIUKnR2aMJfGDdIJWXOpBPQmIVJh+yF2ZuDhenaeQO
            vP8m+EUDb614T0T9AOydc11stN5iYn03Uy8NGl3Uki4kT3P+b6qFekALRA5j7Pvi
            re4MhgzIxko=
            =8jTR
            -----END PGP MESSAGE-----
          fp: 848EEBCEE9F0D29D25C321A658577946A65EB712
    unencrypted_suffix: _unencrypted
    version: 3.8.1

M systems/hosts/default.nix => systems/hosts/default.nix +5 -0
@@ 42,6 42,11 @@
    profile = lxc;
    modules = [];
  };
  proxy = {
    system = "x86_64-linux";
    profile = lxc;
    modules = [];
  };
  social = {
    system = "x86_64-linux";
    profile = lxc;

A systems/hosts/proxy/default.nix => systems/hosts/proxy/default.nix +157 -0
@@ 0,0 1,157 @@
{
  config,
  pkgs,
  ...
}: let
  promtailPort = 3100;
in {
  sops.secrets.wg1PrivateKey = {};
  sops.secrets.wg1PresharedKey = {};
  sops.secrets.wg0PrivateKey = {};
  sops.secrets.wg0PresharedKey = {};

  networking.firewall.interfaces."eth0".allowedTCPPorts = [443 promtailPort 8404];
  networking.firewall.interfaces."wg0".allowedTCPPorts = [80];
  networking.firewall.interfaces."wg1".allowedTCPPorts = [80 5522];
  # TODO: Remove wg1
  networking.wg-quick = {
    interfaces.wg1 = {
      privateKeyFile = config.sops.secrets.wg1PrivateKey.path;
      address = ["192.168.2.10"];
      listenPort = 21841;

      peers = [
        {
          publicKey = "uvdeJAsxUf/bEREwCaFDHg9rO1xxC3Wzu1d2x+WiNEQ=";
          presharedKeyFile = config.sops.secrets.wg1PresharedKey.path;
          endpoint = "140.238.216.88:51820";
          allowedIPs = ["192.168.2.0/24"];
          persistentKeepalive = 25;
        }
      ];
    };
  };
  networking.wireguard.interfaces."wg0" = {
    ips = ["10.100.0.10/24"];
    listenPort = 51820;

    # pubKey pxbf41wTYSpBxTQW8ksQKNd7VOjTEUWKpW381qEnQyw=
    privateKeyFile = config.sops.secrets.wg0PrivateKey.path;

    peers = [
      {
        publicKey = "+HChRIruvl92cxk4Ztyut28T/m1ilEy3hqDd3HH6XRk=";
        presharedKeyFile = config.sops.secrets.wg0PresharedKey.path;
        allowedIPs = ["10.100.0.0/24"];
        endpoint = "172.234.96.20:51820";
        persistentKeepalive = 25;
      }
    ];
  };

  systemd.services.caddy.path = [
    pkgs.nssTools
  ];

  environment.etc = {
    "haproxy/domainstobackends.map" = {
      text = builtins.readFile ./domainstobackends.map;
    };
  };

  services = {
    haproxy = {
      enable = true;
      config = builtins.readFile ./haproxy.conf;
    };
    caddy = {
      enable = true;
      #email = "";
      logFormat = "level ERROR";
      globalConfig = ''
        http_port 8080
        https_port 8443
      '';
      virtualHosts = {
        "dns.rustylily.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.2.3:80
        '';

        "multi.media.rustylily.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.2.30:8096
        '';
        "books.media.rustylily.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.2.30:5000
        '';
        "nextcloud.rustylily.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.2.15:80
        '';

        "metrics.rustylily.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.2.5:3000
        '';

        "portainer.uwulpine.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.1.10:9080
        '';
        "registry.uwulpine.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.1.10:5000
        '';
        "registryui.uwulpine.home.arpa".extraConfig = ''
          tls internal
          reverse_proxy http://10.1.1.10:5080
        '';
      };
    };
  };

  services.promtail = {
    enable = true;
    configuration = {
      server = {
        http_listen_port = promtailPort;
        grpc_listen_port = 0;
      };
      positions = {
        filename = "/tmp/positions.yaml";
      };
      clients = [
        {
          url = "http://10.1.2.5:9091/loki/api/v1/push";
        }
      ];
      scrape_configs = [
        {
          job_name = "journal";
          journal = {
            max_age = "12h";
            labels = {
              job = "systemd-journal";
              host = "lxcproxy";
            };
          };
          relabel_configs = [
            {
              action = "keep";
              source_labels = ["__journal__systemd_unit"];
              regex = "haproxy.service";
            }
            {
              source_labels = ["__journal__systemd_unit"];
              target_label = "unit";
            }
          ];
        }
      ];
    };
  };

  system.stateVersion = "23.05";
}

A systems/hosts/proxy/domainstobackends.map => systems/hosts/proxy/domainstobackends.map +20 -0
@@ 0,0 1,20 @@
auth.liljamo.com         autheliamain
cloud.liljamo.com        nextcloud
docs.liljamo.com         outline
rss.liljamo.com          miniflux

liljamo.dev           liljamodev
registry.liljamo.dev  registry
umami.liljamo.dev     umami

lothlorien.social       akkoma
media.lothlorien.social akkomamedia

src.quest          sourcequest
builds.src.quest   sourcequest
git.src.quest      sourcequest
lists.src.quest    sourcequest
man.src.quest      sourcequest
meta.src.quest     sourcequest
paste.src.quest    sourcequest
todo.src.quest     sourcequest

A systems/hosts/proxy/haproxy.conf => systems/hosts/proxy/haproxy.conf +127 -0
@@ 0,0 1,127 @@
global
  log /dev/log local0
  daemon
  maxconn 512

defaults
  log global
  mode http
  option httplog
  timeout connect 5s
  timeout client 1m
  timeout server 1m

frontend stats
  bind *:8404
  http-request capture req.fhdr(User-Agent) len 512
  log-format "client_ip=\"%ci\" client_port=\"%cp\" time=\"%t\" frontend_name=\"%f\" backend_name=\"%b\" request=\"%r\" request_headers=\"%hr\""

  http-request use-service prometheus-exporter if { path /metrics }
  stats enable
  stats uri /stats
  stats refresh 10s

frontend http-in
  bind 0.0.0.0:80
  http-request capture req.fhdr(User-Agent) len 512
  log-format "client_ip=\"%ci\" client_port=\"%cp\" time=\"%t\" frontend_name=\"%f\" backend_name=\"%b\" request=\"%r\" request_headers=\"%hr\""

  acl host_media req.hdr(Host) media.liljamo.com
  acl allow_media_metrics src 10.1.2.5
  acl media_metrics path_beg /metrics
  http-request deny if media_metrics !allow_media_metrics
  use_backend be_jellyfin if host_media

  acl host_liljamocom req.hdr(Host) liljamo.com
  acl liljamocom_webfinger path_beg /.well-known/webfinger
  acl liljamocom_matrix path_beg /_matrix
  use_backend be_liljamocom_webfinger if host_liljamocom liljamocom_webfinger
  use_backend be_liljamocom_matrix if host_liljamocom liljamocom_matrix
  use_backend be_liljamocom if host_liljamocom

  acl host_alderaanfi req.hdr(Host) alderaan.fi
  acl alderaanfi_matrix path_beg /_matrix
  use_backend be_alderaan_matrix if host_alderaanfi alderaanfi_matrix

  use_backend be_%[req.hdr(Host),map(/etc/haproxy/domainstobackends.map,caddy-http)]

frontend https-in
  bind 0.0.0.0:443
  mode tcp
  option tcplog
  log-format "client_ip=\"%ci\" client_port=\"%cp\" time=\"%t\" frontend_name=\"%f\" backend_name=\"%b\" request_headers=\"%hr\""

  default_backend be_caddy-https

frontend sourcequest-ssh-in
  bind 0.0.0.0:5522
  mode tcp
  option tcplog
  log-format "client_ip=\"%ci\" client_port=\"%cp\" time=\"%t\" frontend_name=\"%f\" backend_name=\"%b\" request_headers=\"%hr\""

  use_backend be_ssh_sourcequest

backend be_caddy-http
  server caddy localhost:8080

backend be_caddy-https
  mode tcp
  server caddy localhost:8443

# liljamo.com
backend be_liljamocom
  server liljamocom 10.1.1.10:8100

backend be_liljamocom_webfinger
  server liljamocomwebfinger 10.1.2.12:80

backend be_liljamocom_matrix
  server conduit 10.1.1.10:8448

backend be_autheliamain
  server autheliamain 10.1.2.12:3001

backend be_outline
  server outline 10.1.2.15:3000

backend be_miniflux
  server miniflux 10.1.1.10:8600

backend be_nextcloud
  server nextcloud 10.1.2.15:80

backend be_jellyfin
  option httpchk
  option forwardfor
  http-check send meth GET uri /health
  http-check expect string Healthy
  server jellyfin 10.1.2.30:8096

# lothlorien.social
backend be_akkoma
  server akkoma 10.1.2.17:4000

backend be_akkomamedia
  server akkoma 10.1.2.17:4000

# liljamo.dev
backend be_liljamodev
  server liljamodev 10.1.1.10:8110

backend be_registry
  server registry 10.1.1.10:5000

backend be_umami
  server umami 10.1.1.10:8700

# src.quest
backend be_sourcequest
  server sourcequest 10.1.1.20:80

backend be_ssh_sourcequest
  mode tcp
  server sourcequest 10.1.1.20:22

# alderaan.fi
backend be_alderaan_matrix
  server conduit 10.1.2.16:6167