Add ARC self-hosted runners for IUCLabs #579

Merged
benvin merged 6 commits from benvin/iuclabs-arc-runners into main 2026-11-10 23:27:41 +11:00
Member

IUCLabs public repos need self-hosted CI capacity, but anyone can open PRs there, so runners must only execute trusted code and must not reach internal services.

  • deploy the ARC controller chart in arc-system, pulled through artifactapi
  • keep shared runner resources (namespace, manager Role/RoleBinding, VSO secret, hooks) in the iuclabs-runners base
  • package each scale set as a kustomize component (AutoscalingRunnerSet + its HTTPS/Vault egress policy), starting with iuclabs-k8s
  • allow only push/dispatch/schedule/merge_group/release and trusted pull_request jobs via a job-started hook, tested in pre-commit
  • default-deny the namespace and allow DNS

Depends on the github-app secret existing in Vault.

IUCLabs public repos need self-hosted CI capacity, but anyone can open PRs there, so runners must only execute trusted code and must not reach internal services. - deploy the ARC controller chart in arc-system, pulled through artifactapi - keep shared runner resources (namespace, manager Role/RoleBinding, VSO secret, hooks) in the iuclabs-runners base - package each scale set as a kustomize component (AutoscalingRunnerSet + its HTTPS/Vault egress policy), starting with iuclabs-k8s - allow only push/dispatch/schedule/merge_group/release and trusted pull_request jobs via a job-started hook, tested in pre-commit - default-deny the namespace and allow DNS Depends on the github-app secret existing in Vault.
unkin-agent added 1 commit 2026-11-10 22:20:55 +11:00
Add ARC self-hosted runners for IUCLabs
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
5cbbb9ea21
Author
Member
  • apps/base/iuclabs-runners/job-started.sh:71 — denylist lets pull_request_review and pull_request_review_comment through; on a fork PR they run the fork-supplied workflow, and any account (sock puppet) can trigger them; issue_comment/discussion_comment/issues etc. also unchecked → switch to an allowlist (push, pull_request with the fork check, schedule, workflow_dispatch, merge_group, release, ...) with *) refuse as default; if review events are allowed, apply the same fork/association check to .pull_request.
  • apps/base/iuclabs-runners/networkpolicy.yaml:162 — 198.18.200.4:443 plus traefik-internal pods:websecure expose every internal vhost behind traefik-internal (vault, argocd, grafana, mediamark, ...) to untrusted runner code, not just artifactapi → give artifactapi its own LB IP/entrypoint to allow instead, or record explicit acceptance of the residual exposure in the PR body.
  • apps/base/iuclabs-runners/networkpolicy.yaml:154 — except omits 169.254.0.0/16, 100.64.0.0/10 and 127.0.0.0/8, so :443 is open to link-local/CGNAT/loopback → add them.
  • apps/base/iuclabs-runners/job-started.sh:76 — .head.repo.fork == false treats any non-fork head repo as trusted → compare .pull_request.head.repo.full_name with .repository.full_name.
  • nit: ci/test-runner-hooks.sh:518 — no cases for missing/invalid GITHUB_EVENT_PATH, unset GITHUB_EVENT_NAME or comment/review events → add fail-closed cases (want exit 1).
  • nit: apps/base/iuclabs-runners/networkpolicy.yaml:180 — five hardcoded Vault IPs will drift from vault.service.consul → note the source in the comment so a re-sync is possible.
- apps/base/iuclabs-runners/job-started.sh:71 — denylist lets pull_request_review and pull_request_review_comment through; on a fork PR they run the fork-supplied workflow, and any account (sock puppet) can trigger them; issue_comment/discussion_comment/issues etc. also unchecked → switch to an allowlist (push, pull_request with the fork check, schedule, workflow_dispatch, merge_group, release, ...) with `*) refuse` as default; if review events are allowed, apply the same fork/association check to `.pull_request`. - apps/base/iuclabs-runners/networkpolicy.yaml:162 — 198.18.200.4:443 plus traefik-internal pods:websecure expose every internal vhost behind traefik-internal (vault, argocd, grafana, mediamark, ...) to untrusted runner code, not just artifactapi → give artifactapi its own LB IP/entrypoint to allow instead, or record explicit acceptance of the residual exposure in the PR body. - apps/base/iuclabs-runners/networkpolicy.yaml:154 — `except` omits 169.254.0.0/16, 100.64.0.0/10 and 127.0.0.0/8, so :443 is open to link-local/CGNAT/loopback → add them. - apps/base/iuclabs-runners/job-started.sh:76 — `.head.repo.fork == false` treats any non-fork head repo as trusted → compare `.pull_request.head.repo.full_name` with `.repository.full_name`. - nit: ci/test-runner-hooks.sh:518 — no cases for missing/invalid GITHUB_EVENT_PATH, unset GITHUB_EVENT_NAME or comment/review events → add fail-closed cases (want exit 1). - nit: apps/base/iuclabs-runners/networkpolicy.yaml:180 — five hardcoded Vault IPs will drift from vault.service.consul → note the source in the comment so a re-sync is possible.
unkin-agent added 1 commit 2026-11-10 22:24:59 +11:00
Allowlist runner hook events and tighten runner egress
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
c75ed6497f
Author
Member
  • apps/base/iuclabs-runners/networkpolicy.yaml:47 — nit: Vault egress hardcodes five 198.18.x /32s from a one-off dig; a Vault node replacement silently cuts runner Vault access → note how to refresh, or accept as known.
  • ci/test-runner-hooks.sh:23 — nit: no case for OWNER or COLLABORATOR fork PRs, nor a missing author_association (should refuse) → add fixtures for those.
  • ci/test-runner-hooks.sh:12 — nit: hook runs via its #!/bin/sh shebang, which is bash on many dev hosts, so dash-compatibility is untested → invoke it with dash explicitly if available in the pre-commit env.
- apps/base/iuclabs-runners/networkpolicy.yaml:47 — nit: Vault egress hardcodes five 198.18.x /32s from a one-off `dig`; a Vault node replacement silently cuts runner Vault access → note how to refresh, or accept as known. - ci/test-runner-hooks.sh:23 — nit: no case for OWNER or COLLABORATOR fork PRs, nor a missing `author_association` (should refuse) → add fixtures for those. - ci/test-runner-hooks.sh:12 — nit: hook runs via its `#!/bin/sh` shebang, which is bash on many dev hosts, so dash-compatibility is untested → invoke it with `dash` explicitly if available in the pre-commit env.
unkin-agent added 2 commits 2026-11-10 22:49:18 +11:00
Author
Member

No findings.

No findings.
unkin-agent added 1 commit 2026-11-10 23:15:15 +11:00
Pull ARC controller chart through artifactapi
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
26f5564ce0
Author
Member

No findings.

No findings.
unkin-agent added 1 commit 2026-11-10 23:21:03 +11:00
Split iuclabs-k8s scale set into a kustomize component
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
543fed279a
Author
Member

No findings.

No findings.
benvin merged commit fd3446ae8a into main 2026-11-10 23:27:41 +11:00
benvin deleted branch benvin/iuclabs-arc-runners 2026-11-10 23:27:41 +11:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/argocd-apps#579