blog.ondevice.io

How it all started

Hi, I’m Manuel from ondevice.io.

Since this is the first blog post, I thought it would be fitting to talk a little about what got the project started in the first place.

The ‘work’ reason

We manage a couple hundred Linux PCs and servers that mostly run on premise at our customers.
They’re all connected to a VPN server (OpenVPN, which uses UDP port 1194 by default) for software upgrades and the like.

And most of the time that works fine. But every so often our PCs end up in networks that are a little more restrictive than the others (limiting UDP or even blocking everything but HTTP/HTTPS and a few other common ports).

There are different reasons for those restrictions. Sometimes it’s corporate policy, other times our PCs end up in the public network (an open WIFI for example).
A quick talk to the respective network admin usually gets us firewall exceptions, but every one of those special treatments is a problem waiting to happen (e.g. if the server IP changes, etc.).

Over time, these issues have become kind of a nuisance and I started thinking of ways to turn this white-listing problem (i.e. “please put me on the white list”) into a black-listing one (“if you want, you can blacklist my traffic, but if you don’t it’ll work”).

One of the suggestions you’ll read on the internet is to simply run OpenVPN on port 443 (TCP of course), since no network admin in their right mind would block HTTPS, right?
But that always seemed like kind of a hack, and running OpenVPN on port 443 means you can’t run HTTPS on the same server.

Other issues with classic VPNs: - IP range clashes:
With enough clients out ‘in the wild’, there’s gonna be one or two in a network that uses the same private IP address space you want to use for your VPN, causing all kinds of headaches. - cloned disk images:
With traditional VPNs, if you clone a disk image (to avoid having to set up hundreds and thousands of PCs separately), those PCs end up with the same VPN credentials. Of course there are initialization scripts that fix that, but in case that script doesn’t work as expected (or wasn’t invoked for whatever reason) you end up with PCs sharing those credentials (and with OpenVPN they end up kicking each other out of the network over and over again), which makes keeping track of running certain scripts once for each PC hard if not impossible.

The ‘tech enthusiast’ reason

Running all kinds of hardware in my own flat as well as in my parent’s home, I wanted a simple way to SSH into those devices when needed (e.g. my Raspberry PIs).
In the past I’ve set up yet another VPN for that exact purpose, but it always felt a little too complicated to set up (creating certificates, messing around with config files, etc).

Core concepts

After letting the idea sink in for some time, I ended up with these design principles:

  • firewall-friendly:
    As long as HTTPS works, the (at that time yet to be named) service works as well.
    Using websockets over HTTPS seemed to be the perfect fit.
  • SSH-first:
    To keep things simple, focus on tunneling SSH first. Since OpenSSH can do all sorts of fun things (like tunneling other protocol, playing proxy, etc.), is end to end encrypted and has decent authentication, we get a ton of features practically for free.
  • lightweight:
    It’s not a full-blown VPN. Instead of exposing your whole PC (and possibly your network), you explicitly enable the services you want to expose.
  • simple to use: It has to feel just like calling ssh, rsync etc (so no need to learn new commands).
    The only difference is the ondevice ... prefix as well as the host names
  • easy to set up:
    “install a package, set up your credentials and you’re good to go”
  • account separation:
    • only you (and the people you trust) are able to connect to your devices
    • device IDs are unique to each account and randomly generated (but can be set explicitly)
  • distinction between device and client:
    • devices expose services, client connect to those services
    • device daemons keep running in the background, clients are started on demand
    • devices can’t see or connect to other devices
    • devices can also be clients (thus lifting above restriction)
  • scriptability:
    • ondevice ssh behaves like the regular SSH, allowing you to use it (+ its output and exit code) in scripts
    • devices can have user-defined properties (arbitrary key=value pairs).
      This allows keeping track of hard-/software characteristics as well as maintenance script execution.
  • cloneability:
    In case of a deviceID clash (e.g. if a disk clone of another device tries to come online) the service assigns a new, random ID to the new device and sets its parent to the original device (which in turn makes all clones children of the original)
  • protocol-agnosticity:
    The service is protocol agnostic and doesn’t care about the contents of the data it relays. The official client is open source, custom implementations are welcome (the necessary documentation for that is still work in progress at the time of this writing)

With these pillars in place, the next step was to pick frameworks for both the client and the server.
I’ll write these up in on of the next posts…


Share