Files
oswald-infra/butane/oswl_connector.yaml.tftpl

94 lines
4.1 KiB
Plaintext

variant: flatcar
version: 1.0.0
# Headscale (Tailscale) node: advertises 192.168.7.0/24 as a subnet route and
# offers itself as an exit node.
#
# Registered as an EPHEMERAL node: tailscaled runs with in-memory state, so the
# VM re-authenticates on every boot and headscale drops the node shortly after
# it goes offline. That requires the preauth key to be both --ephemeral and
# --reusable, otherwise the second boot fails to register.
#
# HEADSCALE_AUTHKEY is templated in from Infisical (see secrets.tmpl) by
# main.tf, not stored here. It still ends up in plaintext in the rendered
# Ignition snippet on the node's storage -- see the caveat in flatcar-todo.md.
systemd:
units:
- name: tailscaled.service
enabled: true
contents: |
[Unit]
Description=Tailscale node (headscale subnet router + exit node)
After=docker.service network-online.target versions-fetch.service
Requires=docker.service
Wants=network-online.target versions-fetch.service
[Service]
# Image tag comes from versions.env; see butane/versions-sync.yaml.
EnvironmentFile=/etc/versions.env
TimeoutStartSec=0
# None of these are loaded by default on a stock Flatcar boot, and the
# container cannot load them itself: it has NET_ADMIN (enough to write
# iptables rules) but not SYS_MODULE, and the image ships no
# /lib/modules, so tailscaled's own modprobe fallback fails with
# "the filter table does not exist". Loading them here works because
# the container shares the host's network namespace (--network host),
# so it sees tables created on the host. Without the nat table in
# particular there is no ts-postrouting chain, which means no SNAT:
# the exit node cannot work at all and subnet-routed replies are sent
# back to tailnet addresses the LAN has no route for.
ExecStartPre=-/usr/sbin/modprobe -a tun iptable_filter iptable_nat ip6table_filter ip6table_nat nf_tables xt_mark
# Recommended by Tailscale for subnet routers and exit nodes: without
# this, UDP throughput through the node is roughly halved.
ExecStartPre=-/usr/bin/bash -c 'ethtool -K $(ip route show 0.0.0.0/0 | cut -d" " -f5) rx-udp-gro-forwarding on rx-gro-list off'
ExecStartPre=-/usr/bin/docker rm --force tailscaled
ExecStart=/usr/bin/docker run --name tailscaled \
--network host --cap-add NET_ADMIN --cap-add NET_RAW \
--device /dev/net/tun \
-e TS_AUTHKEY=${headscale_authkey} \
-e TS_HOSTNAME=oswl-connector \
-e TS_ROUTES=192.168.7.0/24 \
-e TS_ACCEPT_DNS=false \
-e "TS_EXTRA_ARGS=--login-server=https://hs.atlashorizon.net --advertise-exit-node" \
-e TS_USERSPACE=false \
$${TAILSCALE_IMAGE}
ExecStop=/usr/bin/docker stop tailscaled
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
- name: dozzle-agent.service
enabled: true
contents: |
[Unit]
Description=Dozzle Agent
After=docker.service versions-fetch.service
Wants=versions-fetch.service
Requires=docker.service
[Service]
# Image tag comes from versions.env; see butane/versions-sync.yaml.
EnvironmentFile=/etc/versions.env
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker rm --force dozzle-agent
ExecStart=/usr/bin/docker run --name dozzle-agent \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 7007:7007 \
$${DOZZLE_IMAGE} agent
ExecStop=/usr/bin/docker stop dozzle-agent
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
storage:
files:
# Forwarding must be on for the subnet route and the exit node to pass
# traffic at all; the container shares the host netns (--network host), so
# this has to be set on the host, not inside it.
- path: /etc/sysctl.d/99-tailscale.conf
mode: 0644
contents:
inline: |
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1