42

This is my /etc/sysconfig/iptables:

It has two ports open 80 apache and 22 for ssh.

# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

For port 22 ( SSH ) I want to ensure no-one can connect to this port except for a specific ip address.

example ip:

1.2.3.4

Please disregard any oversight/concerns regarding what if my ip changes and I can not SSH to my server any more.

46

if I get the question in a right way, you want your server to be reachable only from specific IP address on port 22, you can update Iptables for this:

iptables -A INPUT -p tcp -s YourIP --dport 22 -j ACCEPT

In that case, you are opening ssh port only to YourIP, if you need to open DNS for your internal network:

iptables -A INPUT -p udp -s YourIP --dport 53 -j ACCEPT
iptables -A INPUT -p tcp -s YourIP --dport 53 -j ACCEPT

Once you have them added and opened for those IPs, you need to close the door for the rest of IPs

iptables -A INPUT -p tcp -s 0.0.0.0/0 --dport 22 -j DROP
iptables -A INPUT -p udp -s 0.0.0.0/0 --dport 53 -j DROP
iptables -A INPUT -p tcp -s 0.0.0.0/0 --dport 53 -j DROP

(Make sure to set the rules in the correct position in your ruleset. iptables -A INPUT will add the rules to the end of the INPUT as it currently is.)

or as joel said you can add one rule instead:

iptables -A INPUT -p tcp ! -s <permittedIP> -j DROP

or you can just set the default policy on the firewall with

iptables -P INPUT DROP

In brief, as presented in this question on SO:

iptables -A INPUT -p tcp --dport 22 -s YourIP -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
  • 2
    It's also worth noting that iptables supports inversion with the bang operator in case you want to do a targeted DROP. Example: iptables -I INPUT -p tcp ! -s <permittedIP> -j DROP – Bratchley Jul 22 '14 at 15:45
  • 1
    Also, unconditional DROP's aren't really needed you can just set the default policy on the firewall with iptables -P INPUT DROP and let it go at that. You probably also want to do them as an append if do them this way otherwise all traffic will get caught by the DROP and never reach your ACCEPT rule. – Bratchley Jul 22 '14 at 15:48
  • 1
    This didn't work for me because the default for -I (insert) is to insert as rule #1, so the DROP is inserted as rule #1 and evaluated first and therefore drops all ssh packets, never evaluating the ACCEPT rule. You have to execute iptables -I INPUT 3 -p tcp -s 0.0.0.0/0 --dport 22 -j DROP and iptables -I INPUT 3 -p udp -s 0.0.0.0/0 --dport 53 -j DROP The "3" after INPUT means insert as INPUT rule #3 (assuming you are inserting two ACCEPTS, otherwise if just one ACCEPT then use "2" for INPUT. – Kevin Triplett Jul 5 '15 at 19:47
  • @Networker Using -I will insert the new iptables rules at the top. As such you might end up insterting your drop before your allow. I suggest using -A instead – BlueCacti Feb 10 '16 at 12:56
  • 1
    well i locked myself out, gj – ngwdaniel Sep 25 '16 at 12:18
6

Though I recommend using SSH keys, I will give you an explanation.

You don't have to use IPtables for what you're trying to achieve, there are multiple ways. This is the IPtables way:

iptables -I INPUT -s [YOUR_HOME_IP] -p tcp -m tcp --dport [SSH_PORT] -j ACCEPT

[YOUR_HOME_IP] = Your home IP (pretty straightforward)

[SSH_PORT] = The port that you run SSH on (by default 22)

iptables -I INPUT -p tcp -m tcp --dport [SSH_PORT] -j REJECT

This makes sure no-one except your IP can log in to SSH.

There's another way, which is by adding something to the sshd_config.

Add the following:

AllowUsers root@[YOUR_HOME_IP]
PermitRootLogin without-password

This allows you to log in to SSH as the root user from your IP without asking for a password.

Please keep in mind that a cronjob with

iptables -X
iptables -F

may be smart so you don't get locked out of your server with SSH (the cronjob will reset IPtables so you will get access again). If you still have access, you can remove the cronjob and set up your IPtables again.

  • The cronjob would just remove the firewalling though. Why set iptables up in the first place? Some form of out of band access is the usual method around. knockd is another. – Matt Jul 22 '14 at 16:18
  • @mtm Yes, when you're locked out the cronjob will reset your IPtables setup so you will be able to access SSH again. The reasons why people use IPtables are different, my opinion is that it is an effective, simple and flexible firewall. – William Edwards Jul 22 '14 at 16:26
  • 2
    oic. you mean run the flush once at setup time, not regularly scheduled. at does that. – Matt Jul 22 '14 at 17:24
  • 4
    Whitelisting only your IP and then allowing a root login without a password seems like a terrible idea. – Alex W May 8 '15 at 4:01
  • 1
    @AlexW I know it's been a while but I still wanted to comment: Without-Password means password authentication is not allowed, so you'll have to use SSH key authentication instead. It's indeed a bit of an unclear naming for this authentication method. But this does not mean that you don't need a password to login as root. Nevertheless, a more secure method is to set PermitRootLogin no and use a different sudo account to login, as root is a common target – BlueCacti Feb 10 '16 at 11:04
5

Other answers are using iptables -I in their examples, which often isn't what you should use.

iptables will execute the first rule which matches, so the order of rules is very important. -I is the "insert" command, and should be used with an index parameter to specify where in the list a given rule belongs. -A is the "append" command, which will add the rule to the end of the list.

In some distrobutions (perhaps all) using -I without an index parameter will add the rule to index one, making it the first rule checked. In this scenario if the last command you run is iptables -I INPUT -s tcp 0.0.0.0/0 -j DROP then iptables will drop all traffic, regardless of whether or not you have any ACCEPT rules later in the chain.

Here's a sample of setting up a rule which only allows SSH from a single IP:

Starting without rules:

#> iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Add a new "allow SSH from 1.2.3.4" rule:

#>iptables -A INPUT -p tcp -s 1.2.3.4 --dport 22 -j ACCEPT

Block SSH from all other IPs:

#>iptables -A INPUT -p tcp -s 0.0.0.0/0 --dport 22 -j DROP

Now your INPUT chain will look like:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     tcp  --  1.2.3.4              0.0.0.0/0            tcp dpt:22
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22

Later, if you need to whitelist a second IP you can use the -I parameter to place it before the blacklist rule.

#>iptables -I INPUT 2 -p tcp -s 4.3.2.1 --dport 22 -j ACCEPT

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     tcp  --  1.2.3.4              0.0.0.0/0            tcp dpt:22
ACCEPT     tcp  --  4.3.2.1              0.0.0.0/0            tcp dpt:22
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22

Notice that using -I INPUT 2 added the new rule as rule number 2 and bumped the DROP rule to number 3.

protected by Community Jul 22 '14 at 16:34

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?