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
  • 652

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
  • 84,206
  • 24
  • 145
  • 224
mzhaase
  • 3,888
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
  • 315
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,336
  • 29
  • 28