Implement A Basic Firewall Template With Iptables On Ubuntu 14 04
Implementing a firewall is an all-important stride in obtaining
your server. a gigantic part of that is deciding on the solo rules and contracts that will enforce traffic restrictions to your network. Firewalls like
iptables also allow you to have a say about the structural framework in which your rules are enlisted
In this govern, we will construct a firewall that can be the basis for more complex rule sets. This firewall will focus primarily on giving reasonable failures and establishing a framework that encourages simple extensibility. We will be showing this on an ubuntu 14.04 server.
Before you commence, you should have a basic concept of the firewall contracts you wish to implement. You can follow this lead to get a good concept of some of the things you should be thinking about.
In order to follow along, you will need to have accesses to an ubuntu 14.04 server. We will be using a non-root user configured with
sudo privileges throughout this lead. You can learn how to configure this type of user in our Ubuntu 14.04 first server setup govern.
When you are completed , continue below.
Installing the Persistent Firewall Service
To get began
, you will need to install the
iptables-persistent package if you have not done so already. This will allow us to save our rule sets and have them automatically registered
- sudo apt-get modify
- sudo apt-get install iptables-persistent
During the installation, you'll be questioned whether you want to save your actual rules. Say "yes" here. We will be editing the generated rules records momentarily.
A Note About IPv6 in this Guide
Before we get commenced
, we should talk briefly about IPv4 vs IPv6. The
iptables control only handles IPv4 traffic. For IPv6 traffic, an apart friend equipment labelled
ip6tables is used. The rules are stored in apart tables and chains. For
iptables-persistent, the IPv4 rules are written to and read from
/etc/iptables/rules.v4 and the IPv6 rules are kept in
This govern assumes that you are not actively using IPv6 on your server. If your services do not leverage IPv6, it is fail-safe to block accesses entirely, as we will be doing in this article.
Implementing the Basic Firewall Policy (The Quick Way)
For the sake of getting up and running as quickly as feasible, we'll show you how to edit the rules register directly to copy and composition the completed
firewall policy. Afterwards, we will inform the general strategy and show you how these rules could be implemented using the
iptables control instead of altering
To implement our firewall policy and framework, we will be editing the
/etc/iptables/rules.v6 records. ajar the
rules.v4 register in your matter editor with
- sudo nano /etc/iptables/rules.v4
Inside, you will see a register that looks something like this:
# Generated by iptables-save v1.4.21 on Tue Jul 28 13:29:56 2015 *device :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Tue Jul 28 13:29:56 2015
Replace the proportions with:
*device # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # Commit the changes COMMIT *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *security :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT
Save and close the register.
You can try-out the register for structure errors by writing this control. Fix any structure errors that this reveals before continuing:
- sudo iptables-restore -t /etc/iptables/rules.v4
Next, ajar the
/etc/iptables/rules.v6 register to alter the IPv6 rules:
- sudo nano /etc/iptables/rules.v6
We can block all IPv6 traffic by replacing the proportions of the register with the below configuration:
*device :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] COMMIT *raw :PREROUTING DROP [0:0] :OUTPUT DROP [0:0] COMMIT *nat :PREROUTING DROP [0:0] :INPUT DROP [0:0] :OUTPUT DROP [0:0] :POSTROUTING DROP [0:0] COMMIT *security :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] COMMIT *mangle :PREROUTING DROP [0:0] :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] :POSTROUTING DROP [0:0] COMMIT
Save and close the register.
To try-out this register for structure errors, we can use the
ip6tables-restore control with the
- sudo ip6tables-restore -t /etc/iptables/rules.v6
When both rules records report no structure errors, you can enlistly the rules within by writing :
- sudo service iptables-persistent reload
This will immediately implement the policy outlined in your records. You can verify this by listing the
iptables rules currently in use:
- sudo iptables -S
- sudo ip6tables -S
These firewall rules will be re-applied at each boot. experiment to make convinced that you can still log in and that all other accesses is blocked off.
An Explanation of Our General Firewall Strategy
In the basic firewall we've constructed with the above rules, we've created an extensible framework that can be easily altered
to increase or remove rules. For IPv4 traffic, we're mainly concerned with the
INPUT series within the
device table. This chain will process all packets destined for our server. We've also allowed all outgoing traffic and denied all packet forwarding, which would only be appropriate if this server were acting as a router for other hosts. We accept packets in all of the other tables since we are only looking to device packets in this lead.
In general, our rules set up a firewall that will deny incoming traffic by failure. We then go about creating objections for the services and traffic symbols we wish to exclude from this policy.
In the important
INPUT series, we've increased
some generic rules for traffic that we are assured will always be handled the same route. For example, we always want to deny packets that are deemed "invalid" and we will always want to allow traffic on the local loopback interface and data associated with an established connection.
Afterwards, we match traffic based on the protocol it is using and reordering it to a protocol-accurate series. These protocol-accurate chains are conveyed
to hold rules that match and allow traffic for accurate services. In this instance, the only service we allow is SSH in our
TCP series. If we were offering another service, like a http(S) server, we could increase objections that here as well. These chains will be the focus of most of your customization.
Any traffic that does not match the generic rules or the service rules in the protocol-specific are handled by the last few rules in the
INPUT series. We have set the failure policy to
DROP for our firewall, which will deny packets that plummet through our rules. However, the rules at the end of the
INPUT series reject packets and send a communication to the case that mimics how the server would answer if there were no service running on that port.
For IPv6 traffic, we simply drop all traffic. Our server is not using this protocol, so it is fail-safe to not engage with the traffic at all.
(Optional) Update Nameservers
Blocking all IPv6 traffic can interfere with how your server resolves things on the Internet. For instance, this can affect how you use inclined.
If you get errors like this when you attempt to run
Err http://security.ubuntu.com trusty-security InRelease Err http://security.ubuntu.com trusty-security Release.gpg Could not resolve 'security.ubuntu.com' . . .
You should follow this part to get inclined working again.
First, set your nameservers to outside nameservers. This instance uses Google's nameservers. ajar
/etc/network/interfaces for editing:
- sudo nano /etc/network/interfaces
dns-nameservers line as shown
. . . iface eth0 inet6 static address 2604:A880:0800:0010:0000:0000:00B2:0001 netmask 64 gateway 2604:A880:0800:0010:0000:0000:0000:0001 autoconf 0 dns-nameservers 126.96.36.199 188.8.131.52
Refresh your network environments:
- sudo ifdown eth0 && sudo ifup eth0
The expected output is:
RTNETLINK answers: No such process Waiting for DAD... Done
Next, create a brand-new firewall rule to force IPv4 when it's accessible. Create this brand-new register:
- sudo nano /etc/apt/apt.conf.d/99force-ipv4
increase this solo line to the register:
Save and close the register. Now you should be able to use APT.
Implementing our Firewalls Using the IPTables Command
Now that you understand the general concept behind the policy we built, we will walk through how you could go about creating those rules using
iptables controls. We will end up with the same rules that we selected
above but we will create our contracts by increasing
rules iteratively. Because
iptables applies each of the rules immediately, rule requesting
is very all-important (we leave the rules that deny packets until the end).
Reset your Firewall
We will commence by resetting our firewall rules so that we can see how contracts can be built from the regulate line. You can even all of your rules by writing :
- sudo service iptables-persistent flush
You can verify that your rules are device by writing :
- sudo iptables -S
You should see that the rules in the
device table are gone and that the failure policy is set to
ACCEPT on all chains:
output-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
Create Protocol-Specific Chains
We will begin by creating all of our protocol-specific chains. These will be used to hold the rules that create objections to our deny policy for services we want to subject. We will create one for
UDP traffic, one for
TCP, and one for
- sudo iptables -N UDP
- sudo iptables -N TCP
- sudo iptables -N ICMP
We can go right ahead and increase the objection for SSH traffic. SSH uses TCP, so we will increase a rule to accept TCP traffic ordained for port 22 to the TCP series:
- sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT
If we wanted to add additional TCP services, we could do that now by repeating the control with the port number replaced.
Create General Purpose Accept and Deny Rules
INPUT chain, where all incoming traffic begins deviceing, we need to add our general purpose rules. These are some common sense rules that set the baseline for our firewall by accepting traffic that's low risk (local traffic and traffic that's associated with connections we've already checked) and dropping traffic that is clearly not useful (invalid packets).
First, we will create an objection to accept all traffic that is part of an established connection or is related to an established connection:
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
This rule uses the
conntrack protraction, which provides inner tracking so that
iptables has the discourse it needs to evaluate packets as part of large connections instead of as a stream of separate, misrelated packets. TCP is a connection-based protocol, so an established connection is fairly well-defined. For UDP and other connectionless protocols, established connections refer to traffic that has seen a response (the source of the genuine message will the destination of the response message, and vice versa). a related connection refers to a brand-new connection that has been initiated in association with an existing connection. The standard instance here is a ftp data transfer connection, which would be related to the FTP regulate connection that has already been established.
We want to also allow all traffic becoming on the local loopback interface. This is traffic generated by the server and ordained for the server. It is used by services on the host to communicate with one another:
- sudo iptables -A INPUT -i lo -j ACCEPT
Finally, we want to deny all invalid packets. Packets can be invalid for a number of reasons. They may refer to connections that do not exist, they may be ordained for interfaces, addresses, or ports that do not exist, or they may simply be unshapely. In any case, we will drop all invalid packets since there is no proper route to handle them and because they could represent malicious activity:
- sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
Creating the Jump Rules to the Protocol-Specific Chains
So far, we have created some general rules in the
INPUT series and some rules for exact good services within our protocol-exact chains. However, right now, traffic comes into the
INPUT series and has no route of coming
our protocol-specific chains.
We need to direct traffic in the
INPUT series into the befitting protocol-specific chains. We can match on protocol symbol to send it to the right series. We will also ensure that the message represents a brand-new connection (any established or related connections should already be handled earlier). For TCP packets, we will increase the extra requirement that the message is a syn message, which is the only binding symbol to commence a tcp connection:
- sudo iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
- sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
- sudo iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
Reject All Remaining Traffic
If a message that was passed to a protocol-specific series did not match any of the rules within, command will be passed back to the
INPUT series. Anything that reaches this point should not be allowed by our firewall.
We will deny the traffic using the
REJECT target, which sends a response communication to the case. This allows us to choose the outgoing messaging so that we can mimic the response that would be given if the case strove
to send packets to an orderly closed port. The response is babelike on the protocol used by the case.
striving to approach a closed UDP port will result in an icmp "port unreachable" communication. We can reproduce this by writing :
- sudo iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
trying to establish a tcp connection on a closed port results in a tcp RST response:
- sudo iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
For all other packets, we can send an icmp "protocol unreachable" communication to tell that the server doesn't reply to packets of that symbol:
- sudo iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
Adjusting Default Policies
The last three rules we increased
should handle all being
traffic in the
INPUT series. However, we should set the failure policy to
DROP as a precaution. We should also set this policy in the
FORWARD series if this server isn't configured as a router to other appliances:
- sudo iptables -P INPUT DROP
- sudo iptables -P FORWARD DROP
DROP, if you clear your
sudo iptables -F, your actual SSH connection will be dropped! Flushing with
sudo iptables-persistent evenis a good path to clear rules since it will reset the failure policy as well.
To match our IPv6 policy of dropping all traffic, we can use the following
- sudo ip6tables -P INPUT DROP
- sudo ip6tables -P FORWARD DROP
- sudo ip6tables -P OUTPUT DROP
This should replicate our rules set fairly closely.
Saving IPTables Rules
At this point, you should try-out your firewall rules and make convinced they cover the block the traffic you want to keep out while not hindering your normal accesses. Once you are satisfied that your rules are behaving correctly, you can save them so that they will be automatically be enlisted to your system at boot.
Save your actual rules (both IPv4 and IPv6) by writing :
- sudo service iptables-persistent save
This will overwrite your
/etc/iptables/rules.v6 records with the contracts you crafted on the regulate line.
By following this lead, either by pasting your firewall rules directly into the configuration files or by manually applying and saving them on the command line, you have created a good starting firewall configuration. You will have to add the individual rules to allow access to the services you want to make available.
The framework established in this lead should allow you to easily make adjustments and can help clarify your existing policies. Check out some of our other guides to see how to build out your firewall policy with some popular services: