From 79d88d52438c0dda23b11309f0f1d69fa8427577 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Mon, 9 Feb 2026 17:16:58 +0100 Subject: [PATCH] fix self-signed cert --- .github/workflows/gha-validate-chart.yaml | 10 +- .../templates/_mode_dind.tpl | 33 +++ .../templates/_mode_empty.tpl | 64 ++++- .../templates/_mode_kubernetes.tpl | 54 ++++ .../templates/autoscalingrunnserset.yaml | 4 +- ...thub_server_tls_runner_injection_test.yaml | 249 ++++++++++++++++++ ..._set_mode_empty_runner_container_test.yaml | 4 +- 7 files changed, 413 insertions(+), 5 deletions(-) create mode 100644 charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_github_server_tls_runner_injection_test.yaml diff --git a/.github/workflows/gha-validate-chart.yaml b/.github/workflows/gha-validate-chart.yaml index 1fe0118f..c6c91905 100644 --- a/.github/workflows/gha-validate-chart.yaml +++ b/.github/workflows/gha-validate-chart.yaml @@ -66,14 +66,22 @@ jobs: echo "EOF" >> $GITHUB_OUTPUT - name: Install helm-unittest - if: contains(steps.list-changed.outputs.changed_charts, 'charts/gha-runner-scale-set-controller-experimental') + if: | + contains(steps.list-changed.outputs.changed_charts, 'charts/gha-runner-scale-set-controller-experimental') || + contains(steps.list-changed.outputs.changed_charts, 'charts/gha-runner-scale-set-experimental') run: | helm plugin install https://github.com/helm-unittest/helm-unittest.git + - name: Run helm-unittest (gha-runner-scale-set-controller-experimental) if: contains(steps.list-changed.outputs.changed_charts, 'charts/gha-runner-scale-set-controller-experimental') run: | helm unittest ./charts/gha-runner-scale-set-controller-experimental/ + - name: Run helm-unittest (gha-runner-scale-set-experimental) + if: contains(steps.list-changed.outputs.changed_charts, 'charts/gha-runner-scale-set-experimental') + run: | + helm unittest ./charts/gha-runner-scale-set-experimental/ + - name: Run chart-testing (lint) run: | ct lint --config charts/.ci/ct-config-gha.yaml diff --git a/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl b/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl index e9cbed5e..e58a134b 100644 --- a/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl +++ b/charts/gha-runner-scale-set-experimental/templates/_mode_dind.tpl @@ -1,4 +1,10 @@ {{- define "runner-mode-dind.runner-container" -}} +{{- $tlsConfig := (default (dict) .Values.githubServerTLS) -}} +{{- $tlsMountPath := (index $tlsConfig "runnerMountPath" | default "") -}} +{{- $tlsCertKey := "" -}} +{{- if $tlsMountPath -}} + {{- $tlsCertKey = required "githubServerTLS.certificateFrom.configMapKeyRef.key is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "key") -}} +{{- end -}} name: runner image: {{ include "runner.image" . | quote }} command: {{ include "runner.command" . }} @@ -9,11 +15,22 @@ env: {{- with .Values.runner.env }} {{- toYaml . | nindent 2 }} {{- end }} + {{- if $tlsMountPath }} + - name: NODE_EXTRA_CA_CERTS + value: {{ printf "%s/%s" (trimSuffix "/" $tlsMountPath) $tlsCertKey | quote }} + - name: RUNNER_UPDATE_CA_CERTS + value: "1" + {{- end }} volumeMounts: - name: work mountPath: /home/runner/_work - name: dind-sock mountPath: {{ include "runner-mode-dind.sock-mount-dir" . | quote }} + {{- if $tlsMountPath }} + - name: github-server-tls-cert + mountPath: {{ $tlsMountPath | quote }} + readOnly: true + {{- end }} {{- end }} {{- define "runner-mode-dind.dind-container" -}} @@ -46,10 +63,26 @@ volumeMounts: {{- end }} {{- define "runner-mode-dind.pod-volumes" -}} +{{- $tlsConfig := (default (dict) .Values.githubServerTLS) -}} +{{- $tlsMountPath := (index $tlsConfig "runnerMountPath" | default "") -}} +{{- $tlsCMName := "" -}} +{{- $tlsCertKey := "" -}} +{{- if $tlsMountPath -}} + {{- $tlsCMName = required "githubServerTLS.certificateFrom.configMapKeyRef.name is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "name") -}} + {{- $tlsCertKey = required "githubServerTLS.certificateFrom.configMapKeyRef.key is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "key") -}} +{{- end -}} - name: work emptyDir: {} - name: dind-sock emptyDir: {} +{{- if $tlsMountPath }} +- name: github-server-tls-cert + configMap: + name: {{ $tlsCMName | quote }} + items: + - key: {{ $tlsCertKey | quote }} + path: {{ $tlsCertKey | quote }} +{{- end }} {{- if .Values.runner.dind.copyExternals }} - name: dind-externals emptyDir: {} diff --git a/charts/gha-runner-scale-set-experimental/templates/_mode_empty.tpl b/charts/gha-runner-scale-set-experimental/templates/_mode_empty.tpl index 823bb61a..b8408b24 100644 --- a/charts/gha-runner-scale-set-experimental/templates/_mode_empty.tpl +++ b/charts/gha-runner-scale-set-experimental/templates/_mode_empty.tpl @@ -6,10 +6,72 @@ Container spec that is expanded for the runner container {{ fail "You must provide a runner container specification in values.runner.container" }} {{- end }} {{- $tlsConfig := (default (dict) .Values.githubServerTLS) -}} +{{- $tlsMountPath := (index $tlsConfig "runnerMountPath" | default "") -}} +{{- $tlsCertKey := "" -}} +{{- if $tlsMountPath -}} + {{- $tlsCertKey = required "githubServerTLS.certificateFrom.configMapKeyRef.key is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "key") -}} +{{- end -}} name: runner image: {{ .Values.runner.container.image | default "ghcr.io/actions/runner:latest" }} command: {{ toJson (default (list "/home/runner/run.sh") .Values.runner.container.command) }} -{{ $extra := omit .Values.runner.container "name" "image" "command" -}} + +{{/* Merge/add TLS env vars without duplicating user-defined ones */}} +{{ $setNodeExtraCaCerts := false }} +{{ $setRunnerUpdateCaCerts := false }} +{{ if $tlsMountPath }} + {{ $setNodeExtraCaCerts = true }} + {{ $setRunnerUpdateCaCerts = true }} + {{ with .Values.runner.container.env }} + {{ range . }} + {{ if and (kindIs "map" .) (eq ((index . "name") | default "") "NODE_EXTRA_CA_CERTS") }} + {{ $setNodeExtraCaCerts = false }} + {{ end }} + {{ if and (kindIs "map" .) (eq ((index . "name") | default "") "RUNNER_UPDATE_CA_CERTS") }} + {{ $setRunnerUpdateCaCerts = false }} + {{ end }} + {{ end }} + {{ end }} +{{ end }} +{{ if or .Values.runner.container.env $setNodeExtraCaCerts $setRunnerUpdateCaCerts }} +env: + {{- with .Values.runner.container.env }} + {{- toYaml . | nindent 2 }} + {{- end }} + {{- if $setNodeExtraCaCerts }} + - name: NODE_EXTRA_CA_CERTS + value: {{ printf "%s/%s" (trimSuffix "/" $tlsMountPath) $tlsCertKey | quote }} + {{- end }} + {{- if $setRunnerUpdateCaCerts }} + - name: RUNNER_UPDATE_CA_CERTS + value: "1" + {{- end }} +{{ end }} + +{{/* Merge/add TLS volumeMount without duplicating user-defined ones */}} +{{ $setTLSVolumeMount := false }} +{{ if $tlsMountPath }} + {{ $setTLSVolumeMount = true }} + {{ with .Values.runner.container.volumeMounts }} + {{ range . }} + {{ if and (kindIs "map" .) (eq ((index . "name") | default "") "github-server-tls-cert") }} + {{ $setTLSVolumeMount = false }} + {{ end }} + {{ end }} + {{ end }} +{{ end }} +{{ if or .Values.runner.container.volumeMounts $setTLSVolumeMount }} +volumeMounts: + {{- with .Values.runner.container.volumeMounts }} + {{- toYaml . | nindent 2 }} + {{- end }} + {{- if $setTLSVolumeMount }} + - name: github-server-tls-cert + mountPath: {{ $tlsMountPath | quote }} + readOnly: true + {{- end }} +{{ end }} + +{{ $extra := omit .Values.runner.container "name" "image" "command" "env" "volumeMounts" -}} {{- if not (empty $extra) -}} {{ toYaml $extra }} {{- end -}} diff --git a/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl b/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl index 6c02a67e..294aee09 100644 --- a/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl +++ b/charts/gha-runner-scale-set-experimental/templates/_mode_kubernetes.tpl @@ -1,6 +1,12 @@ {{- define "runner-mode-kubernetes.runner-container" -}} {{- $runner := (.Values.runner | default dict) -}} {{- $kubeMode := (index $runner "kubernetesMode" | default dict) -}} +{{- $tlsConfig := (default (dict) .Values.githubServerTLS) -}} +{{- $tlsMountPath := (index $tlsConfig "runnerMountPath" | default "") -}} +{{- $tlsCertKey := "" -}} +{{- if $tlsMountPath -}} + {{- $tlsCertKey = required "githubServerTLS.certificateFrom.configMapKeyRef.key is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "key") -}} +{{- end -}} {{- $hookPath := (index $kubeMode "hookPath" | default "/home/runner/k8s/index.js") -}} {{- $extensionRef := (index $kubeMode "extensionRef" | default "") -}} {{- $extension := (index $kubeMode "extension" | default dict) -}} @@ -51,6 +57,24 @@ name: runner image: {{ include "runner.image" . | quote }} command: {{ include "runner.command" . }} + +{{ $setNodeExtraCaCerts := false -}} +{{ $setRunnerUpdateCaCerts := false -}} +{{ $userEnv := (.Values.runner.env | default list) -}} +{{ if $tlsMountPath -}} + {{- $setNodeExtraCaCerts = true -}} + {{- $setRunnerUpdateCaCerts = true -}} + {{- if kindIs "slice" $userEnv -}} + {{- range $userEnv -}} + {{- if and (kindIs "map" .) (eq ((index . "name") | default "") "NODE_EXTRA_CA_CERTS") -}} + {{- $setNodeExtraCaCerts = false -}} + {{- end -}} + {{- if and (kindIs "map" .) (eq ((index . "name") | default "") "RUNNER_UPDATE_CA_CERTS") -}} + {{- $setRunnerUpdateCaCerts = false -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{ end -}} env: - name: ACTIONS_RUNNER_CONTAINER_HOOKS value: {{ $hookPath | quote }} @@ -67,6 +91,14 @@ env: {{- with .Values.runner.env }} {{- toYaml . | nindent 2 }} {{- end }} + {{- if $setNodeExtraCaCerts }} + - name: NODE_EXTRA_CA_CERTS + value: {{ printf "%s/%s" (trimSuffix "/" $tlsMountPath) $tlsCertKey | quote }} + {{- end }} + {{- if $setRunnerUpdateCaCerts }} + - name: RUNNER_UPDATE_CA_CERTS + value: "1" + {{- end }} volumeMounts: - name: work mountPath: /home/runner/_work @@ -76,11 +108,24 @@ volumeMounts: subPath: extension readOnly: true {{- end }} + {{- if $tlsMountPath }} + - name: github-server-tls-cert + mountPath: {{ $tlsMountPath | quote }} + readOnly: true + {{- end }} {{- end }} {{- define "runner-mode-kubernetes.pod-volumes" -}} {{- $runner := (.Values.runner | default dict) -}} {{- $kubeMode := (index $runner "kubernetesMode" | default dict) -}} +{{- $tlsConfig := (default (dict) .Values.githubServerTLS) -}} +{{- $tlsMountPath := (index $tlsConfig "runnerMountPath" | default "") -}} +{{- $tlsConfigMapName := "" -}} +{{- $tlsCertKey := "" -}} +{{- if $tlsMountPath -}} + {{- $tlsConfigMapName = required "githubServerTLS.certificateFrom.configMapKeyRef.name is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "name") -}} + {{- $tlsCertKey = required "githubServerTLS.certificateFrom.configMapKeyRef.key is required when githubServerTLS.runnerMountPath is set" (index $tlsConfig "certificateFrom" "configMapKeyRef" "key") -}} +{{- end -}} {{- $extensionRef := (index $kubeMode "extensionRef" | default "") -}} {{- $extension := (index $kubeMode "extension" | default dict) -}} {{- $extensionYamlRaw := "" -}} @@ -124,6 +169,15 @@ volumeMounts: name: {{ if not (empty $extensionRef) }}{{ $extensionRef | quote }}{{ else }}{{ include "runner-mode-kubernetes.extension-name" . | quote }}{{ end }} {{- end }} +{{- if $tlsMountPath }} +- name: github-server-tls-cert + configMap: + name: {{ $tlsConfigMapName | quote }} + items: + - key: {{ $tlsCertKey | quote }} + path: {{ $tlsCertKey | quote }} +{{- end }} + {{- end }} {{/* diff --git a/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml b/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml index 0418078b..e15ba116 100644 --- a/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml +++ b/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml @@ -50,8 +50,10 @@ {{- if not (kindIs "slice" $extraVolumes) -}} {{- fail ".Values.runner.pod.spec.volumes must be a list of volume specifications" -}} {{- end }} +{{- $tlsConfig := (default (dict) .Values.githubServerTLS) -}} +{{- $tlsMountPath := (index $tlsConfig "runnerMountPath" | default "") -}} {{- $hasInitContainers := or (gt (len $extraInitContainers) 0) (eq $runnerMode "dind") -}} -{{- $hasVolumes := or (gt (len $extraVolumes) 0) (eq $runnerMode "kubernetes") (eq $runnerMode "dind") -}} +{{- $hasVolumes := or (gt (len $extraVolumes) 0) (eq $runnerMode "kubernetes") (eq $runnerMode "dind") (not (empty $tlsMountPath)) -}} apiVersion: actions.github.com/v1alpha1 kind: AutoscalingRunnerSet metadata: diff --git a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_github_server_tls_runner_injection_test.yaml b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_github_server_tls_runner_injection_test.yaml new file mode 100644 index 00000000..60b7b759 --- /dev/null +++ b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_github_server_tls_runner_injection_test.yaml @@ -0,0 +1,249 @@ +suite: "GitHub Server TLS (runner injection)" +templates: + - autoscalingrunnserset.yaml + +tests: + - it: should inject CA env + volumeMount + volume in mode-empty when runnerMountPath is set + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + githubServerTLS: + runnerMountPath: "/usr/local/share/ca-certificates/" + certificateFrom: + configMapKeyRef: + name: "my-ca-config" + key: "ca.crt" + runner: + mode: "" + container: + image: "ghcr.io/actions/actions-runner:latest" + command: ["sh", "-c", "echo hello"] + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_EXTRA_CA_CERTS + value: "/usr/local/share/ca-certificates/ca.crt" + - contains: + path: spec.template.spec.containers[0].env + content: + name: RUNNER_UPDATE_CA_CERTS + value: "1" + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: github-server-tls-cert + mountPath: "/usr/local/share/ca-certificates/" + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: github-server-tls-cert + configMap: + name: "my-ca-config" + items: + - key: "ca.crt" + path: "ca.crt" + + - it: should not override user-provided CA env + volumeMount in mode-empty + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + githubServerTLS: + runnerMountPath: "/usr/local/share/ca-certificates/" + certificateFrom: + configMapKeyRef: + name: "my-ca-config" + key: "ca.crt" + runner: + mode: "" + container: + image: "ghcr.io/actions/actions-runner:latest" + env: + - name: NODE_EXTRA_CA_CERTS + value: "/custom/ca.crt" + - name: RUNNER_UPDATE_CA_CERTS + value: "0" + volumeMounts: + - name: github-server-tls-cert + mountPath: "/custom/mount/" + readOnly: true + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_EXTRA_CA_CERTS + value: "/custom/ca.crt" + - notContains: + path: spec.template.spec.containers[0].env + content: + name: NODE_EXTRA_CA_CERTS + value: "/usr/local/share/ca-certificates/ca.crt" + - contains: + path: spec.template.spec.containers[0].env + content: + name: RUNNER_UPDATE_CA_CERTS + value: "0" + - notContains: + path: spec.template.spec.containers[0].env + content: + name: RUNNER_UPDATE_CA_CERTS + value: "1" + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: github-server-tls-cert + mountPath: "/custom/mount/" + readOnly: true + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: github-server-tls-cert + mountPath: "/usr/local/share/ca-certificates/" + readOnly: true + + - it: should inject CA env + volumeMount + volume in dind mode when runnerMountPath is set + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + githubServerTLS: + runnerMountPath: "/usr/local/share/ca-certificates/" + certificateFrom: + configMapKeyRef: + name: "my-ca-config" + key: "ca.crt" + runner: + mode: "dind" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_EXTRA_CA_CERTS + value: "/usr/local/share/ca-certificates/ca.crt" + - contains: + path: spec.template.spec.containers[0].env + content: + name: RUNNER_UPDATE_CA_CERTS + value: "1" + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: github-server-tls-cert + mountPath: "/usr/local/share/ca-certificates/" + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: github-server-tls-cert + configMap: + name: "my-ca-config" + items: + - key: "ca.crt" + path: "ca.crt" + + - it: should inject CA env + volumeMount + volume in kubernetes mode when runnerMountPath is set + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + githubServerTLS: + runnerMountPath: "/usr/local/share/ca-certificates/" + certificateFrom: + configMapKeyRef: + name: "my-ca-config" + key: "ca.crt" + runner: + mode: "kubernetes" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_EXTRA_CA_CERTS + value: "/usr/local/share/ca-certificates/ca.crt" + - contains: + path: spec.template.spec.containers[0].env + content: + name: RUNNER_UPDATE_CA_CERTS + value: "1" + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: github-server-tls-cert + mountPath: "/usr/local/share/ca-certificates/" + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: github-server-tls-cert + configMap: + name: "my-ca-config" + items: + - key: "ca.crt" + path: "ca.crt" + + - it: should fail when runnerMountPath is set but configMap key is missing + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + githubServerTLS: + runnerMountPath: "/usr/local/share/ca-certificates/" + certificateFrom: + configMapKeyRef: + name: "my-ca-config" + runner: + mode: "dind" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: "githubServerTLS.certificateFrom.configMapKeyRef.key is required when githubServerTLS.runnerMountPath is set" + + - it: should fail when runnerMountPath is set but configMap name is missing + set: + scaleset.name: "test" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + githubServerTLS: + runnerMountPath: "/usr/local/share/ca-certificates/" + certificateFrom: + configMapKeyRef: + key: "ca.crt" + runner: + mode: "" + container: + image: "ghcr.io/actions/actions-runner:latest" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: "githubServerTLS.certificateFrom.configMapKeyRef.name is required when githubServerTLS.runnerMountPath is set" diff --git a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_mode_empty_runner_container_test.yaml b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_mode_empty_runner_container_test.yaml index 84ab1e43..5e2f940f 100644 --- a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_mode_empty_runner_container_test.yaml +++ b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_mode_empty_runner_container_test.yaml @@ -85,7 +85,7 @@ tests: mode: "" container: name: "not-runner" - image: "example.com/custom-runner:1" + image: "ghcr.io/actions/actions-runner:latest" command: ["sh", "-c", "echo hi"] args: ["--foo"] release: @@ -97,7 +97,7 @@ tests: value: runner - equal: path: spec.template.spec.containers[0].image - value: example.com/custom-runner:1 + value: ghcr.io/actions/actions-runner:latest - equal: path: spec.template.spec.containers[0].command[0] value: sh