Commit 9467ed29d6

9467ed29d693e590e8e037c8858eeb793f21f029

parent: 9809a86bfc

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-28 07:31 UTC

runner egress: remove the rule when it blocks the runner's poll

Ref #260

Layout: unified · split

deploy/gitbay-runner-egress.nft +4 −3
@@ -20,9 +20,10 @@
20# 127.0.0.1:22 the forge over loopback, for the runner. Builds do 20# 127.0.0.1:22 the forge over loopback, for the runner. Builds do
21# not reach loopback at all: the runner starts them 21# not reach loopback at all: the runner starts them
22# with pasta's gateway mapping off (--no-map-gw). 22# with pasta's gateway mapping off (--no-map-gw).
23# loopback :53 the host's resolver, which pasta forwards a 23# loopback :53 the host's resolver, for when the host's nameserver
24# build's DNS to when the host's nameserver is a 24# is a loopback address. That pasta forwards a
25# loopback address. 25# build's DNS there is to be confirmed from inside a
26# build by runbook R3, not assumed.
26# public 22/80/443 the forge, as anyone on the internet reaches it. 27# public 22/80/443 the forge, as anyone on the internet reaches it.
27# Everything else is rejected: the admin sshd on 2222 on every address, 28# Everything else is rejected: the admin sshd on 2222 on every address,
28# and any service bound to loopback. -isolation none builds run as the 29# and any service bound to loopback. -isolation none builds run as the
deploy/gitbay-runner-egress.service +4 −1
@@ -10,6 +10,9 @@
10# Reload re-reads the file and replaces the table in one transaction; it 10# Reload re-reads the file and replaces the table in one transaction; it
11# does not restart the runner, which a restart of this unit would 11# does not restart the runner, which a restart of this unit would
12# (Requires= propagates restarts). `make deploy-runner` reloads. 12# (Requires= propagates restarts). `make deploy-runner` reloads.
13#
14# Stop uses destroy, which succeeds when the table is already gone (a
15# flush ruleset removes it); delete would fail and leave the unit failed.
13[Unit] 16[Unit]
14Description=Host egress rule for CI builds 17Description=Host egress rule for CI builds
15After=nftables.service ufw.service 18After=nftables.service ufw.service
@@ -20,7 +23,7 @@ Type=oneshot
20RemainAfterExit=yes 23RemainAfterExit=yes
21ExecStart=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft 24ExecStart=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft
22ExecReload=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft 25ExecReload=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft
23ExecStop=/usr/sbin/nft delete table inet gitbay_runner 26ExecStop=/usr/sbin/nft destroy table inet gitbay_runner
24 27
25[Install] 28[Install]
26WantedBy=multi-user.target 29WantedBy=multi-user.target
deploy/runner-egress-check.sh +14 −7
@@ -14,17 +14,24 @@ RUNNER_USER="${RUNNER_USER:-ci-runner}"
14public=$(hostname -I | awk '{print $1}') 14public=$(hostname -I | awk '{print $1}')
15 15
16probe() { 16probe() {
17 su -s /bin/bash "$RUNNER_USER" -c "timeout 5 bash -c 'exec 3<>/dev/tcp/$1/$2'" 2>/dev/null 17 su -s /bin/bash "$RUNNER_USER" -c "timeout 5 bash -c 'exec 3<>/dev/tcp/$1/$2'" </dev/null 2>/dev/null
18} 18}
19 19
20nft list table inet gitbay_runner >/dev/null 20nft list table inet gitbay_runner >/dev/null
21 21
22for dest in 127.0.0.1:22 "$public:22"; do 22# The runner polls 127.0.0.1:22. If the rule blocks that, the running
23 if ! probe "${dest%:*}" "${dest##*:}"; then 23# runner is already cut off, so remove the table: CI keeps polling as it
24 echo "$RUNNER_USER cannot reach $dest: the egress rule would stop the runner" >&2 24# did before the deploy, and the exit still stops make before the restart.
25 exit 1 25if ! probe 127.0.0.1 22; then
26 fi 26 nft destroy table inet gitbay_runner
27done 27 echo "$RUNNER_USER cannot reach 127.0.0.1:22 with the egress rule loaded;" >&2
28 echo "removed table inet gitbay_runner so the runner keeps polling. Fix the rule and deploy again." >&2
29 exit 1
30fi
31if ! probe "$public" 22; then
32 echo "$RUNNER_USER cannot reach $public:22: builds would not reach the forge" >&2
33 exit 1
34fi
28for dest in 127.0.0.1:2222 "$public:2222"; do 35for dest in 127.0.0.1:2222 "$public:2222"; do
29 if probe "${dest%:*}" "${dest##*:}"; then 36 if probe "${dest%:*}" "${dest##*:}"; then
30 echo "$RUNNER_USER reaches $dest: the egress rule is not in force" >&2 37 echo "$RUNNER_USER reaches $dest: the egress rule is not in force" >&2