Daily archives of “March 12, 2015

comments 2

Preparing a Secured Minimum System for Your RaspberryPi Server

Table of Contents

  1. Intro
  2. Operating System Selection
  3. Installing MinibianPi
  4. Creating New User With Administrative Privileges
  5. Securing The Operating System
  6. Getting The System Up-to-Date

Intro

A RaspberryPi isn’t the most powerful computer around, nor is it equipped to perform server-grade mission-critical tasks. But a lot of people use it as their home-grown server, some have multiple units or clusters of them, and some companies even offer RaspberryPi data centers.

I’m a tinkerer. This means I make mistakes, I ruin one of my servers, and — more often than not — I re-install it from scratch because I don’t know how to fix it. Then I do it all over again. Setting up a base system that I can build on has become a somewhat mundane task. This post documents just that: my endeavor to create a secured minimum system from which I can build a RaspberryPi server.

Disclaimer

I am by no means an expert in server installation or maintenance. I do this for fun, and sometimes I get lazy and cut corners. Please don’t treat this as a you-must-do-this guide, but more of a this-is-what-I-did and I’d like to share it with you. If you spot any mistakes, please let me know and I’ll do my best to address it immediately.


Operating System Selection

The objective of this build is to prepare a minimum system that is reasonably secured and can be used as a base system from which we can build a RaspberryPi-based server. Note the keywords: minimum and server. We won’t need to have a desktop environment, let alone Minecraft. Let’s leave all unnecessary things out of the build.

To achieve the objective, I chose MinibianPi. It’s a stripped-down version of Raspbian which is quite up-to-date, and even supports Pi 2. I think it’s a great place to start.


Installing MinibianPi

  1. Download MinibianPi image.
  2. Write the image to an SD card (there are instructions for Windows users, Mac users, and Linux users).
  3. Login as root (password is raspberry), either directly or via SSH using Terminal if you’re on a Mac or PuTTY if you’re a Windows user. The image has SSH enabled by default.
  4. Install raspi-config. We could just re-partition the SD card ourselves, but I would personally try to not mess with partitions.
    apt-get install raspi-config -y
  5. Run raspi-config, and then expand filesystem. We have to do this now to avoid running out of disk space when we start installing other stuff.
  6. Reboot

Creating New User With Administrative Privileges

I believe this is one of the most important things to do, because the default ‘pi’ user on the Raspbian image is vulnerable enough if exposed to the internet, let alone having a system with a known root password.

  1. First we need to update our repositories. I found out the hard way that if we do this any later, some installations just won’t work.
    apt-get update
  2. Next, we need to install sudo so that we can grant administrative privileges to non-root users.
    apt-get install sudo
  3. Alright, with that done, let’s add the new user.
    adduser USERNAME

    We have to set a password for this new user, but all other fields can be left blank.

  4. To grant administrative privileges, we can add USERNAME to the sudo group.
    adduser USERNAME sudo
  5. With that done, we can reboot and login as USERNAME.

Securing The Operating System

Regenerating Unique Host Keys

  1. The very first thing we need to do is regenerate the unique host keys.
    sudo rm /etc/ssh/ssh_host_* && sudo dpkg-reconfigure openssh-server
  2. Next we need to verify that the keys have indeed changed and make sure we’re still able to login. If you’ve been doing all this via SSH, try to login using another Terminal or PuTTY session. If you’re using PuTTY, you should see a warning and getting past it is simple. If you’re using Terminal or a Linux machine, you need to remove the host key from your known hosts file. Here’s how you do it if you previously logged in using the Pi’s IP address:
    ssh-keygen -R 192.168.1.111

    If that doesn’t work, and you’re okay with resetting your entire known hosts file, just delete it:

    cd
    rm .ssh/known_hosts
    ssh ras.mydomain.com

Setting Up Key Pair Authentication for SSH

Next, we should prefer key pair authentication for SSH than the default password authentication. As long as we don’t lose our private key, that is. If you’re a Mac or Linux user, follow along. If you’re stuck with Windows, like I am, here‘s a good article about setting up key pair authentication using PuTTY.

  1. On your own terminal (not on the Pi), do this to create your private and public key pair:
    ssh-keygen
  2. Follow the on-screen instructions to create the SSH keys on your computer. To use key pair authentication without a passphrase, press Enter when prompted for a passphrase. After completing this, 2 files will be created in the directory ~/.ssh (or /home/USERNAME/.ssh). The file id_rsa is your private key, and id_rsa.pub is your public key. Now, we need to upload the public key to the Pi. Let’s use SCP for this:
    scp ~/.ssh/id_rsa.pub USERNAME@192.168.1.2:

    Change 192.168.1.2 to your Pi’s reserved IP address.

  3. Then, using the Pi’s console, on the Pi’s home directory, let’s create the .ssh directory:
    mkdir .ssh
  4. Next, move and rename the id_rsa.pub file to the .ssh directory and change permissions to secure it:
    mv id_rsa.pub ~/.ssh/authorized_keys
    chown -R USERNAME:USERNAME .ssh
    chmod 700 .ssh
    chmod 600 .ssh/authorized_keys
    

