3

I have read many articles and answers on this topic and I have been in discussion with Linode support, but no one seems to be able to answer my exact problem.

Seems easy - I'd like to use a iptables firewall to restrict access to all ports except 22, 80 and 443. Linode has a great write up here: https://library.linode.com/securing-your-server#sph_creating-a-firewall and I used their firewall rules as is. The firewall works well.

I also want to preroute some ports, because this is a nodejs app. So I used:

sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 3000

These rules work if I do not have the firewall rules. In fact, I'm using them right now, but I've had to leave the firewall down.

If I add the firewall rules, the PREROUTING stops working. If I save the active iptables rules into a file to view, both the firewall (filter rules) and the PREROUTING (nat rules) are present, but only the firewall rules work. See here:

# Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
*security
:INPUT ACCEPT [1606:135329]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1206:144815]
COMMIT
# Completed on Wed Mar 26 02:40:04 2014
# Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
*raw
:PREROUTING ACCEPT [1620:139613]
:OUTPUT ACCEPT [1206:144815]
COMMIT
# Completed on Wed Mar 26 02:40:04 2014
# Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
*nat
:PREROUTING ACCEPT [4:248]
:INPUT ACCEPT [6:376]
:OUTPUT ACCEPT [12:728]
:POSTROUTING ACCEPT [12:728]
-A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
-A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 3000
COMMIT
# Completed on Wed Mar 26 02:40:04 2014
# Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
*mangle
:PREROUTING ACCEPT [1620:139613]
:INPUT ACCEPT [1606:135329]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1206:144815]
:POSTROUTING ACCEPT [1206:144815]
COMMIT
# Completed on Wed Mar 26 02:40:04 2014
# Generated by iptables-save v1.4.18 on Wed Mar 26 02:40:04 2014
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A INPUT -j DROP
-A FORWARD -j DROP
-A OUTPUT -j ACCEPT
COMMIT
# Completed on Wed Mar 26 02:40:04 2014 

If I use iptables -F, it will flush the firewall (filter) rules only and the PREROUTING will start working again. So it's definitely a conflict. The order of the rule blocks doesn't seem to matter as this (above) is the standard output by iptables regardless of the order in which I saved the rules to iptables.

To me, it seems like it's one of two things:

  1. PREROUTING ports that also have the ACCEPT rule could mean the prerouting is ignored
  2. that I'm PREROUTING to a port that is technically blocked (but I thought that's where the "PRE" came in)

Anyone know?

Thanks!

Paul

paintedbicycle
  • 199
  • 1
  • 3
  • 15
  • looks like case 2; after PREROUTING local packets go to the local filter where they get dropped in your case. The solution is to a) run 8080 and 3000 locally (so they are not exposed) and open those ports in iptables like 80 etc or b) add rule to allow those ports for traffic coming locally only – LinuxDevOps Mar 26 '14 at 19:13
  • @LinuxDevOps Makes sense. How do a) and b) different in your answer? I'm not sure how to accomplish either case exactly, but it does make sense that I'd have to open up 8080 and 3000 to local traffic if I want this to work. Do you have a link or example of how to do that? And is there any security concerns there? Thanks! – paintedbicycle Mar 26 '14 at 19:27
  • Sorry for the confusion, I think you just need to open those ports `-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT` (same for 3000) , if you are redirecting from 80/443 to 8080/3000 is like the latter ports are open and exposed to the Internet anyways, I'm supposing you want http(s) requests to go directly to Node and there's no proxy (apache etc) at the front before it. – LinuxDevOps Mar 26 '14 at 19:44
  • @LinuxDevOps Interesting! Yes, http(s) requests are going directly to Node. I had assumed opening 8080 and 3000 to the public would be an issue, but it sounds from your answer that there is literally no difference since I'm forwarding 80 and 443 there anyway. Thanks for the help! – paintedbicycle Mar 26 '14 at 19:49
  • correct, there's no difference from the outside, if everything works now let me put it together in a cleaner answer – LinuxDevOps Mar 26 '14 at 19:54
  • @LinuxDevOps Yes, please do. I have added those rules and the `PREROUTING` is working as desired and all the firewall rules are present in the file. What's the easiest way to test if the firewall is blocking the other ports? I can see them, but just want to be sure. Ping, cURL, wget from terminal? – paintedbicycle Mar 26 '14 at 20:02
  • Internally if you run `netstat -tlpn` and look at services that listen to Local Address 0.0.0.0 or ::: then those are the services that are exposed to the outside (unless you are blocking them which usually doesn't make sense). You can run internally the `nmap` scanner against all ports to be sure of what's open to the Internet (from outside you may want to ask for your ISP's permission). For a particular port you can use `telnet` or `nc`. – LinuxDevOps Mar 26 '14 at 20:10
  • @LinuxDevOps Perfect, thanks. Add your answer and I'll accept it as the one. – paintedbicycle Mar 26 '14 at 20:11

1 Answers1

6

After PREROUTING local packets go to the local filter where they get dropped (your case 2).

So you just need to allow incoming traffic to those ports in iptables:

iptables -A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT

iptables -A INPUT -p tcp -m tcp --dport 3000 -j ACCEPT

Since you are redirecting http(s) traffic from 80/443 to 8080/3000 is like the latter ports are open and exposed to the Internet anyways, so there's no difference from the outside wrorld and there are no further security implications.

LinuxDevOps
  • 1,754
  • 9
  • 14
  • 2
    For the sake of information, what if I want to explicitly block direct requests for port 3000 ? I.E. mysite.com is OK but mysite.com:3000 is NOT OK. – Arthur Corenzan Sep 25 '14 at 23:09
  • @ArthurCorenzan if you are redirecting 80 traffic to 8080 - why not just run node on 80? – Xeoncross Jan 18 '15 at 02:11