From e86687361f83db9683e060e867ea93e84f06de2e Mon Sep 17 00:00:00 2001 From: James Purcell Date: Tue, 5 May 2026 12:42:13 +0100 Subject: [PATCH 1/3] Add rebased Helm security hardening options --- .gitignore | 3 +- .../examples/google-autopilot-cel/values.yaml | 146 ++++++++++++++++++ braintrust/templates/api-deployment.yaml | 28 +++- .../brainstore-fastreader-deployment.yaml | 15 +- .../brainstore-reader-deployment.yaml | 15 +- .../brainstore-writer-deployment.yaml | 15 +- braintrust/values.yaml | 58 +++++++ 7 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 braintrust/examples/google-autopilot-cel/values.yaml diff --git a/.gitignore b/.gitignore index 62d2ec7..626fc04 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ Chart.lock **/secrets.yml values-local.yaml values-local.yml +values-*.yaml +values-*.yml # Helm output and temporary files *.tmp @@ -31,4 +33,3 @@ test-output/ manifests/ rendered/ debug/ - diff --git a/braintrust/examples/google-autopilot-cel/values.yaml b/braintrust/examples/google-autopilot-cel/values.yaml new file mode 100644 index 0000000..37b579e --- /dev/null +++ b/braintrust/examples/google-autopilot-cel/values.yaml @@ -0,0 +1,146 @@ +# Sample values for GKE Autopilot deployment with CEL policy compliance + +global: + orgName: "" + namespace: "braintrust" + +cloud: "google" + +google: + mode: "autopilot" + autopilotMachineFamily: "c4" + +objectStorage: + google: + brainstoreBucket: "" + apiBucket: "" + +api: + name: "braintrust-api" + annotations: + service: + networking.gke.io/load-balancer-type: "Internal" + replicas: 4 + service: + type: LoadBalancer + port: 8000 + portName: http + serviceAccount: + name: "braintrust-api" + googleServiceAccount: "" + enableGcsAuth: false + resources: + requests: + cpu: "4" + memory: "4Gi" + limits: + cpu: "4" + memory: "8Gi" + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + tmpVolume: + enabled: true + sizeLimit: "1Gi" + extraEnvVars: + - name: AWS_REGION + value: "us-central1" + +brainstore: + serviceAccount: + name: "brainstore" + googleServiceAccount: "" + locksBackend: "objectStorage" + + reader: + name: "brainstore-reader" + replicas: 2 + service: + name: "" + type: ClusterIP + port: 4000 + portName: http + resources: + requests: + cpu: "16" + memory: "32Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "900Gi" + verbose: true + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volume: + size: "1000Gi" + sizeLimit: "900Gi" + extraEnvVars: + + fastreader: + name: "brainstore-fastreader" + replicas: 2 + service: + name: "" + type: ClusterIP + port: 4000 + portName: http + resources: + requests: + cpu: "16" + memory: "32Gi" + limits: + cpu: "16" + memory: "32Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "900Gi" + verbose: true + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volume: + size: "1000Gi" + sizeLimit: "900Gi" + extraEnvVars: + + writer: + name: "brainstore-writer" + replicas: 1 + service: + name: "" + type: ClusterIP + port: 4000 + portName: http + resources: + requests: + cpu: "32" + memory: "64Gi" + limits: + cpu: "32" + memory: "64Gi" + cacheDir: "/mnt/tmp/brainstore" + objectStoreCacheMemoryLimit: "1Gi" + objectStoreCacheFileSize: "900Gi" + verbose: true + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volume: + size: "1000Gi" + sizeLimit: "900Gi" + extraEnvVars: diff --git a/braintrust/templates/api-deployment.yaml b/braintrust/templates/api-deployment.yaml index 87f346c..fbbde8b 100644 --- a/braintrust/templates/api-deployment.yaml +++ b/braintrust/templates/api-deployment.yaml @@ -44,6 +44,10 @@ spec: {{- end }} spec: serviceAccountName: {{ .Values.api.serviceAccount.name }} + {{- with .Values.api.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.api.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -60,6 +64,10 @@ spec: - name: api image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}" imagePullPolicy: {{ .Values.api.image.pullPolicy }} + {{- with .Values.api.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} ports: - containerPort: {{ .Values.api.service.port }} resources: @@ -122,17 +130,32 @@ spec: {{- if .Values.api.extraEnvVars }} {{- toYaml .Values.api.extraEnvVars | nindent 12 }} {{- end }} - {{- if and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver }} + {{- if or .Values.api.tmpVolume.enabled (and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver) }} volumeMounts: + {{- if .Values.api.tmpVolume.enabled }} + - name: tmp-volume + mountPath: /tmp + {{- end }} + {{- if and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver }} - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true + {{- end }} {{- end }} {{- with .Values.api.extraContainers }} {{- toYaml . | nindent 8 }} {{- end }} volumes: - {{- if or (and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver) .Values.api.extraVolumes }} + {{- if or .Values.api.tmpVolume.enabled (and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver) .Values.api.extraVolumes }} + {{- if .Values.api.tmpVolume.enabled }} + - name: tmp-volume + emptyDir: + {{- if .Values.api.tmpVolume.sizeLimit }} + sizeLimit: {{ .Values.api.tmpVolume.sizeLimit | quote }} + {{- else }} + {} + {{- end }} + {{- end }} {{- if and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver }} - name: secrets-store-inline csi: @@ -147,4 +170,3 @@ spec: {{- else }} [] {{- end }} - diff --git a/braintrust/templates/brainstore-fastreader-deployment.yaml b/braintrust/templates/brainstore-fastreader-deployment.yaml index ebb8a7d..5852e2e 100644 --- a/braintrust/templates/brainstore-fastreader-deployment.yaml +++ b/braintrust/templates/brainstore-fastreader-deployment.yaml @@ -44,6 +44,10 @@ spec: {{- end }} spec: serviceAccountName: {{ .Values.brainstore.serviceAccount.name }} + {{- with .Values.brainstore.fastreader.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} {{- if or .Values.brainstore.fastreader.nodeSelector (and (eq .Values.cloud "google") (eq .Values.google.mode "autopilot")) }} nodeSelector: {{- with .Values.brainstore.fastreader.nodeSelector }} @@ -67,6 +71,10 @@ spec: - name: brainstore-fastreader image: "{{ .Values.brainstore.image.repository }}:{{ .Values.brainstore.image.tag }}" imagePullPolicy: {{ .Values.brainstore.image.pullPolicy }} + {{- with .Values.brainstore.fastreader.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} command: ["brainstore"] args: ["web"] ports: @@ -155,7 +163,12 @@ spec: requests: storage: {{ required "brainstore.fastreader.volume.size must be set" .Values.brainstore.fastreader.volume.size | quote }} {{- else }} - emptyDir: {} + emptyDir: + {{- if .Values.brainstore.fastreader.volume.sizeLimit }} + sizeLimit: {{ .Values.brainstore.fastreader.volume.sizeLimit | quote }} + {{- else }} + {} + {{- end }} {{- end }} {{- if and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver }} - name: secrets-store-inline diff --git a/braintrust/templates/brainstore-reader-deployment.yaml b/braintrust/templates/brainstore-reader-deployment.yaml index 8773906..7c8e1f6 100644 --- a/braintrust/templates/brainstore-reader-deployment.yaml +++ b/braintrust/templates/brainstore-reader-deployment.yaml @@ -44,6 +44,10 @@ spec: {{- end }} spec: serviceAccountName: {{ .Values.brainstore.serviceAccount.name }} + {{- with .Values.brainstore.reader.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} {{- if or .Values.brainstore.reader.nodeSelector (and (eq .Values.cloud "google") (eq .Values.google.mode "autopilot")) }} nodeSelector: {{- with .Values.brainstore.reader.nodeSelector }} @@ -67,6 +71,10 @@ spec: - name: brainstore-reader image: "{{ .Values.brainstore.image.repository }}:{{ .Values.brainstore.image.tag }}" imagePullPolicy: {{ .Values.brainstore.image.pullPolicy }} + {{- with .Values.brainstore.reader.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} command: ["brainstore"] args: ["web"] ports: @@ -155,7 +163,12 @@ spec: requests: storage: {{ required "brainstore.reader.volume.size must be set" .Values.brainstore.reader.volume.size | quote }} {{- else }} - emptyDir: {} + emptyDir: + {{- if .Values.brainstore.reader.volume.sizeLimit }} + sizeLimit: {{ .Values.brainstore.reader.volume.sizeLimit | quote }} + {{- else }} + {} + {{- end }} {{- end }} {{- if and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver }} - name: secrets-store-inline diff --git a/braintrust/templates/brainstore-writer-deployment.yaml b/braintrust/templates/brainstore-writer-deployment.yaml index 79b5159..de21635 100644 --- a/braintrust/templates/brainstore-writer-deployment.yaml +++ b/braintrust/templates/brainstore-writer-deployment.yaml @@ -44,6 +44,10 @@ spec: {{- end }} spec: serviceAccountName: {{ .Values.brainstore.serviceAccount.name }} + {{- with .Values.brainstore.writer.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} {{- if or .Values.brainstore.writer.nodeSelector (and (eq .Values.cloud "google") (eq .Values.google.mode "autopilot")) }} nodeSelector: {{- with .Values.brainstore.writer.nodeSelector }} @@ -67,6 +71,10 @@ spec: - name: brainstore-writer image: "{{ .Values.brainstore.image.repository }}:{{ .Values.brainstore.image.tag }}" imagePullPolicy: {{ .Values.brainstore.image.pullPolicy }} + {{- with .Values.brainstore.writer.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} command: ["brainstore"] args: ["web"] ports: @@ -155,7 +163,12 @@ spec: requests: storage: {{ required "brainstore.writer.volume.size must be set" .Values.brainstore.writer.volume.size | quote }} {{- else }} - emptyDir: {} + emptyDir: + {{- if .Values.brainstore.writer.volume.sizeLimit }} + sizeLimit: {{ .Values.brainstore.writer.volume.sizeLimit | quote }} + {{- else }} + {} + {{- end }} {{- end }} {{- if and (eq .Values.cloud "azure") .Values.azure.enableAzureKeyVaultDriver }} - name: secrets-store-inline diff --git a/braintrust/values.yaml b/braintrust/values.yaml index b3a3739..a82f67a 100644 --- a/braintrust/values.yaml +++ b/braintrust/values.yaml @@ -116,6 +116,22 @@ api: limits: cpu: "4" memory: "8Gi" + # Optional: Pod-level security context + # podSecurityContext: + # runAsUser: 1000 + # runAsGroup: 1000 + # fsGroup: 1000 + # Optional: Container-level security context + # securityContext: + # readOnlyRootFilesystem: true + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # Optional: Writable /tmp mount for readOnlyRootFilesystem setups + tmpVolume: + enabled: false + sizeLimit: "" # Allow running user generated code functions (e.g. scorers/tools) allowCodeFunctionExecution: true # Brainstore backfill configuration. These defaults are fine for most cases. @@ -223,6 +239,18 @@ brainstore: limits: cpu: "16" memory: "32Gi" + # Optional: Pod-level security context + # podSecurityContext: + # runAsUser: 1000 + # runAsGroup: 1000 + # fsGroup: 1000 + # Optional: Container-level security context + # securityContext: + # readOnlyRootFilesystem: true + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL cacheDir: "/mnt/tmp/brainstore" objectStoreCacheMemoryLimit: "1Gi" objectStoreCacheFileSize: "1000Gi" @@ -232,6 +260,8 @@ brainstore: volume: # Storage size for ephemeral storage requests (used with GKE Autopilot local SSDs) size: "" + # Optional emptyDir size limit for CEL policy compliance + sizeLimit: "" extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -262,6 +292,18 @@ brainstore: limits: cpu: "16" memory: "32Gi" + # Optional: Pod-level security context + # podSecurityContext: + # runAsUser: 1000 + # runAsGroup: 1000 + # fsGroup: 1000 + # Optional: Container-level security context + # securityContext: + # readOnlyRootFilesystem: true + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL cacheDir: "/mnt/tmp/brainstore" objectStoreCacheMemoryLimit: "1Gi" objectStoreCacheFileSize: "1000Gi" @@ -271,6 +313,8 @@ brainstore: volume: # Storage size for ephemeral storage requests (used with GKE Autopilot local SSDs) size: "" + # Optional emptyDir size limit for CEL policy compliance + sizeLimit: "" extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -301,6 +345,18 @@ brainstore: limits: cpu: "32" memory: "64Gi" + # Optional: Pod-level security context + # podSecurityContext: + # runAsUser: 1000 + # runAsGroup: 1000 + # fsGroup: 1000 + # Optional: Container-level security context + # securityContext: + # readOnlyRootFilesystem: true + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL cacheDir: "/mnt/tmp/brainstore" objectStoreCacheMemoryLimit: "1Gi" objectStoreCacheFileSize: "1000Gi" @@ -311,6 +367,8 @@ brainstore: # Storage size for ephemeral storage requests # Used with GKE Autopilot local SSDs and Azure Container Storage CSI size: "" + # Optional emptyDir size limit for CEL policy compliance + sizeLimit: "" extraEnvVars: [] # Example: # - name: MY_ENV_VAR From c37813d48ac10cf489ed506b88633cd0d4f4447f Mon Sep 17 00:00:00 2001 From: James Purcell Date: Tue, 5 May 2026 14:25:32 +0100 Subject: [PATCH 2/3] update values.yaml --- braintrust/examples/google-autopilot-cel/values.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/braintrust/examples/google-autopilot-cel/values.yaml b/braintrust/examples/google-autopilot-cel/values.yaml index 37b579e..a380cbb 100644 --- a/braintrust/examples/google-autopilot-cel/values.yaml +++ b/braintrust/examples/google-autopilot-cel/values.yaml @@ -17,6 +17,10 @@ objectStorage: api: name: "braintrust-api" + # Uncomment the following section to use a different image or tag from the version in the Helm release + #image: + #repository: public.ecr.aws/braintrust/standalone-api + #tag: "" annotations: service: networking.gke.io/load-balancer-type: "Internal" @@ -53,6 +57,10 @@ brainstore: serviceAccount: name: "brainstore" googleServiceAccount: "" + # Uncomment the following section to use a different image or tag from the version in the Helm release + #image: + #repository: public.ecr.aws/braintrust/brainstore + #tag: "" locksBackend: "objectStorage" reader: From b736b89efb5e3e8f783c9afe68b4b31a5b009484 Mon Sep 17 00:00:00 2001 From: James Purcell Date: Tue, 5 May 2026 14:38:36 +0100 Subject: [PATCH 3/3] Remove commented out code from root values.yaml --- braintrust/values.yaml | 49 ------------------------------------------ 1 file changed, 49 deletions(-) diff --git a/braintrust/values.yaml b/braintrust/values.yaml index a82f67a..5ae0088 100644 --- a/braintrust/values.yaml +++ b/braintrust/values.yaml @@ -116,19 +116,6 @@ api: limits: cpu: "4" memory: "8Gi" - # Optional: Pod-level security context - # podSecurityContext: - # runAsUser: 1000 - # runAsGroup: 1000 - # fsGroup: 1000 - # Optional: Container-level security context - # securityContext: - # readOnlyRootFilesystem: true - # allowPrivilegeEscalation: false - # capabilities: - # drop: - # - ALL - # Optional: Writable /tmp mount for readOnlyRootFilesystem setups tmpVolume: enabled: false sizeLimit: "" @@ -239,18 +226,6 @@ brainstore: limits: cpu: "16" memory: "32Gi" - # Optional: Pod-level security context - # podSecurityContext: - # runAsUser: 1000 - # runAsGroup: 1000 - # fsGroup: 1000 - # Optional: Container-level security context - # securityContext: - # readOnlyRootFilesystem: true - # allowPrivilegeEscalation: false - # capabilities: - # drop: - # - ALL cacheDir: "/mnt/tmp/brainstore" objectStoreCacheMemoryLimit: "1Gi" objectStoreCacheFileSize: "1000Gi" @@ -292,18 +267,6 @@ brainstore: limits: cpu: "16" memory: "32Gi" - # Optional: Pod-level security context - # podSecurityContext: - # runAsUser: 1000 - # runAsGroup: 1000 - # fsGroup: 1000 - # Optional: Container-level security context - # securityContext: - # readOnlyRootFilesystem: true - # allowPrivilegeEscalation: false - # capabilities: - # drop: - # - ALL cacheDir: "/mnt/tmp/brainstore" objectStoreCacheMemoryLimit: "1Gi" objectStoreCacheFileSize: "1000Gi" @@ -345,18 +308,6 @@ brainstore: limits: cpu: "32" memory: "64Gi" - # Optional: Pod-level security context - # podSecurityContext: - # runAsUser: 1000 - # runAsGroup: 1000 - # fsGroup: 1000 - # Optional: Container-level security context - # securityContext: - # readOnlyRootFilesystem: true - # allowPrivilegeEscalation: false - # capabilities: - # drop: - # - ALL cacheDir: "/mnt/tmp/brainstore" objectStoreCacheMemoryLimit: "1Gi" objectStoreCacheFileSize: "1000Gi"