From 939e66bfbbd1810de25aa2a2c1b51e59a6fd6b61 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Tue, 5 May 2026 04:17:52 -0500 Subject: [PATCH] Route runner daemon through nginx CF Access proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit act_runner cannot inject custom HTTP headers, so CF Access blocks its unauthenticated calls to git.neuralplatform.ai. Add a gitea-proxy deployment (nginx:alpine) in the ci namespace that injects the CF Access service-token headers and proxies to https://git.neuralplatform.ai. Both runner secrets now point GITEA_INSTANCE_URL at the in-cluster proxy (http://gitea-proxy.ci.svc.cluster.local:3000). Build containers still clone via SSH through git-ssh-init.sh — unaffected. --- .../legion/k8s/gitea-runner/deployment.yaml | 8 +- .../k8s/gitea-runner/external-secrets.yaml | 8 +- .../legion/k8s/gitea-runner/gitea-proxy.yaml | 132 ++++++++++++++++++ 3 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 servers/legion/k8s/gitea-runner/gitea-proxy.yaml diff --git a/servers/legion/k8s/gitea-runner/deployment.yaml b/servers/legion/k8s/gitea-runner/deployment.yaml index 615ee58..ed9d079 100644 --- a/servers/legion/k8s/gitea-runner/deployment.yaml +++ b/servers/legion/k8s/gitea-runner/deployment.yaml @@ -8,7 +8,7 @@ metadata: labels: app: gitea-runner annotations: - config-version: "2026-05-05-ssh-clone" + config-version: "2026-05-05-gitea-proxy" spec: replicas: 1 selector: @@ -19,7 +19,7 @@ spec: labels: app: gitea-runner annotations: - config-version: "2026-05-05-ssh-clone" + config-version: "2026-05-05-gitea-proxy" spec: securityContext: runAsNonRoot: false @@ -100,7 +100,7 @@ metadata: labels: app: neuron-technologies-runner annotations: - config-version: "2026-05-05-ssh-clone" + config-version: "2026-05-05-gitea-proxy" spec: replicas: 2 selector: @@ -111,7 +111,7 @@ spec: labels: app: neuron-technologies-runner annotations: - config-version: "2026-05-05-ssh-clone" + config-version: "2026-05-05-gitea-proxy" spec: securityContext: runAsNonRoot: false diff --git a/servers/legion/k8s/gitea-runner/external-secrets.yaml b/servers/legion/k8s/gitea-runner/external-secrets.yaml index 553295e..9cc448c 100644 --- a/servers/legion/k8s/gitea-runner/external-secrets.yaml +++ b/servers/legion/k8s/gitea-runner/external-secrets.yaml @@ -13,7 +13,7 @@ metadata: name: gitea-runner-secret namespace: ci annotations: - force-sync: "2026-05-05-ssh-clone" + force-sync: "2026-05-05-gitea-proxy" spec: refreshInterval: 1h secretStoreRef: @@ -24,7 +24,7 @@ spec: creationPolicy: Owner template: data: - GITEA_INSTANCE_URL: "https://git.neuralplatform.ai" + GITEA_INSTANCE_URL: "http://gitea-proxy.ci.svc.cluster.local:3000" GITEA_RUNNER_REGISTRATION_TOKEN: "{{ .runner_token }}" GITEA_SSH_PRIVATE_KEY: "{{ .ci_ssh_private_key }}" data: @@ -44,7 +44,7 @@ metadata: name: neuron-technologies-runner-secret namespace: ci annotations: - force-sync: "2026-05-05-ssh-clone" + force-sync: "2026-05-05-gitea-proxy" spec: refreshInterval: 1h secretStoreRef: @@ -55,7 +55,7 @@ spec: creationPolicy: Owner template: data: - GITEA_INSTANCE_URL: "https://git.neuralplatform.ai" + GITEA_INSTANCE_URL: "http://gitea-proxy.ci.svc.cluster.local:3000" GITEA_RUNNER_REGISTRATION_TOKEN: "{{ .runner_token }}" GITEA_SSH_PRIVATE_KEY: "{{ .ci_ssh_private_key }}" data: diff --git a/servers/legion/k8s/gitea-runner/gitea-proxy.yaml b/servers/legion/k8s/gitea-runner/gitea-proxy.yaml new file mode 100644 index 0000000..00108b9 --- /dev/null +++ b/servers/legion/k8s/gitea-runner/gitea-proxy.yaml @@ -0,0 +1,132 @@ +--- +# gitea-proxy — nginx CF Access header-injecting proxy +# +# act_runner cannot add custom HTTP headers, so it can't send the +# CF-Access-Client-Id / CF-Access-Client-Secret headers that Cloudflare +# Access requires for service-to-service access to git.neuralplatform.ai. +# +# This proxy sits in the ci namespace. Runners use: +# GITEA_INSTANCE_URL: http://gitea-proxy.ci.svc.cluster.local:3000 +# +# nginx:alpine processes *.conf.template files in /etc/nginx/templates/ via +# envsubst at startup — so CF Access credentials come from the Secret as env +# vars and get interpolated into the nginx config before nginx starts. +apiVersion: v1 +kind: ConfigMap +metadata: + name: gitea-proxy-config + namespace: ci +data: + # Placed at /etc/nginx/templates/default.conf.template — nginx:alpine + # runs envsubst on this and writes the result to /etc/nginx/conf.d/default.conf + default.conf.template: | + server { + listen 3000; + + location / { + proxy_pass https://git.neuralplatform.ai; + + # Inject CF Access service-token headers so Cloudflare lets + # the request through without interactive auth. + proxy_set_header CF-Access-Client-Id "${CF_ACCESS_CLIENT_ID}"; + proxy_set_header CF-Access-Client-Secret "${CF_ACCESS_CLIENT_SECRET}"; + + # Preserve Host so Gitea/CF edge routes correctly. + proxy_set_header Host git.neuralplatform.ai; + + # Forward all original request headers (auth tokens, etc). + proxy_pass_request_headers on; + + # Rewrite Location headers in redirects back to the proxy URL. + proxy_redirect https://git.neuralplatform.ai/ + http://gitea-proxy.ci.svc.cluster.local:3000/; + + # Standard proxy headers. + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto http; + + # Allow large request bodies (git push payloads). + client_max_body_size 512m; + } + } +--- +# ExternalSecret — CF Access service token for the proxy +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: gitea-proxy-secret + namespace: ci + annotations: + force-sync: "2026-05-05-initial" +spec: + refreshInterval: 1h + secretStoreRef: + name: vault + kind: ClusterSecretStore + target: + name: gitea-proxy-secret + creationPolicy: Owner + data: + - secretKey: CF_ACCESS_CLIENT_ID + remoteRef: + key: secret/data/gitea-runner-cf-access + property: client_id + - secretKey: CF_ACCESS_CLIENT_SECRET + remoteRef: + key: secret/data/gitea-runner-cf-access + property: client_secret +--- +# Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gitea-proxy + namespace: ci + labels: + app: gitea-proxy +spec: + replicas: 1 + selector: + matchLabels: + app: gitea-proxy + template: + metadata: + labels: + app: gitea-proxy + spec: + containers: + - name: nginx + image: nginx:alpine + ports: + - containerPort: 3000 + volumeMounts: + - name: config-template + mountPath: /etc/nginx/templates + envFrom: + - secretRef: + name: gitea-proxy-secret + resources: + requests: + cpu: 50m + memory: 32Mi + limits: + cpu: 200m + memory: 64Mi + volumes: + - name: config-template + configMap: + name: gitea-proxy-config +--- +# Service — ClusterIP reachable by all runner pods as gitea-proxy.ci:3000 +apiVersion: v1 +kind: Service +metadata: + name: gitea-proxy + namespace: ci +spec: + selector: + app: gitea-proxy + ports: + - port: 3000 + targetPort: 3000