From e6033c8b127d74eb43cf587d6d333a8243d93ae8 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Sun, 2 Aug 2026 20:22:49 +0700 Subject: [PATCH] feat(infra): hardening firewall + sysctl + ssh - deny-by-default iptables/ip6tables: public cuma 22/80/443/4013, sisanya localhost + tailscale CGNAT; log FW-DROP rate-limited - persist via netfilter-persistent (rules.v4/v6) + /usr/local/bin/firewall.sh - sysctl hardening: syncookies, rp_filter, redirect off, kptr/dmesg restrict, protected links, somaxconn, tcp retries tuner - sshd: PasswordAuthentication no (fix 50-cloud-init.conf override), PermitRootLogin prohibit-password, MaxAuthTries 4, LoginGraceTime 30, X11Forwarding no --- infra/firewall/99-hardening.conf | 40 +++++++++++++ infra/firewall/99-ssh-optimization.conf | 12 ++++ infra/firewall/firewall.sh | 74 +++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 infra/firewall/99-hardening.conf create mode 100644 infra/firewall/99-ssh-optimization.conf create mode 100755 infra/firewall/firewall.sh diff --git a/infra/firewall/99-hardening.conf b/infra/firewall/99-hardening.conf new file mode 100644 index 0000000..ba65aaa --- /dev/null +++ b/infra/firewall/99-hardening.conf @@ -0,0 +1,40 @@ +# OrangeVPS hardening sysctl — /etc/sysctl.d/99-hardening.conf +# Network hardening +net.ipv4.tcp_syncookies = 1 +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 +net.ipv6.conf.all.accept_source_route = 0 +net.ipv6.conf.default.accept_source_route = 0 + +# TCP hardening +net.ipv4.tcp_max_syn_backlog = 4096 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_syn_retries = 3 +net.ipv4.tcp_fin_timeout = 15 +net.ipv4.tcp_keepalive_time = 120 +net.ipv4.tcp_keepalive_intvl = 30 +net.ipv4.tcp_keepalive_probes = 5 +net.ipv4.tcp_tw_reuse = 1 +net.ipv4.ip_local_port_range = 1024 65535 + +# Kernel hardening +kernel.randomize_va_space = 2 +kernel.core_uses_pid = 1 +kernel.dmesg_restrict = 1 +kernel.kptr_restrict = 1 +kernel.yama.ptrace_scope = 2 +fs.protected_hardlinks = 1 +fs.protected_symlinks = 1 +fs.suid_dumpable = 0 + +# Resource limits (SYN flood protection) +net.core.somaxconn = 1024 +net.core.netdev_max_backlog = 4096 diff --git a/infra/firewall/99-ssh-optimization.conf b/infra/firewall/99-ssh-optimization.conf new file mode 100644 index 0000000..8465419 --- /dev/null +++ b/infra/firewall/99-ssh-optimization.conf @@ -0,0 +1,12 @@ +ClientAliveInterval 60 +ClientAliveCountMax 3 +MaxStartups 100:30:200 +MaxSessions 100 +TCPKeepAlive yes + +# Hardening 2026-08-02 +MaxAuthTries 4 +LoginGraceTime 30 +PermitRootLogin prohibit-password +X11Forwarding no +AllowTcpForwarding yes diff --git a/infra/firewall/firewall.sh b/infra/firewall/firewall.sh new file mode 100755 index 0000000..a649d04 --- /dev/null +++ b/infra/firewall/firewall.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# ============================================================ +# firewall.sh — deny-by-default firewall untuk orangevps +# Public: 22 (SSH), 80/443 (Caddy), 4013 (hermes dashboard) +# Tailscale CGNAT 100.64/10: semua port (imrnes & node lain) +# Localhost: semua +# Sisanya: DROP + log +# ============================================================ +set -e + +### IPv4 ### +iptables -F +iptables -X +iptables -Z + +# Policy default DROP +iptables -P INPUT DROP +iptables -P FORWARD DROP +iptables -P OUTPUT ACCEPT + +# Loopback +iptables -A INPUT -i lo -j ACCEPT + +# Established/related +iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# Tailscale overlay (100.64.0.0/10) — imrnes & peers +iptables -A INPUT -s 100.64.0.0/10 -j ACCEPT + +# Public: SSH, HTTP(S) +iptables -A INPUT -p tcp --dport 22 -j ACCEPT +iptables -A INPUT -p tcp --dport 80 -j ACCEPT +iptables -A INPUT -p tcp --dport 443 -j ACCEPT +# Public: hermes dashboard (auth-protected) +iptables -A INPUT -p tcp --dport 4013 -j ACCEPT + +# ICMP (ping, PMTU) +iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 5/sec --limit-burst 10 -j ACCEPT +iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ACCEPT +iptables -A INPUT -p icmp -j ACCEPT + +# Log dropped (rate-limited, 1 baris/5s) +iptables -A INPUT -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "FW-DROP " --log-level 4 +iptables -A INPUT -j DROP + +# UFW chains (dipanggil dari ts-input) — kosongkan +iptables -F ufw-before-input 2>/dev/null || true +iptables -F ufw-after-input 2>/dev/null || true +iptables -F ufw-before-logging-input 2>/dev/null || true +iptables -F ufw-after-logging-input 2>/dev/null || true +iptables -F ufw-reject-input 2>/dev/null || true +iptables -F ufw-track-input 2>/dev/null || true + +### IPv6 ### +ip6tables -F +ip6tables -X +ip6tables -Z +ip6tables -P INPUT DROP +ip6tables -P FORWARD DROP +ip6tables -P OUTPUT ACCEPT +ip6tables -A INPUT -i lo -j ACCEPT +ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +# Tailscale IPv6 ULA (fd7a:115c::/48) +ip6tables -A INPUT -s fd7a:115c::/48 -j ACCEPT +ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT +ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT +ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT +ip6tables -A INPUT -p tcp --dport 4013 -j ACCEPT +ip6tables -A INPUT -p icmpv6 -j ACCEPT +ip6tables -A INPUT -m limit --limit 5/min --limit-burst 10 -j LOG --log-prefix "FW6-DROP " --log-level 4 +ip6tables -A INPUT -j DROP + +echo "Firewall applied:" +iptables -L INPUT -n --line-numbers | head -20