Pasteur is an unikernel (MirageOS) which provides an mini-website to paste snippets and save them into a Git repository. The goal of this project is to be a full example of: how to write a website as an unikernel today?
This example uses several stacks:
- HTTP with http/af and paf
- Git with ocaml-git
- Irmin with irmin
- SSH with awa
- TLS with ocaml-tls
- TCP/IP of course with mirage-tcpip
- JavaScript with
js_of_ocaml
and brr - a read-only filesystem with docteur
The project needs MirageOS 4 and it is available here: https://paste.osau.re/
MirageOS lets user to choose which backend he/she wants. So we have 2 general backends:
- Unix target (a simple executable as usual)
- KVM or Xen with Solo5
We will explain the Solo5 target which provides a full operating system which can be executed into KVM. It needs few steps on your server to be able to run it. We will use albatross which helps us to deploy an unikernel.
To be able to deploy an unikernel, you should follow this little tutorial about
albatross
which describes how to install the albatross service and how to use
it: Robur Reproducible Builds
Then, we will play a bit with iptables
to allow our unikernel to communicate
with Internet and let clients to communicate with our unikernel. When we want
to virtualize an operating system, we need to configure a bridge on the host
system such as:
. [ vm00 ]
[ eht0 ] <- NAT -> [ br0 ] -|
` [ vm01 ]
The Robur's tutorial explain, on Linux, you can modify the file
/etc/network/interface
and add a new bridge with a specific MAC address:
auto service
iface service inet manual
up ip link add service-master address 02:00:00:00:00:01 type dummy
up ip link set dev service-master up
up ip link add service type bridge
up ip link set dev service-master master service
up ip addr add 10.0.42.1/24 dev service
up ip link set dev service up
down ip link del service
down ip link del service-master
You can restart your system or restart your Network service. You can check the
creation of your bridge via sudo ip a
and you will your new service
bridge.
More concretely, when you want to launch a unikernel with albatross
, the
Albatross daemon will create a [TAP][tap] interface and it will connect this
one to your bridge. Then, you just need to configure your NAT to allow
incoming and outcoming connections.
In this situation, we will try to configure your NAT to allow incoming and outcoming communications. But we need to allow IPv4 forwarding first:
user$ sudo su
root$ echo "1" > /proc/sys/net/ipv4/ip_forward
Finally, we can 1) let our host system to keep a table between our private IP address and Internet (such as our unikernel is able to maintain a connection with outside):
$ sudo iptables -t nat -A POSTROUTING -i eth0 -j MASQUERADE
Then, we will redirect incoming connection from our <public-ip>:{80,443}
1
to our private IP address of our unikernel (let's say 10.0.42.2
):
$ sudo iptables -t nat POSTROUTING -p tcp -m tcp --dport 80 -j DNAT \
--to-destination 10.0.42.2:80
$ sudo iptables -t nat POSTROUTING -p tcp -m tcp --dport 443 -j DNAT \
--to-destination 10.0.42.2:443
Warning: depending on your iptables
's rules but sometimes, the FORWARD
chain is setted to DROP
. Even if you follow this tutorial, any packets sent
by your unikernel will be lost - so you must update the FORWARD
chain with
ACCEPT
:
$ sudo iptables -A FORWARD -o service -m conntrack --ctstate \
RELATED,ESTABLISHED -j ACCEPT
$ sudo iptables -A FORWARD -i service ! -o service -j ACCEPT
$ sudo iptables -A FORWARD -i service -o service -j ACCEPT
As we said in introduction, we use a Git repository to store pastes. So we need to configure a bit the host server to setting up a Git server. You can follow this tutorial: Git SCM - Setting up the server
Warning: at some points, if you want to clone a Git repository, be sure
that you use the good branch in both sides. Indeed, for Debian, the main
branch still is master
and your main branch into your computer is
probably main
.
Finally, on the MirageOS side, the easy way to communicate with a Git
repository is to generate a in-the-fly RSA key, put it (as explained into
the tutorial) into the .ssh/authorized_keys
and keep the seed which will
be used by our unikernel:
$ opam install awa
$ awa_gen_key > awa.gen.key
$ tail -n1 awa.gen.key | ssh git@localhost 'cat >> ~/.ssh/authorized_keys'
$ head -n1 awa.gen.key
seed is svIdyO8boxNQP03NrUgfwDxk4iPaURukAyKl1cx8
Finally, we can build and launch our unikernel:
$ git clone https://github.com/dinosaure/pasteur
$ cd pasteur
$ opam install mirage
$ mirage configure -t hvt
$ make depends
$ mirage build
The distribution builds 2 artifacts:
- the unikernel
dist/pasteur.hvt
- an external image as a read-only filesystem
dist/disk
We need to add a new block device from our dist/disk
and launch our
unikernel:
$ albatross-client-local create_block --data dist/disk pasteur 1
$ albatross-client-local create \
--mem=512 --net=service:service --block=disk:pasteur dist/pasteur.hvt \
--arg='--remote git@10.0.42.1:pasteur.git' \
--arg='--ssh-key=rsa:svIdyO8boxNQP03NrUgfwDxk4iPaURukAyKl1cx8' \
--arg='--hostname <HOSTNAME>' \
--arg='--https=true' \
--arg='--ipv4=10.0.42.2/24' \
--arg='--ipv4-gateway=10.0.42.1'
As you can see, we set the --ssh-key
with our seed given by awa_gen_key
and we set a <HOSTNAME>
which will be our hostname used by our unikernel - be
sure that your DNS is well configured to your public IP address.
At the boot, pasteur
will do the Let's encrypt challenge and if it can get
the let's encrypt certificate, it will launch an HTTPS server.
Warning: the JavaScript script which encrypt/decrypt contents on the client side requires an HTTPS connection! That mostly means that if you access to the Pasteur website without TLS, the script does not work!
Pasteur is fully configurable about:
- the Git repository: the user can use a local or a remote Git repository. The
underlying protocol used to clone/pull/push can be SSH (as we did) or TCP/IP
via the
git://
URL or via HTTP(S) - The unikernel can launch a simple HTTP server without a TLS certificate via
--https=false
- and let something else such asnginx
orcontruno
to handle certificates - To test your deployement, you can ask a non-productive certificate - and
be able to launch your unikernel several times without the Let's encrypt
limit via the
--production=false
option - You are able to set the CSS if you want, you just need to update
public/pastisserie.css
and regenerate the image viadocteur
:docteur.make file://$(pwd)/public dist/disk
Footnotes
-
We must redirect
*:80
and*:443
becausepasteur
will do the HTTP let's encrypt challenge. So Let's Encrypt should be able to communicate with our unikernel via*:80
. ↩