graphene-os-server-infrastr.../nftables-web.conf
Daniel Micay cd59960e7b move IP-based SSH connection limits to nftables
We use synproxy for establishing all new connections to the SSH port and
enforce a connection limit between synproxy and the standard network
stack. Once the connection limit is reached, it's also enforced for new
connections at the synproxy layer. This avoids creating conntrack and
connection limit set entries until connections are already established
to avoid packets with spoofed source addresses exhausting these limited
size tables. Primary servers using SSH to mirror TLS certificates to
their replicas are allowlisted.
2024-03-28 11:38:03 -04:00

95 lines
2.7 KiB
Plaintext

#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
51.222.156.101, # 0.grapheneos.org
167.114.114.114, # 0.releases.grapheneos.org
}
define ip6-allowlist-ssh = {
::1,
2607:5300:205:200::29c6, # 0.grapheneos.org
2607:5300:201:3100::6210, # 0.releases.grapheneos.org
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
chain prerouting-raw {
type filter hook prerouting priority raw
# drop packets without a reverse path (strict reverse path filtering)
fib saddr . iif oif missing counter drop
iif lo notrack accept
# drop packets to address not configured on incoming interface (strong host model)
fib daddr . iif type != { local, broadcast, multicast } counter drop
tcp dport { 80, 443 } notrack accept
tcp dport 22 tcp flags syn notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport { 80, 443 } notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo tcp dport 22 tcp flags syn ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } reject with tcp reset
iif lo tcp dport 22 tcp flags syn ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr ct count over 1 } reject with tcp reset
iif lo accept
tcp dport { 80, 443 } accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
tcp dport 22 ip saddr @ip-connlimit-ssh reject with tcp reset
tcp dport 22 ip6 saddr @ip6-connlimit-ssh reject with tcp reset
tcp dport 22 synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output {
type filter hook output priority filter
oif lo goto output-internal
skuid != { root, systemd-network, unbound, chrony, http } counter goto graceful-reject
}
chain output-internal {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid chrony meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}