From 9f1d0f5627252777fe4fc0cbb45811af1fbee6ec Mon Sep 17 00:00:00 2001 From: Ryan Conway Date: Thu, 12 Nov 2026 18:05:38 +0000 Subject: [PATCH] Add support for passing an existing Secret for deployments that build from templates, or use External Secrets. --- helm/codeapi/README.md | 41 +++++++++++++++++++ helm/codeapi/templates/_helpers.tpl | 7 ++++ helm/codeapi/templates/api-deployment.yaml | 4 +- .../templates/egress-gateway-deployment.yaml | 6 +-- .../templates/file-server-deployment.yaml | 12 +++--- helm/codeapi/templates/secrets.yaml | 4 +- .../tool-call-server-deployment.yaml | 4 +- .../templates/worker-sandbox-deployment.yaml | 17 +++++--- helm/codeapi/values.yaml | 6 +++ 9 files changed, 82 insertions(+), 19 deletions(-) diff --git a/helm/codeapi/README.md b/helm/codeapi/README.md index f63950ae..26d9d4f9 100644 --- a/helm/codeapi/README.md +++ b/helm/codeapi/README.md @@ -47,6 +47,47 @@ to a values file. is publicly known (the same keypair is hardcoded in the unit tests), so never use it outside local development. +## Using an existing Secret + +By default the chart renders a Secret from `internalServiceAuth.token`, +`egressGrant.secret`, `executionManifest.privateKey` and the Redis and MinIO +credentials in values. To keep these secrets out of your values file entirely, +for example when rendering with `helm template`, or when the Secret is written +by External Secrets, set `existingSecret` to the name of a Secret you manage. + +The chart then renders no Secret resource, ignores those values, and reads these +keys from your existing Secret instead: + +| Key | Needed | +|-----|--------| +| `codeapi-internal-service-token` | Always | +| `codeapi-egress-grant-secret` | Always | +| `redis-password` | Always (may be empty if Redis has no password) | +| `codeapi-execution-manifest-private-key` | With `workerSandbox.enabled` | +| `codeapi-execution-manifest-public-key` | With `workerSandbox.enabled`, unless `executionManifest.publicKey` is set | +| `minio-access-key`, `minio-secret-key` | Unless using S3 with `fileServer.s3.useIrsa` | + +For example: + +```bash +kubectl create secret generic codeapi-secrets \ + --from-literal=codeapi-internal-service-token="$(openssl rand -hex 32)" \ + --from-literal=codeapi-egress-grant-secret="$(openssl rand -hex 32)" \ + --from-literal=redis-password="$(openssl rand -hex 32)" \ + --from-literal=codeapi-execution-manifest-private-key="$PRIVATE_KEY" \ + --from-literal=codeapi-execution-manifest-public-key="$PUBLIC_KEY" + +helm install codeapi . \ + --set existingSecret=codeapi-secrets \ + --set redis.auth.existingSecret=codeapi-secrets \ + --set redis.auth.existingSecretPasswordKey=redis-password +``` + +The bundled Redis reads its password separately, so also point `redis.auth` at +the same Secret. Similarly, the bundled MinIO has its own +`minio.auth.existingSecret`, while `minio.useSimple` still takes MinIO's root +credentials from values. + ## Production deployment notes This chart deploys the full service stack on a single cluster and is the diff --git a/helm/codeapi/templates/_helpers.tpl b/helm/codeapi/templates/_helpers.tpl index ce81df7e..6e88ad63 100644 --- a/helm/codeapi/templates/_helpers.tpl +++ b/helm/codeapi/templates/_helpers.tpl @@ -33,6 +33,13 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this. {{- end }} {{- end }} +{{/* +The Secret holding the chart's secret values: existingSecret when set, otherwise the one templates/secrets.yaml renders. +*/}} +{{- define "codeapi.secretName" -}} +{{- .Values.existingSecret | default (printf "%s-secrets" (include "codeapi.fullname" .)) }} +{{- end }} + {{/* Create chart name and version as used by the chart label. */}} diff --git a/helm/codeapi/templates/api-deployment.yaml b/helm/codeapi/templates/api-deployment.yaml index 69985db4..f75c82ab 100644 --- a/helm/codeapi/templates/api-deployment.yaml +++ b/helm/codeapi/templates/api-deployment.yaml @@ -57,7 +57,7 @@ spec: - name: REDIS_PASSWORD valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: redis-password - name: CODEAPI_BRIDGE_PAIRING_ROLLBACK_EPOCH valueFrom: @@ -75,7 +75,7 @@ spec: - name: CODEAPI_INTERNAL_SERVICE_TOKEN valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-internal-service-token - name: EGRESS_GRANT_TTL_SECONDS value: {{ .Values.egressGrant.ttlSeconds | quote }} diff --git a/helm/codeapi/templates/egress-gateway-deployment.yaml b/helm/codeapi/templates/egress-gateway-deployment.yaml index 941844ce..317b1668 100644 --- a/helm/codeapi/templates/egress-gateway-deployment.yaml +++ b/helm/codeapi/templates/egress-gateway-deployment.yaml @@ -67,12 +67,12 @@ spec: - name: CODEAPI_EGRESS_GRANT_SECRET valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-egress-grant-secret - name: CODEAPI_INTERNAL_SERVICE_TOKEN valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-internal-service-token - name: REDIS_HOST value: {{ include "codeapi.redis.host" . }} @@ -81,7 +81,7 @@ spec: - name: REDIS_PASSWORD valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: redis-password livenessProbe: httpGet: diff --git a/helm/codeapi/templates/file-server-deployment.yaml b/helm/codeapi/templates/file-server-deployment.yaml index 1a9e8531..9d74aef6 100644 --- a/helm/codeapi/templates/file-server-deployment.yaml +++ b/helm/codeapi/templates/file-server-deployment.yaml @@ -75,12 +75,12 @@ spec: - name: MINIO_ACCESS_KEY valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: minio-access-key - name: MINIO_SECRET_KEY valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: minio-secret-key {{- end }} {{- else }} @@ -96,12 +96,12 @@ spec: - name: MINIO_ACCESS_KEY valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: minio-access-key - name: MINIO_SECRET_KEY valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: minio-secret-key {{- end }} # Redis connection @@ -112,12 +112,12 @@ spec: - name: REDIS_PASSWORD valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: redis-password - name: CODEAPI_INTERNAL_SERVICE_TOKEN valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-internal-service-token # Server config - name: FILE_SERVER_PORT diff --git a/helm/codeapi/templates/secrets.yaml b/helm/codeapi/templates/secrets.yaml index b23085e0..8a8e03f2 100644 --- a/helm/codeapi/templates/secrets.yaml +++ b/helm/codeapi/templates/secrets.yaml @@ -7,10 +7,11 @@ For production deployments: - Or override values at deploy time: --set redis.auth.password=$REDIS_PASSWORD - Never commit real credentials to version control */}} +{{- if not .Values.existingSecret }} apiVersion: v1 kind: Secret metadata: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} labels: {{- include "codeapi.labels" . | nindent 4 }} type: Opaque @@ -46,3 +47,4 @@ stringData: minio-access-key: "" minio-secret-key: "" {{- end }} +{{- end }} diff --git a/helm/codeapi/templates/tool-call-server-deployment.yaml b/helm/codeapi/templates/tool-call-server-deployment.yaml index b5596c90..ca264fb3 100644 --- a/helm/codeapi/templates/tool-call-server-deployment.yaml +++ b/helm/codeapi/templates/tool-call-server-deployment.yaml @@ -42,12 +42,12 @@ spec: - name: REDIS_PASSWORD valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: redis-password - name: CODEAPI_INTERNAL_SERVICE_TOKEN valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-internal-service-token # Server config - name: TOOL_CALL_SERVER_PORT diff --git a/helm/codeapi/templates/worker-sandbox-deployment.yaml b/helm/codeapi/templates/worker-sandbox-deployment.yaml index 2819d998..9aadc6fd 100644 --- a/helm/codeapi/templates/worker-sandbox-deployment.yaml +++ b/helm/codeapi/templates/worker-sandbox-deployment.yaml @@ -13,10 +13,10 @@ Split runtime deployments: {{- end }} {{- $serviceWorkerServiceAccount := .Values.workerSandbox.serviceAccount.name | default (printf "%s-service-worker" (include "codeapi.fullname" .)) }} {{- $sandboxRunnerServiceAccount := .Values.workerSandbox.sandboxServiceAccount.name | default (printf "%s-sandbox-runner" (include "codeapi.fullname" .)) }} -{{- if not .Values.executionManifest.privateKey }} +{{- if not (or .Values.executionManifest.privateKey .Values.existingSecret) }} {{- fail "workerSandbox.enabled requires executionManifest.privateKey so service-worker can sign sandbox execute manifests. The chart ships no default keypair; generate your own Ed25519 keypair (see helm/codeapi/README.md 'Execution manifest signing keys') and set it via --set or a values file (base64 DER or PEM with escaped newlines). For minikube local dev use -f values-local.yaml" }} {{- end }} -{{- if not .Values.executionManifest.publicKey }} +{{- if not (or .Values.executionManifest.publicKey .Values.existingSecret) }} {{- fail "workerSandbox.enabled requires executionManifest.publicKey so sandbox-runner can verify signed execute manifests without a signing secret. The chart ships no default keypair; derive the public key from your Ed25519 private key (see helm/codeapi/README.md 'Execution manifest signing keys') and set it via --set or a values file (base64 DER or PEM with escaped newlines). For minikube local dev use -f values-local.yaml" }} {{- end }} {{- $packagesSource := .Values.workerSandbox.packages.source | default "image" }} @@ -162,17 +162,17 @@ spec: - name: REDIS_PASSWORD valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: redis-password - name: CODEAPI_INTERNAL_SERVICE_TOKEN valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-internal-service-token - name: CODEAPI_EXECUTION_MANIFEST_PRIVATE_KEY valueFrom: secretKeyRef: - name: {{ include "codeapi.fullname" . }}-secrets + name: {{ include "codeapi.secretName" . }} key: codeapi-execution-manifest-private-key - name: EXECUTION_MANIFEST_TTL_SECONDS value: {{ .Values.executionManifest.ttlSeconds | quote }} @@ -333,7 +333,14 @@ spec: - name: SANDBOX_REQUIRE_EGRESS_MANIFEST value: "true" - name: SANDBOX_EXECUTION_MANIFEST_PUBLIC_KEY + {{- if .Values.executionManifest.publicKey }} value: {{ .Values.executionManifest.publicKey | quote }} + {{- else }} + valueFrom: + secretKeyRef: + name: {{ include "codeapi.secretName" . }} + key: codeapi-execution-manifest-public-key + {{- end }} {{- with .Values.workerSandbox.sandboxExtraEnv }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/helm/codeapi/values.yaml b/helm/codeapi/values.yaml index 33c32af0..dd55a97c 100644 --- a/helm/codeapi/values.yaml +++ b/helm/codeapi/values.yaml @@ -14,6 +14,12 @@ global: # Storage class for persistent volumes storageClass: "" +# Name of an existing Secret to use instead of rendering one from the values +# below, so that no secret values need to be passed to Helm. It must contain the +# keys listed in README.md "Using an existing Secret". The Redis subchart reads +# its password separately, so also set redis.auth.existingSecret to the same name. +existingSecret: "" + # Shared token for internal service-to-service requests between the public API, # file-server, tool-call-server, worker, and sandbox API. Override for every # production install.