diff --git a/mkosi.images/buildernet/mkosi.conf b/mkosi.images/buildernet/mkosi.conf index 8bdbec0c..ee39b38a 100644 --- a/mkosi.images/buildernet/mkosi.conf +++ b/mkosi.images/buildernet/mkosi.conf @@ -13,6 +13,7 @@ Packages=cryptsetup haproxy jq nano-tiny + nftables openssh-server prometheus-node-exporter rclone diff --git a/mkosi.images/buildernet/mkosi.extra/etc/systemd/system-preset/10-buildernet.preset b/mkosi.images/buildernet/mkosi.extra/etc/systemd/system-preset/10-buildernet.preset index ddaab9bd..077d8867 100644 --- a/mkosi.images/buildernet/mkosi.extra/etc/systemd/system-preset/10-buildernet.preset +++ b/mkosi.images/buildernet/mkosi.extra/etc/systemd/system-preset/10-buildernet.preset @@ -3,4 +3,5 @@ disable ssh.* disable systemd-pcrphase.service disable systemd-pcrphase-initrd.service disable systemd-pcrphase-sysinit.service +enable nftables-load.service enable ntpd-rs-metrics.service diff --git a/mkosi.images/buildernet/mkosi.extra/etc/systemd/system/nftables-load.service b/mkosi.images/buildernet/mkosi.extra/etc/systemd/system/nftables-load.service new file mode 100644 index 00000000..980d1012 --- /dev/null +++ b/mkosi.images/buildernet/mkosi.extra/etc/systemd/system/nftables-load.service @@ -0,0 +1,15 @@ +[Unit] +Description=Load nftables ruleset +Wants=render-config.service +After=render-config.service +Before=haproxy.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/nft -f /etc/nftables/ruleset.nft +ExecReload=/usr/sbin/nft -f /etc/nftables/ruleset.nft +ExecStop=/usr/sbin/nft delete table inet filter + +[Install] +WantedBy=multi-user.target diff --git a/mkosi.images/buildernet/mkosi.extra/usr/lib/mustache-templates/etc/nftables/ruleset.nft.mustache b/mkosi.images/buildernet/mkosi.extra/usr/lib/mustache-templates/etc/nftables/ruleset.nft.mustache new file mode 100644 index 00000000..d63ef8fa --- /dev/null +++ b/mkosi.images/buildernet/mkosi.extra/usr/lib/mustache-templates/etc/nftables/ruleset.nft.mustache @@ -0,0 +1,39 @@ +#!/usr/sbin/nft -f + +table inet filter { + # Privileged source IPs (same list HAProxy uses). Members bypass all caps. + set privileged_ips { + type ipv4_addr + flags interval + elements = { {{#haproxy.rate_limit_privileged_ips}}{{.}}, {{/haproxy.rate_limit_privileged_ips}} } + } + + # Per-source concurrent-connection counter. + set conn_count { + type ipv4_addr + size 131072 + flags dynamic + } + + # Per-source new-connection rate counter. + set conn_rate { + type ipv4_addr + size 131072 + flags dynamic + timeout 1m + } + + chain ingress { + type filter hook input priority filter; policy accept; + + iif "lo" accept + ct state established,related accept + ct state invalid counter drop + + meta l4proto != tcp accept + tcp dport != { 80, 443 } accept + ip saddr @privileged_ips accept + ct state new add @conn_count { ip saddr ct count over {{haproxy.rate_limit_total_conn_regular}} } counter drop + ct state new add @conn_rate { ip saddr limit rate over {{haproxy.nft_conn_rate_per_sec_regular}}/second burst {{haproxy.rate_limit_conn_rate_regular}} packets } counter drop + } +}