Wednesday, May 22, 2013

RPi-Monitor: Security and authentication with a reverse proxy

RPi-Monitor was embedding a web server supporting ssl which was working correctly on Ubuntu distribution but unfortunately crashed on Raspbian. I did remove it since version 1.2 to remove dependencies.
Photo from flickr AttributionNoncommercialNo Derivative Works cc-nc-nd by cjelli
In this post, we will see how to increase the security of RPi-Monitor by using a reverse proxy. The reverse proxy will be in charge of user authentication and ssl connections. We will also configure a firewall to make the RPi ready to be directly connected to Internet.


You may notice in RPi-Monitor the menu shellinabox. Activating this feature is also a topic of this post.
Note: This post is inspired by the article rpi-nginx-shellinabox written by Guilhem Marchand.

Prerequisite

Before following the instruction of this post, you have to install the version 1.3 of RPI-Monitor. You will find all the details into this previous post.

Install Software

We start to install nginx for the reverse proxy and shellinabox with the following command:

sudo apt-get install nginx shellinabox


Manage authentication

To manage authentication we need to create a file gathering the username and passwords. The following script will help you to generate new users id and encrypted password.

#!/bin/bash

if [ "$(id -u)" != "0" ]; then
  echo "This script must be run as root"
  exit 1
fi

echo -n "Enter new username: "; read user
echo -n "Enter new password: "; read pass

printf "$user:$(openssl passwd -crypt $pass)\n" >> /etc/nginx/.htpasswd

This script is  also downloadable from Github. Execute the following command to use it:

wget http://goo.gl/DO1hw -O addnginxuser.sh
chmod +x addnginxuser.sh
sudo ./addnginxuser.sh

Answer to the question and you are done. If you need to enter additionnal user, execute the script again.

Manage secured connection

To activate SSL connection we need to create certificate. In this post we will create a simple self signed certificate.

