3

I'm working on a server and am supposed to configure it, such that requests on port 8080 are allowed only from a specific IP. (On other http(s) ports nothing is listening anyway.)

Everything else shall stay unrestricted.

After researching about /etc/host and iptables I wrote this script to activate (and deactivate) that rule:

#!/bin/bash

if ["$1" != 'restrict'] && ["$1" != 'restore']
  then
    echo "Usage:"
    echo "'${0##*/} restrict' to activate rules."
    echo "'${0##*/} restore' to deactivate rules."
    echo "'${0##*/}' to show this help."
    exit 0
fi


# Set default policies for INPUT, FORWARD and OUTPUT chains
# Allowing everything else.
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

# Flush all current rules from iptables
iptables -F

if [$1 == "restrict"]
  then

    # Allow HTTP connections on tcp port 8080 from X.X.X.X
    # [I]nserting the rules as first in the chain.
    iptables -I INPUT -p tcp --dport 8080 -s X.X.X.X -j ACCEPT

    # Denying all other connections on tcp port 8080
    # [A]ppending the rule as last in the chain.
    iptables -A INPUT -p tcp --dport 8080 -j DROP
fi

# Save settings
/sbin/service iptables save

# List rules
iptables -L -v

Since I only have access to the machine via SSH, I don't wanna screw up and lock myself out. Thus I'd like to ask if this script

  • works?
  • will do what is desired?
  • won't do anything else?
  • stays nonvolatile?
Braiam
  • 642
  • 4
  • 23
Robin Koch
  • 143
  • 2
  • 5
  • Note that you need spaces around your `[` in your `if` conditions. `[` is actually a command, so needs to be separated like any other one, and the string equality test is just a single `=`, and you'll want to quote `$1` each time you use it, which you missed later in the `if`. You might want to look at www.shellcheck.net for scripts – Eric Renouf Aug 08 '16 at 12:22
  • I recommend that you get a firewall configuration tool like Shorewall or UFW instead of configuring rules by hand. – Tero Kilkanen Aug 08 '16 at 18:24

3 Answers3

6

While this will work, it is not best practice. Instead of allowing everything and only dropping specific things, it is best practice to drop everything, and then only allow what you actually want to go through.

A 'normal' IP table ruleset usually begins like this:

# Flush rules
iptables -F

# Policy drop
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

# Permit loopback device
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Permit new outgoing connections, and packets that belong to
# an existing connection. You might actually not want to allow
# all new connections from the inside if you want to restrict 
# this, you will have to allow DNS, updates, etc.. manually
iptables -A OUTPUT -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Same for input
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT

# Custom rules
# ...
iptables -A INPUT -p tcp --dport 8080 -s 5.35.252.105 -j ACCEPT

Also, when setting up a new firewall, do not automatically run the script, or make the changes permanent. This way, if you mess up, a reboot of the server will give you connectivity back.

HBruijn
  • 77,029
  • 24
  • 135
  • 201
mzhaase
  • 3,798
  • 2
  • 20
  • 32
  • Hi, I'm aware that's not the best practice. But I'm unsure what connections might be needed (SQL, SFTP, ...) so I went for the "bare minimum". - But I will definitely look into your advise when I have more specs, thank you! – Robin Koch Aug 08 '16 at 12:23
  • 7
    This will lock you out. ssh is port 22. – corny Aug 08 '16 at 12:32
  • 1
    @corny Oh wow, that was an unfortunate typo. Thanks for the edit! – mzhaase Aug 08 '16 at 14:06
  • If I may ask, what's your reasoning for the default DROP policy vs. putting a DROP rule into the last rule for each chain? – Thomas Ward Aug 08 '16 at 22:16
  • I would recommend using `iptables-save` and `iptables-restore` instead of shell scripts. – André Borie Aug 09 '16 at 02:00
  • @RobinKoch if you find yourself unaware of what may be needed then open things as they are. Rather than punching holes in the walls of your house on the off chance you may add some features down the road, plan ahead accordingly and only open the ports as they are required. Would you sleep with your front door open on the off chance your neighbor might bring some cookies by? – Mike McMahon Aug 09 '16 at 05:42
  • @ThomasWard That's what policy is there for. Functionally, AFAIK it is the same having it as the last rule versus having it as policy, however some commands, for example iptables -L give you the policy next to the chain name, which might enhance readability. – mzhaase Aug 09 '16 at 08:42
  • @mzhaase I tend to close off my rules with a REJECT in most cases, so maybe I'm biased against setting the default policy since REJECT doesn't appear to be acceptable as a default-policy option... but thank you for your reply! :) – Thomas Ward Aug 09 '16 at 11:10
6

Your rules are correct (in case you fix the syntax error in the shell script, mentioned in the previous comment) for IPv4. For IPv6, your machine is likely completely open.

Tips for the future:

  • Preventing lock out: If you write your rules in iptables-save style directly, you may love the iptables-apply command which restores your previous rules in case the new ones will lock you out.

  • Making rules persistent: On ubuntu, there should be the iptables-persistent package to make sure your rules survive a reboot. Just set up your rules and go apt-get install iptables-persistent and follow the interactive dialogue.

  • Improving style and security: mzhaase gave a very nice tutorial how to write whitelisting rules.

corny
  • 285
  • 1
  • 6
  • About `iptables-save`: How can I create a rule file safely? The man-page says it's for applying a ruleset that was written by iptables-save, which itself dumps the **currents** rules. Wouldn't I lock myself out before I even could dump the rules? Or did I misunderstand something? – Robin Koch Aug 08 '16 at 15:59
  • Just look at [some iptables-save scripts](https://github.com/diekmann/net-network/blob/master/configs_synology_diskstation_ds414/iptables-save_jun_2015_cleanup). It's basically the iptables command but the actual `iptables` in the beginning is omitted. With some practice, you can easily write it by yourself. If unsure, try it in a virtual machine first. – corny Aug 08 '16 at 19:33
3

Here's an easy way to prevent lockout. It will work in principle on any *nix system, not just Ubuntu.

Let's presume your script is called /usr/local/bin/start-iptables.sh and you disable iptables entirely with the command /usr/local/bin/stop-iptables.sh

/usr/local/bin/start-iptables.sh ; sleep 30 ; /usr/local/bin/stop-iptables.sh

If you run the commands like this, on one line, the shell will run them sequentially. If you control-c, the entire command string will be aborted - it won't just cancel the running command and move to the next.

So, the shell will run your start script, then sleep 30 seconds. During that 30 seconds, verify that you can still access the server. Make a new connection, there are ways you could hose up new connections but leave your existing one active. Once you're sure, control-c and the sleep and the stop-iptables script will be aborted.

If you do lock yourself out, after 30 seconds, the stop script will run and you'll be back.

Dan Pritts
  • 3,221
  • 26
  • 28