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] |
| 14 | Description=Host egress rule for CI builds |
17 | Description=Host egress rule for CI builds |
| 15 | After=nftables.service ufw.service |
18 | After=nftables.service ufw.service |
| @@ -20,7 +23,7 @@ Type=oneshot |
| 20 | RemainAfterExit=yes |
23 | RemainAfterExit=yes |
| 21 | ExecStart=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft |
24 | ExecStart=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft |
| 22 | ExecReload=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft |
25 | ExecReload=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft |
| 23 | ExecStop=/usr/sbin/nft delete table inet gitbay_runner |
26 | ExecStop=/usr/sbin/nft destroy table inet gitbay_runner |
| 24 | |
27 | |
| 25 | [Install] |
28 | [Install] |
| 26 | WantedBy=multi-user.target |
29 | WantedBy=multi-user.target |
deploy/runner-egress-check.sh
+14 −7
| @@ -14,17 +14,24 @@ RUNNER_USER="${RUNNER_USER:-ci-runner}" |
| 14 | public=$(hostname -I | awk '{print $1}') |
14 | public=$(hostname -I | awk '{print $1}') |
| 15 | |
15 | |
| 16 | probe() { |
16 | probe() { |
| 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 | |
| 20 | nft list table inet gitbay_runner >/dev/null |
20 | nft list table inet gitbay_runner >/dev/null |
| 21 | |
21 | |
| 22 | for 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 |
25 | if ! probe 127.0.0.1 22; then |
| 26 | fi |
26 | nft destroy table inet gitbay_runner |
| 27 | done |
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 |
| |
30 | fi |
| |
31 | if ! probe "$public" 22; then |
| |
32 | echo "$RUNNER_USER cannot reach $public:22: builds would not reach the forge" >&2 |
| |
33 | exit 1 |
| |
34 | fi |
| 28 | for dest in 127.0.0.1:2222 "$public:2222"; do |
35 | for 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 |