Simplify your firewall setup

Fire Protection

Author(s):

Canonical's ufw lets you configure your firewall without the hassle of the iptables tool, while reducing the risk of misconfiguration and simplifying maintenance.

The netfilter firewall included in the Linux kernel can be comprehensively controlled with the iptables tool. However, iptables' complexity not only drives some users crazy, it also increases the risk of unintentionally tearing holes in the firewall with incorrect rules or typos.

Canonical offers a remedy with the Uncomplicated Firewall (ufw) [1]. The command-line program accepts clearly structured rules, which it translates into the appropriate iptables calls in the background. This approach also allows you the advantage of supplementing your setup with more complex rules in iptables, if needed.

Installation

Originally developed by Canonical for Ubuntu, ufw has been part of the distribution since Ubuntu 8.04. Alternately, you can install it with the ufw package. You can also now find ufw on other distributions.

If your distribution's repositories do not contain ufw, you can pick up the source code online [2]. To get started, ufw requires Python v3.4 or later, iptables 1.4 or later, gettext, and make. After unpacking the source code archive, just call

python3 ./setup.py install

with root privileges for a global installation. To start the firewall at boot time, integrate the command

/lib/ufw/ufw-init start

into the respective start scripts. An example unit for systemd is available in the source code archive in doc/systemd.example.

If you also want to regulate IPv6 traffic, open the configuration file located in /etc/default/ufw and make sure it contains a line stating IPV6=yes. In this article, all examples use IPv4 addresses, but the commands will also work with IPv6.

Blockade

Before getting started, check whether the firewall is running with:

sudo ufw status

If a status: inactive message appears, launch ufw by typing

sudo ufw enable

This command also ensures that the firewall starts up automatically at boot time. If necessary, you can disable it again at any time with:

sudo ufw disable

By default, ufw blocks all incoming requests and allows all outgoing messages from the machine to pass. This prevents attackers in particular from reaching any service on the corresponding system. At the same time, the behavior gives you a safety net that catches everything; unless another rule says otherwise, ufw applies the default rules. For example, if you do not define a rule for SSH access, ufw automatically blocks access from outside based on the default rules.

You can change the default behavior with the two commands shown in Listing 1. The first line takes care of all incoming connections, while the second line is for outgoing connections; deny prohibits access, while allow permits it. Consequently, the two commands ensure the default behavior. If you were to replace allow with deny in the second line of Listing 1, ufw would automatically prohibit all network traffic.

Listing 1

Connections

$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing

Like all other commands, the two commands in Listing 1 are intuitive. Even without knowledge of the individual parameters, you can decipher what the command does. Ufw uses its own syntax, which is based on the OpenBSD PF firewall's syntax. If you have previously worked with other tools like iptables, you will need to learn ufw's syntax.

Regulators

Ufw lets you drill holes in the firewall in a targeted way. To do this, specify the appropriate service after the following command:

sudo ufw allow

For instance, the command shown in Figure 1

Figure 1: The command ufw allow automatically adds rules for IPv4 and IPv6 connections, as evidenced by the ufw status that follows.
sudo ufw allow ssh

allows SSH connections from the outside. Repeat this step for all other services you want to allow. For example,

sudo ufw allow http

allows access to an HTTP browser via port 80. All supported names and services can be found in the /etc/services file.

In addition, ufw also understands the names of some applications. For example,

sudo ufw allow 'CUPS'

sets up custom rules for the CUPS printing system. To determine which application names a system currently supports, use:

sudo ufw app list

On Ubuntu, the range of available applications depends largely on the installed services. For example, if the web server Nginx is not available on your system, ufw does not support it either.

If an application name contains spaces, such as Nginx Full, you will need to quote it in the ufw call, as shown in the CUPS example. Otherwise, the shell interprets the words in the name as individual parameters. It is a good idea to get into the habit of always enclosing application names in quotes.

An application's rules are defined by an application profile (Figure 2). All existing profiles are grouped in the directory /etc/ufw/applications.d/. The files in this directory can be used as a basis for your own application profiles; its structure is self-explanatory.

Figure 2: Only CUPS and an SSH server are installed here, which means that ufw only maintains application profiles for the two services.

When creating a firewall rule, you can also specify the port directly. For SSH, for example, you would specify the port as follows:

sudo ufw allow 22

Ufw then automatically sets up matching rules for the TCP and UDP protocols. To allow only a specific protocol, append it to the port number with a forward slash (22/tcp). Complete port ranges can also be stored. For example,

sudo ufw allow 8080:8082/tcp

opens ports 8080, 8081, and 8082 for incoming TCP connections.

Fine Tuning

Ufw stores all the rules and enables them automatically after a system reboot. The IPv4 rules are stored in the /etc/ufw/user.rules file, and the IPv6 counterparts in /etc/ufw/user6.rules. After creating new rules, you should reload these files for safety purposes by typing:

sudo ufw reload

Based on the default rules, ufw allows all outgoing connections. To specifically deny a service access to the network, use deny instead of allow. In addition, use out at the end of the line to indicate that the rule applies to outgoing connections. For example, to prohibit outgoing traffic on port 22, use:

sudo ufw deny out ssh

After issuing this command, the system can no longer contact another host via SSH. Rules for incoming connections are tagged in the same way with in. In all the previous examples where this keyword is missing, ufw automatically assumes that the rule applies to incoming connections.

In addition to allow and deny, reject signifies that the firewall does not simply ignore access attempts but also notifies the sender of the attempts. Also, comment lets you attach a note to all rules (Listing 2, first line). Each rule always applies to all network interfaces. To restrict a rule to one interface, specify its name after in or out (Listing 2, second line).

Listing 2

Comments and Interfaces

$ sudo ufw reject out ssh comment 'no ssh access allowed'
$ sudo ufw allow in on enp0s3 ssh

Bouncer

Access via SSH should only be allowed for defined hosts. To do this, first deny SSH access globally with

sudo ufw deny ssh

Since this is also the default setting, you can alternatively remove the rule

sudo ufw delete allow ssh

which deletes the allow ssh rule. If you can't remember the rules, call

sudo ufw status verbose

In addition, each rule is internally given a sequential number, which can be displayed with:

sudo ufw status numbered

You can use these numbers to delete specific rules. For example, to remove the rule assigned the number 2, use:

sudo ufw delete 2

Now that access via SSH is generally blocked, the command shown in Listing 3 exclusively allows SSH access for the computer with the IP address 192.168.1.101. If you omit to any port 22, the IP address is allowed to access all services. Similarly, you can use deny to block specific requests from an IP address.

Listing 3

Unblocking

$ sudo ufw allow from 192.168.1.101 to any port 22

Numerous requests within a short time indicate an attack and can also overload the affected service. If so desired, ufw can detect this kind of access attempt and then block it specifically. Currently, however, this useful function only works with IPv4 connections. For example, the firewall monitors the SSH service with the command

sudo ufw limit ssh

and blocks access if there are too many requests in a short time.

Chatterbox

If you get tangled up in too many rules, use the following command to start over:

sudo ufw reset

When creating new rules, you can use various reports for help. Use

sudo ufw show listening

to return all services that are currently listening on any port. This helps you find applications that you didn't know were running or that shouldn't be running at all (Figure 3).

Figure 3: Besides CUPS, the Avahi daemon and NetworkManager also are listening on the network interfaces.

If you are familiar with iptables, you can take an in-depth look into the firewall's current configuration with:

sudo ufw show raw

Ufw stores detailed information about its work in a log, which you can enable with

sudo ufw logging on

and then view in /var/log/ufw.log.

Detours

Since version 0.34, ufw now also supports routing. This means that the firewall can wave through incoming packets and, for example, forward all requests arriving on network interface enp0s3 to the interface enp0s8 (shown in Listing 4).

Listing 4

Forwarding Requests

$ sudo ufw route allow in on enp0s3 out on enp0s8

For IP forwarding to work, the corresponding function must be enabled in the sysctl.conf configuration file. On Ubuntu, you use the /etc/ufw/sysctl.conf file for this purpose; enter the lines from Listing 5 or – if they already exist – enable them by removing the preceding hashtags (#). If you made some changes, restart ufw by typing

sudo ufw disable

Listing 5

Enable Forwarding

net/ipv4/ip_forward=1
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

followed by

sudo ufw enable

This more or less brings us to the end of ufw's feature set. In particular, ufw does not yet support masquerading, where the firewall changes, among other things, the source and destination ports in the packets that pass through the firewall. But, as mentioned earlier, more complex rules can be added using iptables. The corresponding configuration is stored either in the /etc/ufw/before.rules file or in /etc/ufw/after.rules. These rules are applied by the firewall before or after the rules that you defined with the ufw command-line program.

Gufw

It is even easier to configure the firewall with Gufw [3], the ufw's graphical user interface. However, since it is not officially part of the ufw project, you usually have to install it in a second step. On Ubuntu, you can install Gufw with:

sudo apt install gufw

After starting Gufw, click the button next to Status to fire up the firewall. Then, in Inbound and Outbound, set the respective default rules. The Report tab (Figure 4), an extremely practical feature, displays the running services more clearly than the matching ufw show listening command. Clicking the plus icon also automatically creates a matching firewall rule.

Figure 4: The Report tab in the Gufw user interface shows the services running on the system.

All existing rules can be found in the Rules tab. Use the gear icon to edit the currently selected rule and the plus icon to add another rule. Under Preconfigured, you can select an application profile; Gufw sorts the applications into categories. CUPS, for example, can be found below Network in the Print subcategory. If you don't want to use application profiles, switch to the Simple tab. Even more granular settings are allowed by the Advanced tab (Figure 5).

Figure 5: This rule blocks access to port 22 via TCP.

Conclusions

With the comparatively simple ufw, a firewall can be configured far faster than with the more complex iptables. The simple ufw rules also reduce the risk of misconfiguration and simplify maintenance. Nevertheless, ufw provides all the critical functions required to harden popular services. If you reach ufw's limits, you can add further rules with iptables. However, ufw and iptables' different syntax does prove to be a hindrance here. The bottom line, however, is that ufw makes setting up a firewall far easier.