Securing the Realm Object Server with Let’s Encrypt

Why Secure your Realm Object Server?

This article was written for Realm Object Server 1.x. A few things have been changed since then, so click here for an updated version.

So, you’ve developed an app with the Realm Platform, and you’re ready to go live. Before you hit the publish button though, consider the fact that it’s 2017 - your users expect that their data is secure and not being snooped on. Imagine how much a privacy scandal would hurt the adoption of your app! Combine that with the fact it takes only 10-15 minutes to setup proper encryption, and you really have no excuse not to do it.

As for why Let’s Encrypt? Well, it’s free and automated - what’s not to like? No need to deal with email reminders, copying certificates, or paying fees.

Establishing Expectations

These instructions apply to setting up a Realm Object Server on a Ubuntu instance. For self-sufficiency’s sake, I’ll include all commands needed to make it work there, but will also link to the official docs if you have a different setup.

To obtain a certificate, you’ll need to have a domain name registered. If you’re hosting your server on a public cloud, Let’s Encrypt won’t let you register a certificate for a DNS with the cloud provider’s top-level domain (e.g., myserver.something.azure.com) because too many certificates have been issued for that domain.

Finally, this guide will assume you have a very basic understanding of Linux. If you know what ls does and how to quit vim, you’re good to go. If you know how to recompile the kernel, then I’m afraid you’ll get bored with these instructions rather quickly :)

Installing the Realm Object Server

If your server is hosted in a cloud environment, you’ll probably need to open ports 9080 and 9443 - those are used by Realm for http and https traffic respectively. Additionally, you’ll need to open 443 as it will be used by Let’s Encrypt to verify domain ownership. If you’re self-hosting, you may need to open them in the built-in firewall:

Get more development news like this

sudo ufw allow 9080/tcp
sudo ufw allow 9443/tcp
sudo ufw allow 443/tcp
sudo ufw reload

Instructions for other Linux flavors can be found in the Realm Object Server docs

After this, setting up ROS is fairly straightforward - 5 lines you need to drop into terminal and you’re good to go:

# Setup Realm's PackageCloud repository
curl -s https://packagecloud.io/install/repositories/realm/realm/script.deb.sh | sudo bash

# Update the repositories
sudo apt-get update

# Install the Realm Object Server
sudo apt-get install realm-object-server-developer

# Enable and start the service
sudo systemctl enable realm-object-server
sudo systemctl start realm-object-server

Again, instructions for other Linux flavors can be found in the Realm Object Server docs

You should now be able to head to http://ros.myserver.com:9080 and complete the setup process of creating an admin user.

Setting up the Realm Object Server

Now that the server is installed, let’s configure it - fire up your favorite editor (which clearly is vim) and edit /etc/realm/configuration.yml. There are a bunch of useful configuration options there, but what we care about is the proxy:https section, which is roughly in the middle of the file. Let’s uncomment the settings and set the certificate paths:

https:
  # Obviously, we want it enabled
  enable: true

  # Paths to the keys we'll obtain from LetsEncrypt later
  certificate_path: '/etc/realm/keys/fullchain.pem'
  private_key_path: '/etc/realm/keys/privkey.pem'

  # Listen to all interfaces, not just localhost
  listen_address: '::'

  # 9443 is fine, no need to change that
  # listen_port: 9443

If you restart the service now, you’ll notice that it fails to start due to configuration errors - the certificate paths are invalid, but that’s fine, we’ll fix them in a bit.

Obtaining Certificates

There are a gazillion ACME clients for Let’s Encrypt out there, but we’ll use the recommended one, Certbot. Let’s install it and fire it up:

# install certbot
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot 

# fire it up in certonly mode
sudo certbot certonly

Instructions for other Linux flavors can be found on the Certbot website

Now, you should be presented with a question - do you want to spin up a temporary server or use webroot. Unless you already have a web server running on that box, you should probably choose the former.

Next you’ll be asked for domain name(s). Since Let’s Encrypt won’t issue wildcard certificates and you probably don’t want to host your website on that box, you can setup a DNS record for something like ros.myserver.com and point it to your server. If everything goes well, certbot will negotiate with Let’s Encrypt and place your certificates in /etc/letsencrypt/live/ros.myserver.com/.

Providing the Certificates to ROS

