| @@ -10,14 +10,15 @@ |
| 10 | # deploy/runner-auth-flood-test.sh cmc/runner-scratch # trusted: a push to main |
10 | # deploy/runner-auth-flood-test.sh cmc/runner-scratch # trusted: a push to main |
| 11 | # deploy/runner-auth-flood-test.sh cmc/runner-scratch --untrusted # a merge request from a fork |
11 | # deploy/runner-auth-flood-test.sh cmc/runner-scratch --untrusted # a merge request from a fork |
| 12 | # |
12 | # |
| 13 | # The build's logins use a key registered with --ttl 1s and expired by |
13 | # The build's logins use a git-scoped key registered with --ttl 1s and |
| 14 | # the time the build runs. With registration open an unknown key is |
14 | # expired by the time the build runs. With registration open an |
| 15 | # admitted to run register and never counts against the SSH auth |
15 | # unknown key is admitted to run register and never counts against the |
| 16 | # limiter; an expired key counts (internal/sshd/sshd.go, authenticate). |
16 | # SSH auth limiter; an expired key counts (internal/sshd/sshd.go, authenticate). |
| 17 | # The key is removed from the account when the script exits. |
17 | # The key is removed from the account when the script exits. |
| 18 | # |
18 | # |
| 19 | # The step probes what the build reaches, then makes 12 logins without |
19 | # The step waits a minute, so the operator can find pasta's cgroup |
| 20 | # pause, so the limiter (ssh_auth_rate, 10 a minute per address) locks |
20 | # (Admin page), probes what the build reaches, then makes 12 logins |
| |
21 | # without pause, so the limiter (ssh_auth_rate, 10 a minute per address) locks |
| 21 | # the address those logins come from for most of the next minute. The |
22 | # the address those logins come from for most of the next minute. The |
| 22 | # runner reports the result right after the step; its report retries |
23 | # runner reports the result right after the step; its report retries |
| 23 | # for half a minute. |
24 | # for half a minute. |
| @@ -34,6 +35,14 @@ |
| 34 | # names that address, the build succeeds and the runner keeps polling. |
35 | # names that address, the build succeeds and the runner keeps polling. |
| 35 | # Untrusted: every login is refused by the builds table before it |
36 | # Untrusted: every login is refused by the builds table before it |
| 36 | # reaches sshd, and no auth.* entry comes from the build at all. |
37 | # reaches sshd, and no auth.* entry comes from the build at all. |
| |
38 | # |
| |
39 | # The script also requires lines in the build log, so a missing ssh or |
| |
40 | # bash in the image, or a table that matches nothing, fails rather than |
| |
41 | # passes. Trusted: "logins 12 denied" (every login reached sshd) and |
| |
42 | # 10.0.0.1:80 refused, not timed out. Untrusted: 169.254.1.2:22 and |
| |
43 | # github.com:22 refused and "12 refused". The untrusted lines are the |
| |
44 | # proof that pasta's sockets are in the build's cgroup: the uid table |
| |
45 | # lets ci-runner reach both. |
| 37 | set -eu |
46 | set -eu |
| 38 | |
47 | |
| 39 | repo=${1:-} |
48 | repo=${1:-} |
| @@ -48,13 +57,15 @@ tmp=$(mktemp -d) |
| 48 | fp= |
57 | fp= |
| 49 | cleanup() { |
58 | cleanup() { |
| 50 | if [ -n "$fp" ]; then gitbay keys remove "$fp" >/dev/null || echo "remove key $fp by hand" >&2; fi |
59 | if [ -n "$fp" ]; then gitbay keys remove "$fp" >/dev/null || echo "remove key $fp by hand" >&2; fi |
| |
60 | fp= |
| 51 | rm -rf "$tmp" |
61 | rm -rf "$tmp" |
| 52 | } |
62 | } |
| 53 | trap cleanup EXIT |
63 | trap cleanup EXIT |
| |
64 | trap 'cleanup; exit 130' INT TERM |
| 54 | |
65 | |
| 55 | echo "==> an expired key" |
66 | echo "==> an expired key" |
| 56 | ssh-keygen -q -t ed25519 -N '' -C auth-flood-260 -f "$tmp/key" |
67 | ssh-keygen -q -t ed25519 -N '' -C auth-flood-260 -f "$tmp/key" |
| 57 | gitbay keys add --label auth-flood-260 --ttl 1s <"$tmp/key.pub" >/dev/null |
68 | gitbay keys add --scope git --label auth-flood-260 --ttl 1s <"$tmp/key.pub" >/dev/null |
| 58 | fp=$(ssh-keygen -lf "$tmp/key.pub" | awk '{print $2}') |
69 | fp=$(ssh-keygen -lf "$tmp/key.pub" | awk '{print $2}') |
| 59 | sleep 2 |
70 | sleep 2 |
| 60 | |
71 | |
| @@ -87,6 +98,7 @@ cat >.gitbay/flood.sh <<'EOF' |
| 87 | #!/bin/sh |
98 | #!/bin/sh |
| 88 | # Written by deploy/runner-auth-flood-test.sh (#260). |
99 | # Written by deploy/runner-auth-flood-test.sh (#260). |
| 89 | set -u |
100 | set -u |
| |
101 | sleep 60 |
| 90 | key=/tmp/flood.key |
102 | key=/tmp/flood.key |
| 91 | cp .gitbay/flood.key "$key" |
103 | cp .gitbay/flood.key "$key" |
| 92 | chmod 600 "$key" |
104 | chmod 600 "$key" |
| @@ -104,7 +116,7 @@ probe() { |
| 104 | esac |
116 | esac |
| 105 | } |
117 | } |
| 106 | getent hosts proxy.golang.org >/dev/null && echo "dns ok" || echo "dns failed" |
118 | getent hosts proxy.golang.org >/dev/null && echo "dns ok" || echo "dns failed" |
| 107 | for t in 127.0.0.1:22 127.0.0.1:2222 "$host:22" "$host:80" "$host:443" "$host:2222" \ |
119 | for t in "$host:22" "$host:80" "$host:443" "$host:2222" \ |
| 108 | 10.0.0.1:80 192.168.0.1:80 proxy.golang.org:443 github.com:22; do |
120 | 10.0.0.1:80 192.168.0.1:80 proxy.golang.org:443 github.com:22; do |
| 109 | probe "${t%:*}" "${t##*:}" |
121 | probe "${t%:*}" "${t##*:}" |
| 110 | done |
122 | done |
| @@ -159,7 +171,8 @@ second=$(seen) |
| 159 | echo " $account last seen $first, then $second" |
171 | echo " $account last seen $first, then $second" |
| 160 | |
172 | |
| 161 | echo "==> build log" |
173 | echo "==> build log" |
| 162 | gitbay build log "$repo" "$n" | sed -n '/^dns /,$p' |
174 | log=$(gitbay build log "$repo" "$n") |
| |
175 | printf '%s\n' "$log" | sed -n '/dns /,$p' |
| 163 | |
176 | |
| 164 | echo "==> auth audit, last 15 minutes" |
177 | echo "==> auth audit, last 15 minutes" |
| 165 | gitbay audit --action auth. --since 15m --json | |
178 | gitbay audit --action auth. --since 15m --json | |
| @@ -173,5 +186,16 @@ if gitbay audit --action auth.throttled --since 15m --json | jq -e '.data[] | se |
| 173 | echo "FAIL: 127.0.0.1, the runner's address, was throttled" |
186 | echo "FAIL: 127.0.0.1, the runner's address, was throttled" |
| 174 | fail=1 |
187 | fail=1 |
| 175 | fi |
188 | fi |
| |
189 | need() { |
| |
190 | printf '%s\n' "$log" | grep -Eq "$1" || { echo "FAIL: the build log lacks \"$2\""; fail=1; } |
| |
191 | } |
| |
192 | if [ "$mode" = trusted ]; then |
| |
193 | need 'logins +12 denied' "logins 12 denied" |
| |
194 | need 'refused +10\.0\.0\.1:80( |$)' "refused 10.0.0.1:80" |
| |
195 | else |
| |
196 | need 'refused +169\.254\.1\.2:22( |$)' "refused 169.254.1.2:22" |
| |
197 | need 'refused +github\.com:22( |$)' "refused github.com:22" |
| |
198 | need '12 refused' "12 refused" |
| |
199 | fi |
| 176 | [ $fail = 0 ] && echo "PASS ($mode): the build's failed logins did not lock the runner out" |
200 | [ $fail = 0 ] && echo "PASS ($mode): the build's failed logins did not lock the runner out" |
| 177 | exit $fail |
201 | exit $fail |