sudo mkdir -p /etc/ssl/localcerts
openssl req -new -x509 -days 3650 -nodes -out \
/etc/ssl/localcerts/RPi-Experiences-cert.pem -keyout \
/etc/ssl/localcerts/RPi-Experiences-key.pem
chmod 600 /etc/ssl/localcerts/*

Replace the certificate of shellinabox with the one we will also use for the reverse proxy. We will then have to accept only one time when the browser will raise the certificate warning.

sudo cat /etc/ssl/localcerts/RPi-Experiences-cert.pem \
/etc/ssl/localcerts/RPi-Experiences-key.pem >> \ /var/lib/shellinabox/certificate.pem 

Reverse proxy configuration

Let's first deactivate the default site since we want to use ngnix as a reverse proxy only. To do so, delete the symbolic link from sites-enable directory:

sudo rm /etc/nginx/sites-enable/default

Create the file /etc/nginx/sites-available/reverseproxy with the following content (also downloadable from Github):

access_log off;
add_header Cache-Control public;
server_tokens off;

# HTTP 80
server {
 listen         80;
 #Force the usage of https
 rewrite ^ https://$host$request_uri? permanent;
}

# HTTPS 443
server  {
  listen 443 ssl;
  keepalive_timeout 70;

  # SSL config
  ssl on;
  ssl_certificate /etc/ssl/localcerts/RPi-Experiences-cert.pem;
  ssl_certificate_key /etc/ssl/localcerts/RPi-Experiences-key.pem;

  ssl_session_timeout 5m;
  ssl_protocols SSLv3 TLSv1.2;
  ssl_ciphers RC4:HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  # Allow to use frame from same origin
  add_header X-Frame-Options SAMEORIGIN;

  # DDOS protection - Tune Values or deactivate in case of issue
  # limit_conn conn_limit_per_ip 20;
  # limit_req zone=req_limit_per_ip burst=20 nodelay;

  # Proxy Config
  proxy_redirect          off;
  proxy_set_header        Host            $host;
  proxy_set_header        X-Real-IP       $remote_addr;
  proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
  client_max_body_size    10m;
  client_body_buffer_size 128k;
  proxy_connect_timeout   90;
  proxy_send_timeout      90;
  proxy_read_timeout      90;
  proxy_buffers           32 4k;

  # Define the default site
  location / {
    rewrite ^ /rpimonitor/ permanent;
  }

  location /rpimonitor/ {
  proxy_pass http://localhost:8888;
    auth_basic            "Access Restricted";
    auth_basic_user_file  "/etc/nginx/.htpasswd";
    access_log /var/log/nginx/rpimonitor.access.log;
    error_log /var/log/nginx/rpimonitor.error.log;
  }

  location /shellinabox/ {
  proxy_pass http://localhost:4200;
    auth_basic            "Access Restricted";
    auth_basic_user_file  "/etc/nginx/.htpasswd";
    access_log /var/log/nginx/shellinabox.access.log;
    error_log /var/log/nginx/shellinabox.error.log;
  }
}

Activate the reverse proxy site and retart nginx with the following commands:

sudo ln -s /etc/nginx/sites-available/reverseproxy /etc/nginx/sites-enabled/
sudo service nginx restart

You can now start to test to access your configuration by browsing http://RPiIpAddresss/. You will be automatically redirected to https://RPiIpAddress/rpimonitor/.

You can activate shellinabox from the configuration window and use shellinabox from RPi-Monitor top menu (https://RPiIpAddress/rpimoitor/shellinabox.html).

Configure the firewall

To finish our protection, we will then configure some basic firewall rules to reject every traffic but http (redirected to https), https and ssh. The following lines are doing the job:

sudo iptables -F
sudo iptables -A INPUT -i lo -p all -j ACCEPT
sudo iptables -A OUTPUT -o lo -p all -j ACCEPT
sudo iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
sudo iptables -A INPUT -p tcp --dport http -j ACCEPT
sudo iptables -A INPUT -p tcp --dport https -j ACCEPT
sudo iptables -P INPUT DROP

Explanation:

line 1 : clean previously existing rules
lines 2 and 3 : Add a full access to lo interface (which can only be accessed locally and which is used by the reverse proxy to reach RPi-Monitor and shellinabox)
line 4 : continue to accept established connection on interface eth0
line 5 : accept connection to port ssh (22)
line 6 : accept connection to port http (80)
line 7 : accept connection to port https (443)
line 8 : drop anything else

Executing the  command lines described upper will apply the firewall configuration but without persistence  this means that the firewall configuration will disappear after reboot. To make the firewall persistent we need to install an additional package:

sudo apt-get install iptables-persistent

When the installation program ask you to record the actual ipv4 rules, answer yes and the job is done (you can skip ipv6 rules recording). The configuration is now stored into /etc/iptables/rules.v4 and will be reapplied at start-up.

Conclusion

Now your RPi is protected. You can try to access to RPi-Monitor directly (http://RPiIpAddress:8888/) and you will have an error. If you try to access to it through the revers proxy (http://RPiIpAddress/) you will have to authenticate before accessing to the server and once authenticated, you will be connected through a secured https connection. 

Here it is we have a server which is now able to be connected on the internet.

Stay tuned ;-)
In next post we will see how to generate multi-domain certificate to remove the https warning.


5 comments :

  1. I don't want to replace the Lighttpd with Nginx, or install the Nginx. How can I secure it with Lighttpd?

    ReplyDelete
    Replies
    1. There are many Web Servers existing nginx and lighttpd but also apache, cherokee and certainly other. In this post, I cover nginx only, if you want to use lighttpd (or other) to secure RPi-Monitor, I would advise to read and understand how I do with nginx and try to reproduce this architecture with lighttpd (or other).

      Note: If you write an article about how to configure lighttpd to secure RPi-Monitor, I'll be happy to add a link in this page pointing to your post.

      Delete
    2. I couldn't found the solution. :-/
      This is an interesting thing: I stop the lighttpd service, but I can access the webpage of RPi-Monitor. I don't understand it!
      How van I add a secure page for it, if it hasn't webserver component?
      How does it work? What is the frontend of it?

      Delete
    3. Your problem doesn't looks to be related to Rpi-Monitor. Maybe lighttpd forum/blog/website can answer to your questions.
      In this post, I do explain how to use nginx and it works like a charm...

      Delete
  2. Hello,

    thank you very much for this article and the wonderful rpimonitor tool.
    I'm experimenting with it the last two days locally and had quite some fun with it.
    Made storage and service information run and so forth. Really nice!

    Now, I wanted to start using it via nginx, followed your guide here on this page but unfortunately do not succeed. I had to incorporate it into a running nginx setup rather than defining the reverse-proxy configuration you have presented here (because I already have a couple of webservices up and running). But except some additional /locations/ and some rules for php file parsing there is nothing alien about it.

    However, it doesn't work with rpimonitor so far. Maybe you are able to point me in the right direction?

    Here is the status: the rpimonitor subdomain responds as expected when I point my browser to it, I am asked for the credentials and get redirected to the expected page "Welcome to Rpi-Monitor etc". Sounds and looks pretty promising so far. But one observation here: the linking "Start" button is plain text, without any decoration. Even worse, when I click it I get redirected to the .../status.html page but only see one single black dot. That is it, nothing else. No bootstrap beauty, no info, no links, nada.

    Any ideas?
    Thx and cheers,
    Nix

    ReplyDelete