51

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.

4 Answers4

61

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
Nidal
  • 8,856
  • 11
  • 55
  • 74
  • 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 -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 05 '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 – daniel Sep 25 '16 at 12:18
  • Edited to change `iptables -I` to `-A` so that the rules go in the correct order. – ilkkachu Sep 25 '16 at 13:18
  • Don't forget to run `iptables-save` if you want the rules to be modified permanently. Otherwise your changes will be wiped out the next time the computer reboots. – Andrew Puglionesi Sep 04 '20 at 14:32
7

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.

William
  • 584
  • 2
  • 9
  • 27
  • 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`](http://www.zeroflux.org/projects/knock) 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 Jul 22 '14 at 16:26
  • How does the cronjob know you are locked out? Sorry wasn't questioning your use of `iptables`, I meant why setup `iptables` if you are going to run a cronjob that removes them. – Matt Jul 22 '14 at 16:28
  • @mtm The cronjob doesn't know that, it resets your IPtables anyway. – William Jul 22 '14 at 17:17
  • 2
    oic. you mean run the flush once at setup time, not regularly scheduled. [`at`](http://linux.die.net/man/1/at) does that. – Matt Jul 22 '14 at 17:24
  • @WilliamDavidEdwards: What is the problem in allowing the root user to login with password? – crisron Sep 19 '14 at 04:36
  • 4
    Whitelisting only your IP and then allowing a root login without a password seems like a terrible idea. – Alex W May 08 '15 at 04: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
7

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.

STW
  • 2,191
  • 4
  • 19
  • 22
1

I'm using ufw (Uncomplicated Firewall) for this, and hence wanted to contribute my setting. Ufw uses iptables in the background, but with a much simpler interface for such simple tasks.

I just had to issue:

sudo ufw allow from <your-ipv4-here> to any port 22
sudo ufw allow from <your-ipv6-here> to any port 22

That's it.

Of course you could also deny any other incoming traffic and allow outgoing traffic by default.

sudo ufw default deny incoming
sudo ufw default allow outgoing

Hope this helps someone.

m4110c
  • 183
  • 1
  • 6