Gophermoon 0.2 - a Gopher-Server in Lua – Part 2
What's in it today
I will not change the (minimal) Gopher server (this time), but will prepare the execution environment for Gophermoon: the result will be a container containing, only one executeable and one Lua-Script besides the Gopher content.
The container will be isolated from the network and the filesystem and process-space of the host machine.
So any coding errors I will create while expanding the Gophermoon-Server will have limited security impact on the host system (unless there is a security issue in the container code of the Linux-Kernel, which there have been in the past. Nothing is fully secure).
I'm testing on a RedHat EL 7 machine, but the same result should be possible on other modern Linux systems with a container manager (systemd-nspawn, docker, rkt, LXC …).
Building a static Lua
One feature that makes the Go programming language popular among users of Linux-Containers is the fact that Go produces static binaries. Static binaries have no code runtime dependencies, they are self contained and do not need to be installed, but can just copied around and "just work".
Lua is written in C, but we can create static binaries in C too.
It is recommended to compile the static Lua binary on an development machine, not on the production Gopher server.
For Red Hat based systems, we need to install few build tools and the static library files for the GNU-Libc:
yum install make gcc wget glibc-static
Next, we're downloading the Lua sourcecode from https://www.lua.org/download.html
mkdir ~/src cd ~/src wget https://www.lua.org/ftp/lua-5.3.4.tar.gz tar xfz lua-5.3.4.tar.gz cd lua-5.3.4/src
The option -static
lets the gcc
compiler and linker build a static
binary. Change the MYCFLAGS
and MYLDFLAGS
lines in Makefile
:
[...] MYCFLAGS= -static MYLDFLAGS= -static [...]
Now we can build the new Lua interpreter. I'm building the posix
flavor, which is more generic than the Linux flavor and links less
external libraries:
make posix strip lua
The resulting lua
binary should be a static ELF executable:
# file lua lua: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0631bb0d50ad1209dbf55f2b1dd0eb60fc388df7, stripped # ls -lh lua -rwxr-xr-x. 1 root root 1,7M 23. Dez 23:04 lua
Gophermoon inside a systemd-nspawn container
Next the container root directory is created and the static lua
interpreter together with the gophermoon
script is placed into that
container directory:
mkdir -p /srv/gophermoon/bin cp lua /srv/gophermoon/bin/ mv /usr/local/sbin/gophermoon /srv/gophermoon/bin/
Without timezone information files within the container directory,
systemd-nspawn
will complain about not being able to update the
timezone in the container
Timezone <your-host-timezone> does not exist in container, not updating container timezone.
So far, I found no better way than to copy the timezone information into the container root (only one file is enough if you know the timezone of your host machine):
mkdir -p /srv/gophermoon/usr/share/zoneinfo cp -a /usr/share/zoneinfo/* /srv/gophermoon/usr/share/zoneinfo/
A quick manual test starting the container from the commandline:
# /bin/systemd-nspawn -q --private-network -D /srv/gophermoon /bin/lua /bin/gophermoon iWelcome to GopherMoon @ defaultroutes.de defaultroutes.de 70 i---------------------------------------- defaultroutes.de 70 .
Here is the updated Systemd-Service-Unit (/etc/systemd/system/gophermoon@.service
):
[Unit] Description=GopherMoon Gopher Server in La [Service] ExecStart=/bin/systemd-nspawn -q -x --private-network -D /srv/gophermoon /bin/lua /bin/gophermoon StandardInput=socket
The -x
option creates an ephemeral container that is started from an
BTRFS snapshot each time a new gopher connection comes in. The
snapshot is destroyed as soon as the container terminates. An intruder
will not be able to store new files into the container system.
At last we reload the new unit into Systemd and restart the Socket-Activation:
systemctl daemon-reload systemctl restart gophermoon.socket
Now gophermoon
runs in a (more) secure environment.