The Internet is a scary place, and so putting a host directly onto the Internet comes with some responsibility. Any such hosts should be carefully guarded with strict policies for what they can do, and who can do what to them. What this really means is you need to be careful what services you allow hosts from the Internet to reach, and if they can, controlling how that interaction occurs. For me, this boils down to a few main things:
root
.Here's my somewhat carefully cultivated iptables ruleset for my home Linux router (currently a SolidRun Clearfog Base running Armbian). I'm lazy and run this out of /etc/rc.local. I've been growing it over the years, and some parts of it are inconsistent - but it works for me. I left in stuff that I have commented out in the past because it might be useful to somebody.
The basic ideas are:
#!/bin/bash # external interface with public address EXTIF=eth0 # internal interface. If multiple, change to a loop below INTIF=eth1 # Only use EXTIP for WAN static IP, DHCP uses masquerading #EXTIP= # list of IPs and hostnames to allow inbound TRUSTED_ALLOW="" #MAIL_SERVERS="74.125.25.108 74.125.25.109 74.125.129.108 74.125.129.109 173.194.79.109 173.194.79.108" #DNS_SERVERS="" # Enable IP forwarding in the kernel echo 1 > /proc/sys/net/ipv4/ip_forward # Enable reverse path filtering echo 1 > /proc/sys/net/ipv4/conf/eth0/rp_filter echo 1 > /proc/sys/net/ipv4/conf/eth1/rp_filter # Flush/purge everything - in case this gets rerun after boot. # Be careful not to make any mistakes later on that could cut off # necessary access to the device remotely after flushing. iptables -X iptables -F iptables -t nat -F # REJECT for INPUT to be polite at the end of the script - start with drop iptables -P INPUT DROP # FORWARD is just used for SNAT, and that traffic should not be filtered iptables -P FORWARD ACCEPT # Anything outbound should be dropped unless an exception is made iptables -P OUTPUT DROP # Only act on NEW connections - if established or related it was already # approved at a previous time iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Try this if the above line doesn't work - this changed at some point #iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Trust everything over loopback... iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # ... and trust local network too. Consider removing this and adding # specific things to allow. iptables -A INPUT -i $INTIF -j ACCEPT iptables -A OUTPUT -o $INTIF -j ACCEPT # use MASQUERADE if IP is dynamic, otherwise use SNAT if static IP from ISP iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE #iptables -t nat -A POSTROUTING -o $EXTIF -j SNAT --to $EXTIP # allow DHCP from this host via external interface - this can be disabled # if you have a static IP from your ISP. # If someone somehow breaks into your router, this rule would allow them # to contact internet hosts using UDP 67:68 - but firewalling DHCP is hard iptables -A OUTPUT -o $EXTIF -p udp --dport 67 --sport 68 -j ACCEPT iptables -A INPUT -i $EXTIF -p udp --dport 68 --sport 67 -j ACCEPT # Allow SSH+mosh from everywhere. Check sshd config that root cannot login # remotely and that key auth is required from internet. If users can # auth via passwords, consider moving inside of TRUSTED_ALLOW block iptables -A INPUT -p tcp -i $EXTIF --dport ssh -m conntrack --ctstate NEW -j ACCEPT iptables -A INPUT -p udp -i $EXTIF --dport 60000:61000 -m conntrack --ctstate NEW -j ACCEPT for HOST in $TRUSTED_ALLOW; do iptables -A INPUT -p tcp -i $EXTIF -s $HOST --dport http -m conntrack --ctstate NEW -j ACCEPT iptables -A INPUT -p tcp -i $EXTIF -s $HOST --dport https -m conntrack --ctstate NEW -j ACCEPT done # If this router is a DNS server or doesn't use a local DNS server # via $INTIF, it needs to be able to contact its upstream caches. If it # doesn't uses caches and instead is a recursive nameserver, you'll # need to open this up to allow all outbound DNS #for HOST in $DNS_SERVERS; do # iptables -A OUTPUT -o $EXTIF -p udp --dport domain -d HOST -m conntrack --ctstate NEW -j ACCEPT # iptables -A OUTPUT -o $EXTIF -p tcp --dport domain -d HOST -m conntrack --ctstate NEW -j ACCEPT #done # Allow outbound IMAP and SMTP connections to Gmail. Attempts to be any more # specific than this will only end in tears. This is needed in order to use # something like pine or mutt directly on this router. #for SVR in $MAIL_SERVERS; do # iptables -A OUTPUT -p tcp -o $EXTIF -d $SVR --dport 993 -j ACCEPT # iptables -A OUTPUT -p tcp -o $EXTIF -d $SVR --dport 587 -j ACCEPT # iptables -A OUTPUT -p tcp -o $EXTIF -d $SVR --dport 465 -j ACCEPT #done # Allow all outbound access to NTP - the pool addresses change and # I've had unreliable results hardcoding specific servers iptables -A OUTPUT -p udp -o $EXTIF --dport ntp -j ACCEPT iptables -A OUTPUT -p tcp -o $EXTIF --dport ntp -j ACCEPT # Enable for emergency DNS. #iptables -A OUTPUT -p udp -o $EXTIF -d 4.2.2.2 --dport 53 -j ACCEPT # Allow outbound ICMP ping and some special UDP (for traceroute) # Not needed, but handy. If you plan to give out shell accounts to # friends, not doing this will annoy them. iptables -A OUTPUT -p icmp --icmp-type 8 -o $EXTIF -j ACCEPT iptables -A OUTPUT -p udp -o $EXTIF --dport 33434:33534 -j ACCEPT # Respond to incoming ping requests - not needed, but polite iptables -A INPUT -i $EXTIF -p icmp --icmp-type 8 -j ACCEPT # Be polite to the internet and send an appropriate reject packet. # Without this, default deny policy would just drop packets. # It may be possible to specify this as the default policy of the # INPUT chain rather than just as the last rule, but last time I # tried this failed. Do it last. iptables -A INPUT -j REJECT
Here's my entire sshd configuration. It's mostly stock Debian, but with a few changes I'll point out below.
# Package generated configuration file # See the sshd_config(5) manpage for details # What ports, IPs and protocols we listen for Port 22 # Use these options to restrict which interfaces/protocols sshd will bind to #ListenAddress :: #ListenAddress 0.0.0.0 Protocol 2 # HostKeys for protocol version 2 HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key HostKey /etc/ssh/ssh_host_ecdsa_key HostKey /etc/ssh/ssh_host_ed25519_key #Privilege Separation is turned on for security UsePrivilegeSeparation yes # Lifetime and size of ephemeral version 1 server key KeyRegenerationInterval 3600 ServerKeyBits 1024 # Logging SyslogFacility AUTH LogLevel INFO # Authentication: LoginGraceTime 120 PermitRootLogin no StrictModes yes RSAAuthentication yes PubkeyAuthentication yes #AuthorizedKeysFile %h/.ssh/authorized_keys # Don't read the user's ~/.rhosts and ~/.shosts files IgnoreRhosts yes # For this to work you will also need host keys in /etc/ssh_known_hosts RhostsRSAAuthentication no # similar for protocol version 2 HostbasedAuthentication no # Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication #IgnoreUserKnownHosts yes # To enable empty passwords, change to yes (NOT RECOMMENDED) PermitEmptyPasswords no # Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) ChallengeResponseAuthentication no # Change to no to disable tunnelled clear text passwords PasswordAuthentication no # Kerberos options #KerberosAuthentication no #KerberosGetAFSToken no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes X11Forwarding yes X11DisplayOffset 10 PrintMotd no PrintLastLog yes TCPKeepAlive yes #UseLogin no #MaxStartups 10:30:60 #Banner /etc/issue.net # Allow client to pass locale environment variables AcceptEnv LANG LC_* Subsystem sftp /usr/lib/openssh/sftp-server AllowUsers blood # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the ChallengeResponseAuthentication and # PasswordAuthentication. Depending on your PAM configuration, # PAM authentication via ChallengeResponseAuthentication may bypass # the setting of "PermitRootLogin yes". # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and ChallengeResponseAuthentication to 'no'. UsePAM no Match Address 172.16.253.0/24 PasswordAuthentication yes PermitRootLogin yes AllowUsers blood root
Things to note:
PermitRootLogin no
.ChallengeResponseAuthentication no
, PasswordAuthentication no
, PubkeyAuthentication yes
and UsePAM no
users must supply a correct private key when connecting from the Internet.AllowUsers blood
.I've gone through many iterations of devices to provide NAT for my home network over the years - in the past running:
I think I've settled on a pretty basic Linux setup though running Debian (well, Armbian - but same thing). Why? Well, Linux is for me the least hassle, while still being flexible enough to do whatever I want. I trust the packages for common software, and the hardware support is pretty fantastic, while having minimal requirements.