I was trying to find information on egress rules and iptables out there, but either the information was incomplete or inaccurate. After digging around for a bit and disconnecting my ssh session a few times, I figured it out and thought I'd share it on ServerFault.
Egress rules are key to any security policy, and required for meeting many security standards (such as PCI DSS).
NOTE: The commands in here assume a Debian-based distribution (e.g., Ubuntu server). The iptables commands should be the same across distributions, but check your own distro’s reference guide for how to save and load iptables as those steps vary. If someone wants to wikify this and add RH or other dist differences, go for it.
In the below example, we’ll set up fairly common rules for a server that only really needs to get package updates. Remember that these are case sensitive commands, and also that the order you type them is the order that they are evaluated (i.e., if you are connecting over SSH, don’t do the -A OUTPUT -j REJECT first).
Sample Rule Set
sudo iptables -A OUTPUT -o lo -p all -j ACCEPT
sudo iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 80 -d security.ubuntu.com -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 80 -d us.archive.ubuntu.com -j ACCEPT
sudo iptables -A OUTPUT -j REJECT
IMPORTANT: Do not add the security.ubuntu.com or us.archive.ubuntu.com rules unless you make a /etc/hosts entry for those (but see "Other Egress Rules" on opening up DNS queries). Keep in mind that iptables will evaluate the IP for those addresses AT THE TIME THE RULE IS APPLIED. So if ubuntu changes those addresses, you need to recreate those rules or restart the computer (the rules are applied on startup).
Let’s take a look at each of these rules:
Local Interface Rule
sudo iptables -A OUTPUT -o lo -p all -j ACCEPT
This is adding an entry saying that we should accept any traffic that wants to go outbound on the local (127.0.0.1) interface. Some applications use this interface to exchange information, and we don’t want to break those.
Secret Sauce Rule (Established/Related Sessions)
sudo iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
This is the rule that is often forgotten, leading to disconnected sessions and confusion. What this says is allow outbound traffic that associated with a session that is already established or related to an established session. For example, if you have SSH on your server, you can open up port 22 inbound, but how will the server send data back to clients (that may even suggest an alternate higher port for subsequent communications)? That’s what this rule allows.
These rules simply tell iptables to allow traffic going to port 80 for ubuntu’s update servers. These may be different depending on your region, and there may be more, so you will have to do an apt-get update after you do this to make sure that it works for you. IMPORTANT: As I mentioned before, DO NOT enable this rule without first putting an entry mapping the appropriate IP’s in /etc/hosts. Also if Ubuntu changes these IP’s, you will need to update your hosts entry AND restart or recreate these rules, as iptables evaluates the addresses when the rule is applied.
The "Killer" Rule
sudo iptables -A OUTPUT -j REJECT
This is the rule that kills all the other traffic. This should definitely be the last rule in your chain, or the other rules won’t work.
Don’t forget to do:
sudo sh -c “iptables-save >/etc/iptables.rules”
if you want to keep the rules, and then add:
pre-up iptables-restore < /etc/iptables.rules
under the interface (eth0 or whatever) in /etc/network/interfaces.
Other Egress Rules
To allow “ping” to work (from the server):
sudo iptables -A OUTPUT -p icmp --icmp echo-request -j ACCEPT
sudo iptables -A OUTPUT -p icmp --icmp echo-reply -j ACCEPT
To allow DNS to work (from the server). Note that adding these means you don't have to use /etc/hosts in the above example, but is arguably less secure.
sudo iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
I was trying to find information on egress rules and iptables out there, but either the information was incomplete or inaccurate. After digging around for a bit and disconnecting my ssh session a few times, I figured it out and thought I'd share it on ServerFault.
Egress rules are key to any security policy, and required for meeting many security standards (such as PCI DSS).
NOTE: The commands in here assume a Debian-based distribution (e.g., Ubuntu server). The iptables commands should be the same across distributions, but check your own distro’s reference guide for how to save and load iptables as those steps vary. If someone wants to wikify this and add RH or other dist differences, go for it.
In the below example, we’ll set up fairly common rules for a server that only really needs to get package updates. Remember that these are case sensitive commands, and also that the order you type them is the order that they are evaluated (i.e., if you are connecting over SSH, don’t do the -A OUTPUT -j REJECT first).
Sample Rule Set
IMPORTANT: Do not add the security.ubuntu.com or us.archive.ubuntu.com rules unless you make a
/etc/hosts
entry for those (but see "Other Egress Rules" on opening up DNS queries). Keep in mind that iptables will evaluate the IP for those addresses AT THE TIME THE RULE IS APPLIED. So if ubuntu changes those addresses, you need to recreate those rules or restart the computer (the rules are applied on startup).Let’s take a look at each of these rules:
Local Interface Rule
This is adding an entry saying that we should accept any traffic that wants to go outbound on the local (127.0.0.1) interface. Some applications use this interface to exchange information, and we don’t want to break those.
Secret Sauce Rule (Established/Related Sessions)
This is the rule that is often forgotten, leading to disconnected sessions and confusion. What this says is allow outbound traffic that associated with a session that is already established or related to an established session. For example, if you have SSH on your server, you can open up port 22 inbound, but how will the server send data back to clients (that may even suggest an alternate higher port for subsequent communications)? That’s what this rule allows.
Allowing Ubuntu apt-get update
These rules simply tell iptables to allow traffic going to port 80 for ubuntu’s update servers. These may be different depending on your region, and there may be more, so you will have to do an
apt-get update
after you do this to make sure that it works for you. IMPORTANT: As I mentioned before, DO NOT enable this rule without first putting an entry mapping the appropriate IP’s in/etc/hosts
. Also if Ubuntu changes these IP’s, you will need to update your hosts entry AND restart or recreate these rules, as iptables evaluates the addresses when the rule is applied.The "Killer" Rule
This is the rule that kills all the other traffic. This should definitely be the last rule in your chain, or the other rules won’t work.
Don’t forget to do:
if you want to keep the rules, and then add:
under the interface (eth0 or whatever) in
/etc/network/interfaces
.Other Egress Rules
To allow “ping” to work (from the server):
To allow DNS to work (from the server). Note that adding these means you don't have to use
/etc/hosts
in the above example, but is arguably less secure.To allow NTP time syncing client:
(feel free to add)