artisanal filesystem hacking with systemd
A service I started running some instances of a while ago is RIPE
Atlas, a distributed dns/ping/traceroute
probing tool run by RIPE. It is pretty easy
to deploy - they provide an apt repository, that has a package in it
that installs an apt config that gives you access to the packages.
Once it's installed, it produces an SSH public
key
that you paste into a web page and away it goes.
It is however not super flexible to operate. One thing I wanted to do
was configure it to use an external resolver instead of the local
unbound instance I have that is full of weird config hax for my
internal network. As far as I could tell there's no config option
anywhere for this and I really wanted to avoid editing any of the
files in the package. Once again, systemd saves the day - just put
the resolver config in /etc/ripe-atlas/resolv.conf and a drop-in
file in /etc/systemd/system/ripe-atlas.service.d/dns.conf:
[Service]
BindReadOnlyPaths=/etc/ripe-atlas/resolv.conf:/etc/resolv.conf
et voila. Once again a thing I would probably not have bothered to do
in the pre-systemd era - it is easy to add a "mount --bind" line to
a sysvinit script but that would mean hacking a shell script from a
package (albeit a conffile), which is annoying going forward
(telling dpkg to leave it alone) and much more annoying to
automate - telling Ansible to insert a line into a text file in
roughly the right place is much more annoying than just dropping two
files on disk:
- name: Deploy RIPE Atlas custom resolv.conf
ansible.builtin.template:
src: ripe-atlas-resolv.conf.j2
dest: /etc/ripe-atlas/resolv.conf
owner: root
group: root
mode: '0644'
notify:
- "RIPE Atlas : restart service"
- name: Create ripe-atlas service override directory
ansible.builtin.file:
path: /etc/systemd/system/ripe-atlas.service.d
state: directory
owner: root
group: root
mode: '0755'
- name: Deploy ripe-atlas DNS override
ansible.builtin.template:
src: ripe-atlas-dns.conf.j2
dest: /etc/systemd/system/ripe-atlas.service.d/dns.conf
owner: root
group: root
mode: '0644'
notify:
- "RIPE Atlas : daemon-reload"
- "RIPE Atlas : restart service"
Which is actually quite verbose, but is extremely straight-forward and
depends on the systemd configuration merge semantics rather than
luck at automatically hacking shell scripts. I actually started
writing out an equivalent attempt using ansible.builtin.lineinfile
to edit an init script to add a mount --bind line after the header
(not correctly in the start and torn down in stop since that seems
way too hard), then remembered that in that world I'd first need to
write enough sh to put this service in a chroot to begin with, so
that I could customise the /etc/resolv.conf it saw.