Now we have ROS and our certificates, but there are a few more things to do before being able to relax and enjoy our secure communication. By default, certbot will apply severe restrictions on who can read the certificates folder (and that’s a good thing!), but that means that, because it is not running as root, ROS will not be able to access them. As we don’t want to mess with certbot’s permissions structure, so instead we’ll copy relevant certificates to the /etc/realm/keys folder.

First, let’s create the directory:

sudo mkdir /etc/realm/keys
sudo chown realm:realm /etc/realm/keys
sudo chmod 500 /etc/realm/keys

This creates the folder, changes the owner to realm (the user under which ROS runs), and sets the permissions to read and execute, the latter of which are needed to access files within.

At this point we could copy the files manually inside the folder, but that’s boring and not future-proof - Let’s Encrypt certificates are relatively short-lived (90 days to be exact), so you’d need to renew sooner rather than later, and then you’d have to remember to copy the files, which is error-prone. Instead, we’ll prepare a certbot renew hook script that will be executed after successful renewal:

#!/bin/sh

set -e

for domain in $RENEWED_DOMAINS; do
        case $domain in
        ros.myserver.com) # <- Update this with your own server
                realm_cert_root=/etc/realm/keys

                # Make sure the certificate and private key files are
                # never world readable, even for an instant, while
                # we're copying them into realm_cert_root.
                umask 077

                cp "$RENEWED_LINEAGE/fullchain.pem" "$realm_cert_root/fullchain.pem"
                cp "$RENEWED_LINEAGE/privkey.pem" "$realm_cert_root/privkey.pem"

                # Apply the proper file ownership and permissions for
                # Realm to read its certificate and key.
                chown realm:realm "$realm_cert_root/fullchain.pem" \
                        "$realm_cert_root/privkey.pem"
                chmod 400 "$realm_cert_root/fullchain.pem" \
                        "$realm_cert_root/privkey.pem"

                # restart ROS
                systemctl restart realm-object-server
                ;;
        esac
done

Here’s the human-readable explanation of the various steps:

  1. Check that we’re copying the correct certificate - ros.myserver.com, and avoid touching unrelated certificates.
  2. Copy the new certificates to /etc/realm/keys.
  3. Set the owner of the copied file to the realm user.
  4. Set permissions to “read” just for the file owner, and “none” for everyone else.
  5. Restart ROS to make sure it picks up the new certificate.

Drop that in a non-public folder (e.g., /etc/realm/keys/) and make sure to make it executable (chmod 500 /etc/realm/keys/post-renew.sh).

Now it’s time to make sure everything works as expected. Run:

sudo certbot renew --renew-hook /etc/realm/keys/post-renew.sh --force-renewal

This will force renewal and, upon success, execution of the renewal script. If everything goes according to plan, we should see the new certificates in the /etc/realm/keys folder and restarting the ROS service should be able to pick them up. Head over to the browser and verify that you can open https://ros.myserver.com:9443.

The final step is to automate the renewal so we don’t have to worry about the certificate expiring. Since we’ve verified that our post-renew script works as expected, we can safely setup a cron job to run the renew command:

sudo crontab -e

# choose your favourite editor and paste this at the bottom of the file
0 4 * * * certbot renew --renew-hook /etc/realm/keys/post-renew.sh --quiet

Certbot will only renew certificates nearing expiration, so running it daily is perfectly fine.

Finale

That’s it. We now have a secured Realm Object Server instance that will renew and pick up new certificates without user interaction. It’s a one-time setup that is definitely worth the effort to ensure that your users’ data is not tampered with along the wire.

Ultimately, I’d like to see an “Enable SSL” button in the ROS Dashboard that will handle all the negotiation under the hood, so there’ll be no excuse to host an unprotected instance, ever! Until then though, do invest a little time - your users will thank you for it! :)

Next Up: Get started with the Realm Mobile Platform!

General link arrow white

About the content

This content has been published here with the express permission of the author.


Nikola Irinchev

Nick has extensive experience with everything .NET - from architecting highly performant web servers to shipping cross platform mobile apps, you name it. Now he resides at Realm, delivering the best database in the world to .NET developers. When he’s not doing that, he speaks about cloud infrastructure and occasionally blogs about the hard problems he faces.

4 design patterns for a RESTless mobile integration »

close