security: harden lazyworkhorse with firewall, fail2ban, SSH hardening
- Firewall (default deny): - Allow only essential ports: SSH(2424), Gitea(2222), HTTP(80), HTTPS(443) - Rate limit SSH (max 4 new connections/60s) - Rate limit HTTP/HTTPS (25/minute) - Drop invalid packets, log dropped packets - Fail2ban (auto-ban attackers): - SSH jail: 3 strikes = 1 hour ban - HTTP auth failures: 5 strikes = 1 hour ban - HTTP scanning: 2 strikes = 2 hour ban - Recidive jail: repeat offenders = 1 week ban - SSH hardening: - No root login - Max 3 auth tries, 5 sessions - 30s login grace time - No X11/TCP/agent forwarding - Verbose logging - Kernel network hardening: - SYN flood protection (syncookies) - IP spoofing protection (rp_filter) - Disable source routing, redirects - Log martian packets - Connection tuning for high load - Audit logging enabled Ports commented for review (likely internal-only): - 8000 (Portainer), 4242 (Coms), 5000/8087/8089 (TAK)
This commit is contained in:
@@ -158,7 +158,7 @@
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
KbdInteractiveAuthentication = false;
|
||||
PermitRootLogin = "prohibit-password";
|
||||
# Additional hardening settings below in SERVER HARDENING section
|
||||
};
|
||||
hostKeys = [
|
||||
{
|
||||
@@ -308,6 +308,176 @@
|
||||
# Or disable the firewall altogether.
|
||||
# networking.firewall.enable = false;
|
||||
|
||||
# =============================================================================
|
||||
# SERVER HARDENING - Firewall, Fail2ban, SSH, Kernel
|
||||
# =============================================================================
|
||||
|
||||
# Firewall - default deny, explicit allow
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowPing = true;
|
||||
defaultAllow = false;
|
||||
|
||||
# Only essential ports exposed to internet
|
||||
allowedTCPPorts = [
|
||||
2424 # SSH (non-standard port)
|
||||
2222 # Gitea (version control)
|
||||
80 # HTTP (Traefik redirect)
|
||||
443 # HTTPS (Traefik)
|
||||
# 8000 # Portainer - REVIEW: internal only?
|
||||
# 4242 # Coms - REVIEW: internal only?
|
||||
# 5000 # TAK API - REVIEW: internal only?
|
||||
# 8087 # TAK Connect - REVIEW: internal only?
|
||||
# 8089 # TAK Management - REVIEW: internal only?
|
||||
];
|
||||
|
||||
allowedUDPPorts = [
|
||||
# Add UDP ports if required
|
||||
];
|
||||
|
||||
# Rate limiting and attack prevention
|
||||
extraCommands = ''
|
||||
# Rate limit SSH connections (max 4 new connections per 60 seconds)
|
||||
iptables -A INPUT -p tcp --dport 2424 -m state --state NEW -m recent --set
|
||||
iptables -A INPUT -p tcp --dport 2424 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
|
||||
|
||||
# Rate limit HTTP/HTTPS (protects Traefik)
|
||||
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
|
||||
|
||||
# Drop invalid packets
|
||||
iptables -A INPUT -m state --state INVALID -j DROP
|
||||
|
||||
# Log dropped packets (rate limited)
|
||||
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
|
||||
'';
|
||||
};
|
||||
|
||||
# Fail2ban - automatic IP banning
|
||||
services.fail2ban = {
|
||||
enable = true;
|
||||
maxRetry = 3;
|
||||
findtime = 600;
|
||||
bantime = 3600;
|
||||
banaction = "iptables-multiport";
|
||||
|
||||
# Ban repeat offenders for 1 week
|
||||
recidive = {
|
||||
enabled = true;
|
||||
filter = "recidive";
|
||||
logpath = "/var/log/fail2ban.log";
|
||||
bantime = 604800;
|
||||
findtime = 86400;
|
||||
maxretry = 3;
|
||||
};
|
||||
|
||||
jails = {
|
||||
# SSH brute force protection
|
||||
sshd = {
|
||||
enabled = true;
|
||||
filter = "sshd";
|
||||
port = "2424";
|
||||
logpath = "/var/log/auth.log";
|
||||
maxretry = 3;
|
||||
bantime = 3600;
|
||||
};
|
||||
|
||||
# HTTP authentication failures
|
||||
http-auth = {
|
||||
enabled = true;
|
||||
filter = "apache-auth";
|
||||
port = "80,443";
|
||||
logpath = "/var/log/traefik/access.log";
|
||||
maxretry = 5;
|
||||
bantime = 3600;
|
||||
};
|
||||
|
||||
# HTTP scanning/attacks
|
||||
http-botsearch = {
|
||||
enabled = true;
|
||||
filter = "apache-botsearch";
|
||||
port = "80,443";
|
||||
logpath = [ "/var/log/traefik/access.log" ];
|
||||
maxretry = 2;
|
||||
bantime = 7200;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# SSH hardening
|
||||
services.openssh.settings = {
|
||||
PermitRootLogin = "no";
|
||||
MaxAuthTries = 3;
|
||||
MaxSessions = 5;
|
||||
LoginGraceTime = 30;
|
||||
ClientAliveInterval = 300;
|
||||
ClientAliveCountMax = 2;
|
||||
PermitEmptyPasswords = "no";
|
||||
ChallengeResponseAuthentication = "no";
|
||||
UsePAM = true;
|
||||
LogLevel = "VERBOSE";
|
||||
X11Forwarding = false;
|
||||
AllowTcpForwarding = "no";
|
||||
AllowAgentForwarding = "no";
|
||||
PermitTunnel = "no";
|
||||
};
|
||||
|
||||
# Kernel network hardening
|
||||
boot.kernel.sysctl = {
|
||||
# IP Spoofing protection
|
||||
"net.ipv4.conf.all.rp_filter" = 1;
|
||||
"net.ipv4.conf.default.rp_filter" = 1;
|
||||
|
||||
# Ignore ICMP broadcasts
|
||||
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
|
||||
|
||||
# Disable source routing
|
||||
"net.ipv4.conf.all.accept_source_route" = 0;
|
||||
"net.ipv4.conf.default.accept_source_route" = 0;
|
||||
"net.ipv6.conf.all.accept_source_route" = 0;
|
||||
"net.ipv6.conf.default.accept_source_route" = 0;
|
||||
|
||||
# Disable redirects
|
||||
"net.ipv4.conf.all.send_redirects" = 0;
|
||||
"net.ipv4.conf.default.send_redirects" = 0;
|
||||
|
||||
# SYN flood protection
|
||||
"net.ipv4.tcp_syncookies" = 1;
|
||||
"net.ipv4.tcp_max_syn_backlog" = 2048;
|
||||
"net.ipv4.tcp_synack_retries" = 2;
|
||||
"net.ipv4.tcp_syn_retries" = 5;
|
||||
|
||||
# Log martian packets
|
||||
"net.ipv4.conf.all.log_martians" = 1;
|
||||
"net.ipv4.conf.default.log_martians" = 1;
|
||||
|
||||
# Ignore redirects
|
||||
"net.ipv4.conf.all.accept_redirects" = 0;
|
||||
"net.ipv4.conf.default.accept_redirects" = 0;
|
||||
"net.ipv4.conf.all.secure_redirects" = 0;
|
||||
"net.ipv4.conf.default.secure_redirects" = 0;
|
||||
"net.ipv6.conf.all.accept_redirects" = 0;
|
||||
"net.ipv6.conf.default.accept_redirects" = 0;
|
||||
|
||||
# Connection tuning
|
||||
"net.core.somaxconn" = 4096;
|
||||
"net.core.netdev_max_backlog" = 65536;
|
||||
"net.ipv4.tcp_max_orphans" = 65536;
|
||||
"net.ipv4.tcp_fin_timeout" = 15;
|
||||
"net.ipv4.tcp_keepalive_time" = 300;
|
||||
"net.ipv4.tcp_keepalive_probes" = 5;
|
||||
"net.ipv4.tcp_keepalive_intvl" = 15;
|
||||
};
|
||||
|
||||
# Audit logging
|
||||
services.auditd.enable = true;
|
||||
|
||||
# Fail2ban log directory
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/log/fail2ban 0755 root root -"
|
||||
"d /var/log/traefik 0755 root root -"
|
||||
];
|
||||
|
||||
# Copy the NixOS configuration file and link it from the resulting system
|
||||
# (/run/current-system/configuration.nix). This is useful in case you
|
||||
# accidentally delete configuration.nix.
|
||||
|
||||
Reference in New Issue
Block a user