After that’s done, our Pi will be able to authenticate us using our public key. To try this out, logout from your Pi and try to login again. Instead of the usual SSH login prompt, you will be prompted to enter your passphrase if you have one. If you didn’t set a passphrase, you’ll be logged in immediately.

Disabling Password Authentication and Root Login

When we’re able to log in using key pair authentication, we should disable password authentication. While we’re at it, let’s disable root login as well:

  1. Edit the file /etc/ssh/sshd_config
    sudo nano /etc/ssh/sshd_config
  2. Set ‘PasswordAuthentication’ value to ‘no’.
  3. Set ‘PermitRootLogin’ value to ‘no’.
  4. Restart SSH service.
    sudo service ssh restart
  5. Test by logging in without your private key, the attempt should be rejected.

Installing Iptables and Setting Up Basic Firewall Rules

To protect against attackers who take advantage of open ports, we should install iptables and set our default firewall rules. For now, we’ll just block everything except localhost, network pings, and SSH on port 22.

  1. Install iptables using apt-get
    sudo apt-get install iptables -y
  2. Create a new file for our default firewall settings
    sudo nano /etc/iptables.firewall.rules
  3. Put the following text into the file, then save it and exit
    *filter
    
    # Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
    -A INPUT -i lo -j ACCEPT
    -A INPUT -d 127.0.0.0/8 -j REJECT
    
    # Accept all established inbound connections
    -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    # Allow all outbound traffic - you can modify this to only allow certain traffic
    -A OUTPUT -j ACCEPT
    
    # Allow SSH connections
    # The -dport number should be the same port number you set in sshd_config
    -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
    
    # Allow ping
    -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
    
    # Log iptables denied calls
    -A INPUT -m limit --limit 5/min -j LOG --log-prefix "[NETFILTER] denied: " --log-level 7
    
    # Drop all other inbound - default deny unless explicitly allowed policy
    -A INPUT -j DROP
    -A FORWARD -j DROP
    
    COMMIT
  4. Save and exit nano, then apply the rules
    sudo iptables-restore < /etc/iptables.firewall.rules
  5. Check to see that the rules are in place
    sudo iptables -L

    You should get an output like this:

    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    ACCEPT     all  --  anywhere             anywhere
    REJECT     all  --  anywhere             127.0.0.0/8          reject-with icmp-port-unreachable
    ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
    ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh
    ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
    LOG        all  --  anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "[NETFILTER] denied: "
    DROP       all  --  anywhere             anywhere
    
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination
    DROP       all  --  anywhere             anywhere
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    ACCEPT     all  --  anywhere             anywhere
  6. All good! We just need to make sure those rules get loaded on every reboot. To do that, we’ll need to create a script:
    sudo nano /etc/network/if-pre-up.d/firewall
  7. Put the following code in the file:
    #!/bin/sh
    /sbin/iptables-restore < /etc/iptables.firewall.rules
  8. Save, exit, nano, and make the file executable by root and not accessible by anyone else.
    sudo chmod 700 /etc/network/if-pre-up.d/firewall
  9. Test by rebooting and checking iptables right after you’re able to login again.
  10. After confirming that the firewall is automatically restored on boot, let’s make the system logger divert all iptables-related rules to a different log file. This will come in handy when we need to analyze the logs, saving us the time to sort out the firewall log from other log entries. First, let’s create a new file:
    sudo nano /etc/rsyslog.d/iptables.conf

    In the file, enter the following:

    :msg, contains, "[NETFILTER]" /var/log/netfilter.log
    :msg, contains, "[NETFILTER]" ~
    

    Save and exit, and then restart rsyslog service:

    sudo service rsyslog restart

    After doing this you should have all log messages having the prefix [NETFILTER] stored in /var/log/netfilter.log.

NOTE: This build will eventually evolve into a server, which means we will need some more ports opened for our services to be able to function properly. When you have your services up and running locally but can’t access it from your network, just remember to check your iptables settings and make sure it’s not blocking your service port.

Installing fail2ban

The last item in our security checklist is installing a piece of software called fail2ban. It will monitor our log files for failed login attempts. After an IP address has exceeded the maximum number of authentication attempts, it will be blocked at the network level and the event will be logged in /var/log/fail2ban.log. To install it, issue the following command:

sudo apt-get install fail2ban -y

Getting The System Up-to-Date

Now the system is relatively secure and almost ready, but before we proceed with actually building the server, let’s upgrade everything first.

  1. Update all installed software packages:
    sudo apt-get upgrade -y && sudo apt-get dist-upgrade -y
  2. Update the Pi’s firmware while we’re at it
    sudo apt-get install rpi-update -y
    sudo rpi-update

That’s it, now we have a secured minimum system ready to build. What servers can we build from this starting point? That depends on your imagination. Enjoy!


References and Further Reading

These articles are a good read if you’re into setting up your own RaspberryPi-based server. I believe they use the standard Raspbian Wheezy image for their tutorials, but most of the commands will run just fine.

  1. How to set up a secure Raspberry Pi web server, mail server and Owncloud installation — pestmeester.nl
  2. Setting up a (reasonably) secure home web-server with Raspberry Pi — Matt Wilcox

Please have a look at them if you’re interested in learning more. Meanwhile, I’ll be documenting my own endeavor to build my server based on MinibianPi (as opposed to standard Raspbian Wheezy).