Allowlist runner hook events and tighten runner egress
This commit is contained in:
@@ -1,23 +1,26 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
event="${GITHUB_EVENT_NAME:-}"
|
||||
|
||||
refuse() {
|
||||
echo "job-started hook: refusing ${GITHUB_EVENT_NAME} job: $1" >&2
|
||||
echo "job-started hook: refusing '${event}' job: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
case "${GITHUB_EVENT_NAME}" in
|
||||
pull_request_target | workflow_run)
|
||||
refuse "event not allowed on self-hosted runners"
|
||||
;;
|
||||
[ -r "${GITHUB_EVENT_PATH:-}" ] || refuse "event payload missing"
|
||||
jq -e 'type == "object"' "${GITHUB_EVENT_PATH}" >/dev/null 2>&1 || refuse "event payload unparseable"
|
||||
|
||||
case "${event}" in
|
||||
push | workflow_dispatch | schedule | merge_group | release) ;;
|
||||
pull_request)
|
||||
same_repo=$(jq -r '.pull_request.head.repo.fork == false' "${GITHUB_EVENT_PATH}")
|
||||
assoc=$(jq -r '.pull_request.author_association // "NONE"' "${GITHUB_EVENT_PATH}")
|
||||
if [ "${same_repo}" != true ]; then
|
||||
case "${assoc}" in
|
||||
OWNER | MEMBER | COLLABORATOR) ;;
|
||||
*) refuse "fork pull request from untrusted author (${assoc})" ;;
|
||||
esac
|
||||
fi
|
||||
trusted=$(jq -r '
|
||||
.pull_request.head.repo.full_name as $head
|
||||
| if $head == null then false
|
||||
elif $head == .repository.full_name then true
|
||||
else (.pull_request.author_association | IN("OWNER", "MEMBER", "COLLABORATOR"))
|
||||
end' "${GITHUB_EVENT_PATH}") || refuse "event payload unreadable"
|
||||
[ "${trusted}" = true ] || refuse "pull request from untrusted fork"
|
||||
;;
|
||||
*) refuse "event not allowed on self-hosted runners" ;;
|
||||
esac
|
||||
|
||||
@@ -30,27 +30,16 @@ spec:
|
||||
- 172.16.0.0/12
|
||||
- 192.168.0.0/16
|
||||
- 198.18.0.0/15
|
||||
- 0.0.0.0/8
|
||||
- 100.64.0.0/10
|
||||
- 127.0.0.0/8
|
||||
- 169.254.0.0/16
|
||||
- 224.0.0.0/4
|
||||
- 240.0.0.0/4
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
# artifactapi.k8s.syd1.au.unkin.net: traefik-internal LB, DNATed to its pods in-cluster
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 198.18.200.4/32
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
- to:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: traefik-system
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/instance: traefik-internal-traefik-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: websecure
|
||||
# vault.service.consul
|
||||
# vault.service.consul servers, from `dig vault.service.consul`
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 198.18.25.78/32
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
not json {
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"comment": {
|
||||
"author_association": "NONE"
|
||||
},
|
||||
"issue": {
|
||||
"number": 1
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"pull_request": {
|
||||
"author_association": "NONE",
|
||||
"author_association": "MEMBER",
|
||||
"head": {
|
||||
"repo": null
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
"author_association": "NONE",
|
||||
"head": {
|
||||
"repo": {
|
||||
"fork": true
|
||||
"fork": true,
|
||||
"full_name": "evil/app"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"pull_request": {
|
||||
"author_association": "NONE",
|
||||
"head": {
|
||||
"repo": {
|
||||
"fork": false,
|
||||
"full_name": "evil/app"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,12 @@
|
||||
"author_association": "MEMBER",
|
||||
"head": {
|
||||
"repo": {
|
||||
"fork": true
|
||||
"fork": true,
|
||||
"full_name": "someone/app"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
"author_association": "CONTRIBUTOR",
|
||||
"head": {
|
||||
"repo": {
|
||||
"fork": false
|
||||
"fork": false,
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "IUCLabs/app"
|
||||
}
|
||||
}
|
||||
|
||||
+18
-4
@@ -7,19 +7,33 @@ fail=0
|
||||
|
||||
check() {
|
||||
local want=$1 event=$2 fixture=$3 got=0
|
||||
GITHUB_EVENT_NAME=$event GITHUB_EVENT_PATH=$fixtures/$fixture "$hook" >/dev/null 2>&1 || got=1
|
||||
local -a env=(-u GITHUB_EVENT_NAME -u GITHUB_EVENT_PATH)
|
||||
[ "$event" = - ] || env+=("GITHUB_EVENT_NAME=$event")
|
||||
[ "$fixture" = - ] || env+=("GITHUB_EVENT_PATH=$fixtures/$fixture")
|
||||
env "${env[@]}" "$hook" >/dev/null 2>&1 || got=1
|
||||
if [ "$got" -ne "$want" ]; then
|
||||
echo "FAIL: $event $fixture exit=$got want=$want" >&2
|
||||
fail=1
|
||||
fi
|
||||
}
|
||||
|
||||
check 0 push push.json
|
||||
for e in push workflow_dispatch schedule merge_group release; do
|
||||
check 0 "$e" push.json
|
||||
done
|
||||
check 0 pull_request pr-member.json
|
||||
check 0 pull_request pr-same-repo.json
|
||||
check 1 pull_request pr-fork-none.json
|
||||
check 1 pull_request pr-fork-spoofed.json
|
||||
check 1 pull_request pr-deleted-fork.json
|
||||
check 1 pull_request_target pr-member.json
|
||||
check 1 workflow_run push.json
|
||||
check 1 pull_request push.json
|
||||
for e in pull_request_target workflow_run pull_request_review pull_request_review_comment issue_comment issues discussion discussion_comment create delete unknown_event; do
|
||||
check 1 "$e" pr-member.json
|
||||
done
|
||||
check 1 pull_request_review pr-fork-none.json
|
||||
check 1 issue_comment issue-comment.json
|
||||
check 1 push -
|
||||
check 1 push missing.json
|
||||
check 1 push invalid.txt
|
||||
check 1 - push.json
|
||||
|
||||
exit "$fail"
|
||||
|
||||
Reference in New Issue
Block a user