When you run an embedded linux device like a Raspberry Pi, BeagleBone, or similar device, you’re running a full operating system. Operating systems run all kinds of services in the background, to make your life convenient. Services like an ssh server, an http server, or a mail server spend much of their time listening on network ports and responding to requests. That means they can be exploited by malicious requests. Because of this, it’s a good idea to set up a firewall to block unwelcome requests.
These firewalls also apply to a POSIX server instance like you might set up on Digital Ocean, Dreamhost, AWS, or other hosting services.
In order to get the most out of this tutorial, you should be familiar with the command line interface for Linux or other POSIX operating environments. You should have set up an embedded device like a Raspberry Pi or BeagleBone as well. These instructions assume you’re using the Debian or Raspbian distributions of Linux.
Firewalls set the rules for what your device’s network interfaces (e,.g. WiFi, Ethernet, etc) should do with incoming or outgoing data packets. There are two common firewall packages for linux, iptables and ufw, both of which work well on embedded linux devices.
For a few tips on Linux security, see the Ubuntu page on basic security. There are a number of useful tips on the various log files you should know about to keep track of your device’s security.
Installing and Configuring the ufw Firewall
Ufw, or Uncomplicated Firewall, is a firewall designed to work with well-known services like HTTP, SSH, and other popular linux services. It’s got an interface that’s relatively easy to remember. It’s actually a simplified wrapper around the more complex and powerful iptables firewall. By default, ufw disables all traffic incoming and outgoing. From there, you add rules to allow the kinds of traffic that you want.
For more on ufw, see
- An Introduction to ufw
- ufw man page
- Debian ufw wiki page
- How to Configure a Firewall with ufw
- A helpful post on the Ubuntu forums about using ufw
First you need to install ufw. Assuming you’ve updated your package manager, start by installing ufw:
$ sudo apt-get install ufw
Once it’s installed, you can set defaults to allow outgoing traffic and deny incoming:
$ sudo ufw default allow outgoing $ sudo ufw default deny incoming
This would disconnect your ssh connection if you enabled it now, so you might want to enable ssh connections before you enable the firewall. The following line will enable TCP connections on port 22, the default ssh port:
$ sudo ufw allow ssh
If you’re planning to run an HTTP server, or an HTTPS server, you’ll need to enable them as well. You can specify not only the application (http, https), but also the transport protocol, like so:
$ sudo ufw allow http/tcp $ sudo ufw allow https/tcp
More specific rules ensure that someone won’t try a sneaky attack like flooding UDP packets through your open HTTP ports. If you’re planning to do custom server development, you might want to enable the ports you’ll use for that as well. These settings are typical for node.js development.
$ sudo ufw allow 8080/tcp $ sudo ufw allow 8081/tcp
Port 8081 is used by the p5.serialserver, which is common at ITP.
Once you’ve configured your firewall, you enable it like so:
$ sudo ufw enable
You should reboot once you do this, to check that everything is in order. Once enabled, you can get a status report from ufw like so:
sudo ufw status
You should get a reply like this:
Status: active To Action From -- ------ ---- 22/tcp ALLOW Anywhere 80/tcp ALLOW Anywhere 443/tcp ALLOW Anywhere 8080/tcp ALLOW Anywhere 8081/tcp ALLOW Anywhere 22/tcp (v6) ALLOW Anywhere (v6) 80/tcp (v6) ALLOW Anywhere (v6) 443/tcp (v6) ALLOW Anywhere (v6) 8080/tcp (v6) ALLOW Anywhere (v6) 8081/tcp (v6) ALLOW Anywhere (v6)
Now you’re finished. However, if you’d like to know more about iptables, the more complex firewall on which ufw is built, read on. You don’t need to install both iptables and ufw; in fact, installing both can cause problems. But if you’re interested in firewalls, it can be interesting to understand the difference.
Installing and Configuring the Iptables Firewall
Iptables is a more complex firewall than ufw. It’s harder to understand at first, but allows for a wide range of possible rules. The firewall rules explained here will block access to all incoming traffic except that on port 22, which is the standard port for ssh connections; ports 80, 443, which are the standard ports HTTP traffic; and port 8080, which is a common port for node.js servers. Based on this example, you should be able to add or delete ports to your firewall configuration when you need them.
For more on iptables, the firewall used here, see:
- How the Iptables Firewall Works (a good in-depth introduction)
- How To Set Up a Firewall Using Iptables on Ubuntu 14.04 (not exactly for embedded devices, but a good explanation)
- Raspberry Pi: IPtables (a good starting place for iptables on the Pi)
Iptables works by establishing rules for what your computer should do with incoming packets. It establishes rules for incoming packets (input), outgoing packets (output) and packets that are not addressed to your computer, but are for another device (forwarding). Forwarding rules are mainly relevant for routers, since forwarding packets is a central part of their job. A rule can accept or drop a given packet. You organize the rules in your firewall’s configuration from the most permissive to the most restrivtive. For example, you might start with rules that accept all packets, then filter them through rules that reject some packets, then finish with a rule that drops any packets not already handled by other rules.
The iptables firewall program is part of the Raspbian distribution, but it will not save rules when you shut down, so you need to install iptables-persistent if you want to set rules that will last after reboot. Install iptables-persistent:
$ sudo apt-get install iptables-persistent
When you do this, the application will ask you a few questions about setup, including whether you want to save the rules in the /etc/iptables/ directory. Say yes to all questions asked. Once its installed, you need to set up rules. To get started, you can get a list of the current settings like so:
sudo iptables -S
This should give you an output like this:
-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
It’s telling you that iptables will accept packets that are input from a remote source, output from your computer, or forwarded through your device. This is the most permissive setting you can have.
The rules for iptables are saved in the /etc/iptables/ directory as two files, rules.v4 and rules.v6 for IP version 4 and IP version 6. There’s a separate utility, ip6tables, that manafes firewalls for IPv6 traffic. For this exercise, you’ll just modify rules.v4. You can add rules one by one from the command line (see this tutorial for good examples of this), or you can add them all to the file at once. To do the latter, open the file with the nano text editor like so:
$ sudo nano /etc/iptables/rules.v4
The default setting will look like this (the dates and process numbers will be different for your file):
# Generated by iptables-save v1.4.21 on Fri Jun 2 12:06:45 2017 *filter :INPUT ACCEPT [200:60125] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [61:3865] COMMIT # Completed on Fri Jun 2 12:06:45 2017
To add the rules described earlier, add lines after the :OUTPUT ACCEPT line and before the COMMIT line:
-A INPUT -i lo -j ACCEPT -A INPUT -i wlan0 -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -i wlan0 -p tcp -m tcp --dport 443 -j ACCEPT -A INPUT -i wlan0 -p tcp -m tcp --dport 8080 -j ACCEPT -A INPUT -i wlan0 -p tcp -m tcp --dport 8081 -j ACCEPT -A INPUT -s 192.168.0.1/32 -i tcp -p tcp -m tcp --dport 22 -j DROP -A INPUT -s 192.168.0.0/24 -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -j REJECT -A FORWARD -j REJECT
The first line tells the firewall to accept all incoming traffic from this computer itself, on the loopback interface (lo0).
The second through fourth rules tell it to accept incoming TCP traffic on the WiFi interface (wlan0) on ports 80, 443, and 8080. 80 and 443 are the standard HTTP ports, and 8080 and 8081 are common ports for node.js server applications. You can add another rule like these if you want to accept on another port.
The fifth rule tells the firewall to accept traffic from your local network. You need to change the address 192.168.0.0 to your device’s IP address. The sixth rule tells it to drop packets coming from your router on port 22.
This prevents ssh logins from outside your local network. Change the IP address to the address of your router. If you’re operating in an institution with multiple networks like ITP, this rule might prevent you from logging into your device, if your computer and your device are on different local networks. If so, delete it.
The next rule allows incoming traffic that comes in response to any outgoing requests. For example, if you make a request using curl, this rule allows connections from the remote site that you contacted.
The final rules tell the firewall to reject all other traffic.
These rules are far from comprehensive, but they set a good place to start. Once you’ve set the rules, save and close the file by typing control-X then Y to confirm save. Then tell iptables to update its rules from this file like so:
$ sudo iptables-restore /etc/iptables/rules.v4
Then to save the rules:
You can always list the rules again if you want to check using sudo iptables -S or sudo iptables -L. If you want to delete your rules and start with a fresh set, either delete them from the rules file, or use
$ sudo iptables -F
to flush them all. Don’t forget to update with iptables-restore and iptables-save if you want your fresh start to be persistent.
With one of these installed, you’ll have a reasonably secure embedded linux environment in which to experiment. You’ll need to customize these rules depending on the applications you plan to run, of course, but this provides a reasonable starting point.