From d3d26b7beb9fc791a12dc5090faffc11d4c64cf9 Mon Sep 17 00:00:00 2001 From: derbyj Date: Wed, 15 Apr 2026 07:31:07 +0100 Subject: [PATCH 1/2] feat(helm): support extra volumes/mounts Add extraVolumes and extraVolumeMounts to the chart, enabling external file-based credential flows (e.g. CSI-driven mounts) without introducing a new feature toggle. Default chart behaviour is unchanged for existing users. New chart values: - extraVolumes - extraVolumeMounts Wired into all relevant workloads: agent-deploy, agent-daemonset, aggregator-deploy, config-loader-job, webhook-deploy, and backfill-job. Added reusable Helm helpers for rendering the extra volumes and mounts. Strengthened schema validation: - Default mode: exactly one of apiKey or existingSecretName must be set. - External mode: if both are null, extraVolumes and extraVolumeMounts must be non-empty. Added render-time validation guard: in external mode, at least one extraVolumeMount.mountPath must match serverConfig.containerSecretFilePath. This prevents misconfiguration where credentials are mounted but not at the path the app reads. Added Helm unit tests for extra volume/mount behaviour, API key source validation logic, and external mount-path validation. --- helm/README.md | 4 + helm/templates/_helpers.tpl | 44 ++++ helm/templates/agent-daemonset.yaml | 4 +- helm/templates/agent-deploy.yaml | 5 + helm/templates/aggregator-deploy.yaml | 3 + helm/templates/backfill-job.yaml | 11 +- helm/templates/config-loader-job.yaml | 2 + helm/templates/webhook-deploy.yaml | 11 +- .../api_key_mount_path_validation_test.yaml | 35 +++ helm/tests/apikey_secret_validation_test.yaml | 22 +- helm/tests/extra_volumes_test.yaml | 216 ++++++++++++++++++ helm/values.schema.json | 106 ++++++--- helm/values.schema.yaml | 67 ++++-- helm/values.yaml | 4 + 14 files changed, 468 insertions(+), 66 deletions(-) create mode 100644 helm/tests/api_key_mount_path_validation_test.yaml create mode 100644 helm/tests/extra_volumes_test.yaml diff --git a/helm/README.md b/helm/README.md index 40084a97d..4196a98cb 100644 --- a/helm/README.md +++ b/helm/README.md @@ -152,6 +152,8 @@ Below is a summary of these settings and how they are used: | host | string | `"api.cloudzero.com"` | CloudZero host to send metrics to. Override only for non-production or custom environments. | | apiKey | string | `nil` | CloudZero API key used for exporting metrics. Required unless `existingSecretName` is set. | | existingSecretName | string | `nil` | Name of the Secret that contains the CloudZero API key. Required when not providing the API key via `apiKey`. | +| extraVolumeMounts | array | `[]` | Additional Kubernetes `VolumeMount` entries to add to the CloudZero workloads. | +| extraVolumes | array | `[]` | Additional Kubernetes `Volume` entries to add to the CloudZero workloads. | | region | string | `nil` | Cloud provider region (e.g., `us-east-1`, `eastus`). Auto-detected via IMDS; required if IMDS is blocked or you want to override the detected value. | > It is recommended to use a `values-override.yaml` file for customizations. For details, refer to the [official Helm documentation](https://helm.sh/docs/helm/helm_install/#synopsis). @@ -255,6 +257,8 @@ kubectl create secret -n example-namespace generic example-secret-name --from-li The secret can then be used with `existingSecretName`. +For advanced integrations, you can also use `extraVolumes` and `extraVolumeMounts` to attach additional volumes such as CSI-backed secrets to the CloudZero workloads. + ### Update Helm Chart If you are updating an existing installation, pull the latest chart information: diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 799d5238c..569124af0 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -771,10 +771,36 @@ Name for the secret holding TLS certificates {{- .Values.insightsController.tls.secret.name | default (include "cloudzero-agent.internal.resourceName" (dict "context" . "component" "webhook" "subcomponent" "tls")) }} {{- end }} +{{/* +Validate external API key file mode mount path configuration. + +When both apiKey and existingSecretName are unset, the chart expects the API key +to be available from an externally mounted file. In this mode, at least one +extraVolumeMount must target serverConfig.containerSecretFilePath so the runtime +can read credentials from the configured location. +*/}} +{{- define "cloudzero-agent.validateExternalApiKeyMountPath" -}} +{{- if and (not .Values.apiKey) (not .Values.existingSecretName) -}} + {{- $expectedPath := .Values.serverConfig.containerSecretFilePath | default "/etc/config/secrets/" -}} + {{- $expectedPathTrimmed := trimSuffix "/" $expectedPath -}} + {{- $match := dict "found" false -}} + {{- range $mount := .Values.extraVolumeMounts -}} + {{- $mountPath := $mount.mountPath | default "" -}} + {{- if or (eq $mountPath $expectedPath) (eq (trimSuffix "/" $mountPath) $expectedPathTrimmed) -}} + {{- $_ := set $match "found" true -}} + {{- end -}} + {{- end -}} + {{- if not (get $match "found") -}} + {{- fail (printf "External API key mode requires at least one extraVolumeMount.mountPath matching serverConfig.containerSecretFilePath (%s)." $expectedPath) -}} + {{- end -}} +{{- end -}} +{{- end }} + {{/* Volume mount for the API key */}} {{- define "cloudzero-agent.apiKeyVolumeMount" -}} +{{- include "cloudzero-agent.validateExternalApiKeyMountPath" . -}} {{- if or .Values.existingSecretName .Values.apiKey -}} - name: cloudzero-api-key mountPath: {{ .Values.serverConfig.containerSecretFilePath }} @@ -783,6 +809,24 @@ Volume mount for the API key {{- end }} {{- end }} +{{/* +Additional volume mounts for user-provided extensions. +*/}} +{{- define "cloudzero-agent.extraVolumeMounts" -}} +{{- with .Values.extraVolumeMounts -}} +{{ toYaml . }} +{{- end -}} +{{- end }} + +{{/* +Additional volumes for user-provided extensions. +*/}} +{{- define "cloudzero-agent.extraVolumes" -}} +{{- with .Values.extraVolumes -}} +{{ toYaml . }} +{{- end -}} +{{- end }} + {{/* Return the URL for the agent and insights controller to send metrics to. diff --git a/helm/templates/agent-daemonset.yaml b/helm/templates/agent-daemonset.yaml index f47561072..046caba86 100644 --- a/helm/templates/agent-daemonset.yaml +++ b/helm/templates/agent-daemonset.yaml @@ -183,7 +183,8 @@ spec: - name: cloudzero-agent-storage-volume mountPath: /data subPath: "" - {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} {{- include "cloudzero-agent.generatePodSecurityContext" (mergeOverwrite (.Values.defaults.securityContext | default (dict)) (.Values.components.agent.federatedNode.securityContext | default (dict)) @@ -206,6 +207,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.secretName" . }} {{- end }} + {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} - name: cloudzero-agent-storage-volume emptyDir: {{- if .Values.server.emptyDir.sizeLimit }} diff --git a/helm/templates/agent-deploy.yaml b/helm/templates/agent-deploy.yaml index 2f1370835..ec5fe1807 100644 --- a/helm/templates/agent-deploy.yaml +++ b/helm/templates/agent-deploy.yaml @@ -78,6 +78,7 @@ spec: ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: lifecycle-volume mountPath: /checks/bin/ - name: validator-config-volume @@ -102,6 +103,7 @@ spec: ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: lifecycle-volume mountPath: /checks/bin/ - name: validator-config-volume @@ -234,6 +236,7 @@ spec: - name: validator-config-volume mountPath: /checks/app/config/ {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} {{- end }}{{/* End Prometheus container */}} {{- if eq (include "cloudzero-agent.Values.components.agent.mode" .) "clustered" }} # CloudZero Alloy container (binary embedded in agent image) @@ -315,6 +318,7 @@ spec: - name: alloy-tmp mountPath: /tmp {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} {{- end }}{{/* End Alloy container */}} {{- include "cloudzero-agent.generatePodSecurityContext" (mergeOverwrite (.Values.defaults.securityContext | default (dict)) @@ -348,6 +352,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.secretName" . }} {{- end }} + {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} - name: cloudzero-agent-storage-volume {{- if .Values.server.persistentVolume.enabled }} persistentVolumeClaim: diff --git a/helm/templates/aggregator-deploy.yaml b/helm/templates/aggregator-deploy.yaml index 4f5041ed8..3951b77e5 100644 --- a/helm/templates/aggregator-deploy.yaml +++ b/helm/templates/aggregator-deploy.yaml @@ -85,6 +85,7 @@ spec: value: "{{ .Values.aggregator.collector.port }}" volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: aggregator-config-volume mountPath: {{ .Values.aggregator.mountRoot }}/config readOnly: true @@ -131,6 +132,7 @@ spec: value: "{{ .Values.aggregator.shipper.port }}" volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: aggregator-config-volume mountPath: {{ .Values.aggregator.mountRoot }}/config readOnly: true @@ -191,6 +193,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.secretName" . }} {{- end }} + {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} - name: aggregator-config-volume configMap: name: {{ include "cloudzero-agent.aggregator.name" . }} diff --git a/helm/templates/backfill-job.yaml b/helm/templates/backfill-job.yaml index 32ea53c2b..94a988cbf 100644 --- a/helm/templates/backfill-job.yaml +++ b/helm/templates/backfill-job.yaml @@ -166,18 +166,14 @@ spec: volumeMounts: - name: insights-server-config mountPath: {{ include "cloudzero-agent.insightsController.configurationMountPath" $ }} + {{- include "cloudzero-agent.apiKeyVolumeMount" $ | nindent 16 }} + {{- include "cloudzero-agent.extraVolumeMounts" $ | nindent 16 }} {{- if or $.Values.insightsController.volumeMounts $.Values.insightsController.tls.enabled }} - {{- if or $.Values.existingSecretName $.Values.apiKey }} - - name: cloudzero-api-key - mountPath: {{ $.Values.serverConfig.containerSecretFilePath }} - subPath: "" - readOnly: true - {{- end }} {{- with $.Values.insightsController.volumeMounts }} {{- toYaml . | nindent 16 }} {{- end }} {{- end }} - {{- if or $.Values.insightsController.volumes $.Values.insightsController.tls.enabled }} + {{- if or $.Values.insightsController.volumes $.Values.insightsController.tls.enabled (or $.Values.existingSecretName $.Values.apiKey) $.Values.extraVolumes }} volumes: - name: insights-server-config configMap: @@ -192,6 +188,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.secretName" $ }} {{- end }} + {{- include "cloudzero-agent.extraVolumes" $ | nindent 12 }} {{- with $.Values.insightsController.volumes }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/helm/templates/config-loader-job.yaml b/helm/templates/config-loader-job.yaml index 00c0c4c9f..deb80bd00 100644 --- a/helm/templates/config-loader-job.yaml +++ b/helm/templates/config-loader-job.yaml @@ -91,6 +91,7 @@ spec: ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: config-values mountPath: /cloudzero/config/values # values.yaml - name: config-volume @@ -127,6 +128,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.secretName" . }} {{- end }} + {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} {{- with .Values.insightsController.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/helm/templates/webhook-deploy.yaml b/helm/templates/webhook-deploy.yaml index 0afd024be..3aa2ffc7b 100644 --- a/helm/templates/webhook-deploy.yaml +++ b/helm/templates/webhook-deploy.yaml @@ -131,18 +131,14 @@ spec: volumeMounts: - name: insights-server-config mountPath: {{ include "cloudzero-agent.insightsController.configurationMountPath" . }} + {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} + {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} {{- if or .Values.insightsController.volumeMounts .Values.insightsController.tls.enabled }} {{- if .Values.insightsController.tls.enabled }} - name: tls-certs mountPath: {{ .Values.insightsController.tls.mountPath }} readOnly: true {{- end }} - {{- if or .Values.existingSecretName .Values.apiKey }} - - name: cloudzero-api-key - mountPath: {{ .Values.serverConfig.containerSecretFilePath }} - subPath: "" - readOnly: true - {{- end }} {{- with .Values.insightsController.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} @@ -169,7 +165,7 @@ spec: successThreshold: {{ .Values.insightsController.server.healthCheck.successThreshold }} failureThreshold: {{ .Values.insightsController.server.healthCheck.failureThreshold }} {{- end }} - {{- if or .Values.insightsController.volumes .Values.insightsController.tls.enabled }} + {{- if or .Values.insightsController.volumes .Values.insightsController.tls.enabled (or .Values.existingSecretName .Values.apiKey) .Values.extraVolumes }} volumes: - name: insights-server-config configMap: @@ -184,6 +180,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.secretName" . }} {{- end }} + {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} {{- with .Values.insightsController.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/helm/tests/api_key_mount_path_validation_test.yaml b/helm/tests/api_key_mount_path_validation_test.yaml new file mode 100644 index 000000000..9053ab3d6 --- /dev/null +++ b/helm/tests/api_key_mount_path_validation_test.yaml @@ -0,0 +1,35 @@ +suite: test external api key mount path validation +templates: + - templates/aggregator-deploy.yaml +tests: + - it: should fail when external mode is enabled and no extraVolumeMount matches serverConfig.containerSecretFilePath + set: + apiKey: null + existingSecretName: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - failedTemplate: + errorPattern: "containerSecretFilePath" + + - it: should allow external mode when an extraVolumeMount matches serverConfig.containerSecretFilePath + set: + apiKey: null + existingSecretName: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /etc/config/secrets + readOnly: true + asserts: + - isKind: + of: Deployment diff --git a/helm/tests/apikey_secret_validation_test.yaml b/helm/tests/apikey_secret_validation_test.yaml index 7f6eaf962..bea98d9ce 100644 --- a/helm/tests/apikey_secret_validation_test.yaml +++ b/helm/tests/apikey_secret_validation_test.yaml @@ -2,9 +2,9 @@ suite: test apiKey and existingSecretName validation templates: - aggregator-secret.yaml tests: - # Schema validation failure tests - these test the anyOf + oneOf constraints + # Schema validation failure tests - - it: should fail when neither apiKey nor existingSecretName is set + - it: should fail when neither apiKey nor existingSecretName is set and no external volumes are provided values: - ../values.yaml # Use empty base values set: @@ -13,7 +13,23 @@ tests: host: api.cloudzero.com asserts: - failedTemplate: - errorPattern: "anyOf" + errorPattern: "minItems" + + - it: should allow external volume mode when both apiKey and existingSecretName are null + set: + apiKey: null + existingSecretName: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - hasDocuments: + count: 0 - it: should fail when both apiKey and existingSecretName are set set: diff --git a/helm/tests/extra_volumes_test.yaml b/helm/tests/extra_volumes_test.yaml new file mode 100644 index 000000000..872e16a89 --- /dev/null +++ b/helm/tests/extra_volumes_test.yaml @@ -0,0 +1,216 @@ +suite: test extraVolumes and extraVolumeMounts support +templates: + - templates/aggregator-deploy.yaml + - templates/agent-deploy.yaml + - templates/agent-daemonset.yaml + - templates/config-loader-job.yaml + - templates/webhook-deploy.yaml + - templates/backfill-job.yaml +tests: + - it: should add extra volumes and mounts to the aggregator deployment + set: + clusterName: "test-cluster" + cloudAccountId: "123456789" + region: "us-east-1" + existingSecretName: "cloudzero-api-key" + apiKey: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/aggregator-deploy.yaml + + - it: should add extra volumes and mounts to the clustered agent deployment + set: + clusterName: "test-cluster" + cloudAccountId: "123456789" + region: "us-east-1" + existingSecretName: "cloudzero-api-key" + apiKey: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/agent-deploy.yaml + - contains: + path: spec.template.spec.initContainers[0].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/agent-deploy.yaml + - contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/agent-deploy.yaml + + - it: should add extra volumes and mounts to webhook and config-loader jobs + set: + clusterName: "test-cluster" + cloudAccountId: "123456789" + region: "us-east-1" + existingSecretName: "cloudzero-api-key" + apiKey: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/webhook-deploy.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/webhook-deploy.yaml + - contains: + path: spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/config-loader-job.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/config-loader-job.yaml + + - it: should add extra volumes and mounts in federated mode and backfill + set: + clusterName: "test-cluster" + cloudAccountId: "123456789" + region: "us-east-1" + existingSecretName: "cloudzero-api-key" + apiKey: null + configmapReload: + prometheus: + enabled: false + defaults: + federation: + enabled: true + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/agent-daemonset.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + template: templates/agent-daemonset.yaml + + - it: should add extra volumes and mounts to the backfill CronJob + documentIndex: 0 + set: + clusterName: "test-cluster" + cloudAccountId: "123456789" + region: "us-east-1" + existingSecretName: "cloudzero-api-key" + apiKey: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - contains: + path: spec.jobTemplate.spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/backfill-job.yaml + + - it: should add extra volumes and mounts to the backfill one-time Job + documentIndex: 1 + set: + clusterName: "test-cluster" + cloudAccountId: "123456789" + region: "us-east-1" + existingSecretName: "cloudzero-api-key" + apiKey: null + extraVolumes: + - name: custom-extra-volume + configMap: + name: custom-extra-config + extraVolumeMounts: + - name: custom-extra-volume + mountPath: /opt/custom-extra + readOnly: true + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: custom-extra-volume + configMap: + name: custom-extra-config + template: templates/backfill-job.yaml diff --git a/helm/values.schema.json b/helm/values.schema.json index 0f8afc47a..2a43d03f5 100644 --- a/helm/values.schema.json +++ b/helm/values.schema.json @@ -5443,6 +5443,55 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ + { + "if": { + "properties": { + "apiKey": { + "type": "null" + }, + "existingSecretName": { + "type": "null" + } + } + }, + "then": { + "properties": { + "extraVolumes": { + "minItems": 1, + "type": "array" + }, + "extraVolumeMounts": { + "minItems": 1, + "type": "array" + } + } + }, + "else": { + "oneOf": [ + { + "properties": { + "apiKey": { + "pattern": "^[a-zA-Z0-9-_.~!*'();]+$", + "type": "string" + }, + "existingSecretName": { + "type": "null" + } + } + }, + { + "properties": { + "apiKey": { + "type": "null" + }, + "existingSecretName": { + "type": "string" + } + } + } + ] + } + }, { "if": { "allOf": [ @@ -5529,37 +5578,6 @@ } } ], - "anyOf": [ - { - "required": ["apiKey"] - }, - { - "required": ["existingSecretName"] - } - ], - "oneOf": [ - { - "properties": { - "apiKey": { - "pattern": "^[a-zA-Z0-9-_.~!*'();]+$", - "type": "string" - }, - "existingSecretName": { - "type": "null" - } - } - }, - { - "properties": { - "apiKey": { - "type": "null" - }, - "existingSecretName": { - "type": "string" - } - } - } - ], "properties": { "aggregator": { "additionalProperties": false, @@ -5816,6 +5834,32 @@ "apiKey": { "type": ["string", "null"] }, + "extraVolumeMounts": { + "oneOf": [ + { + "items": { + "$ref": "#/$defs/io.k8s.api.core.v1.VolumeMount" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "extraVolumes": { + "oneOf": [ + { + "items": { + "$ref": "#/$defs/io.k8s.api.core.v1.Volume" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, "cloudAccountId": { "pattern": "^$|^[0-9]+$|^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$|^'[0-9]+'$|^'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'$", "type": "string" diff --git a/helm/values.schema.yaml b/helm/values.schema.yaml index 4e1ee8b49..c7942c440 100644 --- a/helm/values.schema.yaml +++ b/helm/values.schema.yaml @@ -302,23 +302,7 @@ additionalProperties: false required: - host -# Enforce that exactly one of apiKey or existingSecretName must be set -# anyOf ensures at least one is required, oneOf ensures only one has a non-null value -anyOf: - - required: [apiKey] - - required: [existingSecretName] -oneOf: - - properties: - apiKey: - type: string - pattern: "^[a-zA-Z0-9-_.~!*'();]+$" - existingSecretName: - type: "null" - - properties: - apiKey: - type: "null" - existingSecretName: - type: string +# Root-level cross-field validations live in allOf below. properties: cloudAccountId: @@ -393,6 +377,22 @@ properties: - "null" description: | The name of an existing Kubernetes secret containing the API key. + extraVolumeMounts: + oneOf: + - type: array + items: + $ref: "#/$defs/io.k8s.api.core.v1.VolumeMount" + - type: "null" + description: | + Additional Kubernetes VolumeMount definitions to add to CloudZero workloads. + extraVolumes: + oneOf: + - type: array + items: + $ref: "#/$defs/io.k8s.api.core.v1.Volume" + - type: "null" + description: | + Additional Kubernetes Volume definitions to add to CloudZero workloads. nameOverride: deprecated: true type: @@ -3065,6 +3065,39 @@ properties: # Root-level conditional validations that span multiple properties allOf: + # Conditional: API key source validation + # + # Default mode: exactly one of apiKey or existingSecretName must be set. + # External volume mode: if both are null, require explicit extraVolumes and + # extraVolumeMounts so this remains intentional and not accidental. + - if: + properties: + apiKey: + type: "null" + existingSecretName: + type: "null" + then: + properties: + extraVolumes: + type: array + minItems: 1 + extraVolumeMounts: + type: array + minItems: 1 + else: + oneOf: + - properties: + apiKey: + type: string + pattern: "^[a-zA-Z0-9-_.~!*'();]+$" + existingSecretName: + type: "null" + - properties: + apiKey: + type: "null" + existingSecretName: + type: string + # Conditional: Federation mode constraint # # If defaults.federation.enabled is true, then components.agent.mode must be diff --git a/helm/values.yaml b/helm/values.yaml index 47e1ad8b7..f1a1a731d 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -39,6 +39,10 @@ region: null apiKey: null # -- If set, the agent will use the API key in this Secret to authenticate with CloudZero. existingSecretName: null +# -- Additional Kubernetes VolumeMount entries to add to the CloudZero workloads. +extraVolumeMounts: [] +# -- Additional Kubernetes Volume entries to add to the CloudZero workloads. +extraVolumes: [] # Agent largely contains top-level settings which are often shared by multiple # components within this chart, or used as defaults in case values are not From e6367dd81d27e7bc857d4cb67468ed30ff0e9d41 Mon Sep 17 00:00:00 2001 From: Evan Nemerson Date: Fri, 15 May 2026 10:32:55 -0400 Subject: [PATCH 2/2] CP-40648: Add CSI secret provider support for API key delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Community PR #772 added generic extraVolumes/extraVolumeMounts to support CSI-driven API key delivery from external vaults. The approach was too broad — it coupled generic volume mounting to credential validation and exposed the API key volume to every workload regardless of need. This replaces that with a single components.apiKey.secretProviderClass property that switches the API key volume source from a Kubernetes Secret to a Secrets Store CSI Driver volume. Functional Requirements: 1. Users must be able to mount the API key via the Secrets Store CSI Driver without creating a Kubernetes Secret object. Added components.apiKey.secretProviderClass. When set (and both top-level apiKey and existingSecretName are null), the chart generates a CSI volume using the secrets-store.csi.k8s.io driver instead of a Kubernetes Secret volume. The mount path (serverConfig.containerSecretFilePath) is unchanged. 2. Existing apiKey and existingSecretName must continue to work and take priority. The top-level properties are not deprecated or relocated. A new cloudzero-agent.apiKey.mode helper resolves the active provisioning mode (inline, secret, csi, or none) and is used by the volume mount, volume definition, and volumes-section guards. 3. The volume definition must not be duplicated across templates. Added a cloudzero-agent.apiKeyVolume helper that generates the correct volume definition (Secret or CSI) based on the resolved mode. This replaced six identical inline volume blocks across agent-deploy, agent-daemonset, aggregator-deploy, webhook-deploy, backfill-job, and config-loader-job templates. 4. The generic extraVolumes/extraVolumeMounts mechanism must be removed. Removed the extraVolumes and extraVolumeMounts values, schema properties, template helpers, and all wiring across the six workload templates. Removed the validateExternalApiKeyMountPath render-time guard since CSI mode no longer depends on extra volume mounts. Validation: - All 565 Helm unit tests pass (schema, template rendering, CSI volume rendering, precedence, and backwards compatibility) - Added helm/tests/apikey_csi_volume_test.yaml covering CSI volume rendering across all workload templates - Updated helm/tests/apikey_secret_validation_test.yaml with secretProviderClass schema validation and precedence tests - Removed helm/tests/api_key_mount_path_validation_test.yaml and helm/tests/extra_volumes_test.yaml (no longer applicable) - Deployed and validated end-to-end on EKS (AWS Secrets Manager) and AKS (Azure Key Vault) using the Secrets Store CSI Driver --- helm/README.md | 20 +- helm/templates/_helpers.tpl | 79 +++---- helm/templates/agent-daemonset.yaml | 8 +- helm/templates/agent-deploy.yaml | 15 +- helm/templates/aggregator-deploy.yaml | 9 +- helm/templates/backfill-job.yaml | 10 +- helm/templates/config-loader-job.yaml | 8 +- helm/templates/webhook-deploy.yaml | 10 +- .../api_key_mount_path_validation_test.yaml | 35 --- helm/tests/apikey_csi_volume_test.yaml | 169 ++++++++++++++ helm/tests/apikey_secret_reference_test.yaml | 5 +- helm/tests/apikey_secret_validation_test.yaml | 70 ++++-- helm/tests/extra_volumes_test.yaml | 216 ------------------ helm/values.schema.json | 84 +++---- helm/values.schema.yaml | 53 +++-- helm/values.yaml | 11 +- tests/helm/template/alloy.yaml | 8 +- tests/helm/template/cert-manager.yaml | 8 +- tests/helm/template/federated.yaml | 8 +- tests/helm/template/istio.yaml | 8 +- tests/helm/template/kubestate.yaml | 8 +- tests/helm/template/manifest.yaml | 8 +- 22 files changed, 382 insertions(+), 468 deletions(-) delete mode 100644 helm/tests/api_key_mount_path_validation_test.yaml create mode 100644 helm/tests/apikey_csi_volume_test.yaml delete mode 100644 helm/tests/extra_volumes_test.yaml diff --git a/helm/README.md b/helm/README.md index 4196a98cb..9247f90aa 100644 --- a/helm/README.md +++ b/helm/README.md @@ -150,10 +150,8 @@ Below is a summary of these settings and how they are used: | cloudAccountId | string | `nil` | Account ID in AWS, subscription ID in Azure, or project number in GCP. Auto-detected via IMDS when available; required if IMDS is blocked. | | clusterName | string | `nil` | Name of the cluster (RFC 1123). Mandatory on EKS and AKS; auto-detected on GKE; required on any provider if IMDS is blocked. | | host | string | `"api.cloudzero.com"` | CloudZero host to send metrics to. Override only for non-production or custom environments. | -| apiKey | string | `nil` | CloudZero API key used for exporting metrics. Required unless `existingSecretName` is set. | +| apiKey | string | `nil` | CloudZero API key used for exporting metrics. Required unless `existingSecretName` or `components.apiKey` is configured. | | existingSecretName | string | `nil` | Name of the Secret that contains the CloudZero API key. Required when not providing the API key via `apiKey`. | -| extraVolumeMounts | array | `[]` | Additional Kubernetes `VolumeMount` entries to add to the CloudZero workloads. | -| extraVolumes | array | `[]` | Additional Kubernetes `Volume` entries to add to the CloudZero workloads. | | region | string | `nil` | Cloud provider region (e.g., `us-east-1`, `eastus`). Auto-detected via IMDS; required if IMDS is blocked or you want to override the detected value. | > It is recommended to use a `values-override.yaml` file for customizations. For details, refer to the [official Helm documentation](https://helm.sh/docs/helm/helm_install/#synopsis). @@ -257,7 +255,21 @@ kubectl create secret -n example-namespace generic example-secret-name --from-li The secret can then be used with `existingSecretName`. -For advanced integrations, you can also use `extraVolumes` and `extraVolumeMounts` to attach additional volumes such as CSI-backed secrets to the CloudZero workloads. +#### CSI-based Secret Delivery + +For environments using the [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/), you can mount the API key directly from an external vault (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, etc.) without creating a Kubernetes Secret object. + +1. Install the Secrets Store CSI Driver and the appropriate cloud provider plugin on your cluster. +2. Create a `SecretProviderClass` in the same namespace as the CloudZero Agent that fetches your API key and produces a file matching `serverConfig.containerSecretFileName` (default: `value`). +3. Reference it in your values: + +```yaml +components: + apiKey: + secretProviderClass: "your-secret-provider-class-name" +``` + +When `components.apiKey.secretProviderClass` is set and both `apiKey` and `existingSecretName` are null, the chart mounts the API key via the CSI driver. The top-level `apiKey` and `existingSecretName` properties take priority when set. ### Update Helm Chart diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 569124af0..f5facc538 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -53,6 +53,23 @@ Returns: string (e.g., "my-release-api-key" or custom existing secret name) {{ .Values.existingSecretName | default (printf "%s-api-key" .Release.Name) }} {{- end}} +{{/* +Determine the API key provisioning mode. + +Returns one of: "inline", "secret", "csi", "none" +*/}} +{{- define "cloudzero-agent.apiKey.mode" -}} +{{- if .Values.apiKey -}} + {{- print "inline" -}} +{{- else if .Values.existingSecretName -}} + {{- print "secret" -}} +{{- else if and .Values.components .Values.components.apiKey .Values.components.apiKey.secretProviderClass -}} + {{- print "csi" -}} +{{- else -}} + {{- print "none" -}} +{{- end -}} +{{- end -}} + {{/* Define the path and filename on the container filesystem which holds the CloudZero API key. @@ -772,36 +789,12 @@ Name for the secret holding TLS certificates {{- end }} {{/* -Validate external API key file mode mount path configuration. - -When both apiKey and existingSecretName are unset, the chart expects the API key -to be available from an externally mounted file. In this mode, at least one -extraVolumeMount must target serverConfig.containerSecretFilePath so the runtime -can read credentials from the configured location. -*/}} -{{- define "cloudzero-agent.validateExternalApiKeyMountPath" -}} -{{- if and (not .Values.apiKey) (not .Values.existingSecretName) -}} - {{- $expectedPath := .Values.serverConfig.containerSecretFilePath | default "/etc/config/secrets/" -}} - {{- $expectedPathTrimmed := trimSuffix "/" $expectedPath -}} - {{- $match := dict "found" false -}} - {{- range $mount := .Values.extraVolumeMounts -}} - {{- $mountPath := $mount.mountPath | default "" -}} - {{- if or (eq $mountPath $expectedPath) (eq (trimSuffix "/" $mountPath) $expectedPathTrimmed) -}} - {{- $_ := set $match "found" true -}} - {{- end -}} - {{- end -}} - {{- if not (get $match "found") -}} - {{- fail (printf "External API key mode requires at least one extraVolumeMount.mountPath matching serverConfig.containerSecretFilePath (%s)." $expectedPath) -}} - {{- end -}} -{{- end -}} -{{- end }} - -{{/* -Volume mount for the API key +Volume mount for the API key. +Renders for inline, secret, and csi modes. No output for "none". */}} {{- define "cloudzero-agent.apiKeyVolumeMount" -}} -{{- include "cloudzero-agent.validateExternalApiKeyMountPath" . -}} -{{- if or .Values.existingSecretName .Values.apiKey -}} +{{- $mode := include "cloudzero-agent.apiKey.mode" . -}} +{{- if ne $mode "none" -}} - name: cloudzero-api-key mountPath: {{ .Values.serverConfig.containerSecretFilePath }} subPath: "" @@ -810,21 +803,25 @@ Volume mount for the API key {{- end }} {{/* -Additional volume mounts for user-provided extensions. +Volume definition for the API key. +- inline/secret: Kubernetes Secret volume +- csi: Secrets Store CSI Driver volume +- none: no output */}} -{{- define "cloudzero-agent.extraVolumeMounts" -}} -{{- with .Values.extraVolumeMounts -}} -{{ toYaml . }} -{{- end -}} +{{- define "cloudzero-agent.apiKeyVolume" -}} +{{- $mode := include "cloudzero-agent.apiKey.mode" . -}} +{{- if or (eq $mode "inline") (eq $mode "secret") -}} +- name: cloudzero-api-key + secret: + secretName: {{ include "cloudzero-agent.secretName" . }} +{{- else if eq $mode "csi" -}} +- name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: {{ .Values.components.apiKey.secretProviderClass }} {{- end }} - -{{/* -Additional volumes for user-provided extensions. -*/}} -{{- define "cloudzero-agent.extraVolumes" -}} -{{- with .Values.extraVolumes -}} -{{ toYaml . }} -{{- end -}} {{- end }} {{/* diff --git a/helm/templates/agent-daemonset.yaml b/helm/templates/agent-daemonset.yaml index 046caba86..c40a438b9 100644 --- a/helm/templates/agent-daemonset.yaml +++ b/helm/templates/agent-daemonset.yaml @@ -184,7 +184,6 @@ spec: mountPath: /data subPath: "" {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} {{- include "cloudzero-agent.generatePodSecurityContext" (mergeOverwrite (.Values.defaults.securityContext | default (dict)) (.Values.components.agent.federatedNode.securityContext | default (dict)) @@ -202,12 +201,7 @@ spec: name: {{ .Release.Name }}-daemonset-cm - name: processed-config-volume emptyDir: {} - {{- if or .Values.existingSecretName .Values.apiKey }} - - name: cloudzero-api-key - secret: - secretName: {{ include "cloudzero-agent.secretName" . }} - {{- end }} - {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} + {{- include "cloudzero-agent.apiKeyVolume" . | nindent 8 }} - name: cloudzero-agent-storage-volume emptyDir: {{- if .Values.server.emptyDir.sizeLimit }} diff --git a/helm/templates/agent-deploy.yaml b/helm/templates/agent-deploy.yaml index ec5fe1807..35dde2782 100644 --- a/helm/templates/agent-deploy.yaml +++ b/helm/templates/agent-deploy.yaml @@ -78,7 +78,6 @@ spec: ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: lifecycle-volume mountPath: /checks/bin/ - name: validator-config-volume @@ -103,7 +102,6 @@ spec: ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: lifecycle-volume mountPath: /checks/bin/ - name: validator-config-volume @@ -236,8 +234,7 @@ spec: - name: validator-config-volume mountPath: /checks/app/config/ {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - {{- end }}{{/* End Prometheus container */}} + {{- end }}{{/* End Prometheus container */}} {{- if eq (include "cloudzero-agent.Values.components.agent.mode" .) "clustered" }} # CloudZero Alloy container (binary embedded in agent image) - name: {{ template "cloudzero-agent.name" . }}-alloy @@ -318,8 +315,7 @@ spec: - name: alloy-tmp mountPath: /tmp {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - {{- end }}{{/* End Alloy container */}} + {{- end }}{{/* End Alloy container */}} {{- include "cloudzero-agent.generatePodSecurityContext" (mergeOverwrite (.Values.defaults.securityContext | default (dict)) (.Values.components.agent.securityContext | default (dict)) @@ -347,12 +343,7 @@ spec: - name: alloy-tmp emptyDir: {} {{- end }} - {{- if or .Values.existingSecretName .Values.apiKey }} - - name: cloudzero-api-key - secret: - secretName: {{ include "cloudzero-agent.secretName" . }} - {{- end }} - {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} + {{- include "cloudzero-agent.apiKeyVolume" . | nindent 8 }} - name: cloudzero-agent-storage-volume {{- if .Values.server.persistentVolume.enabled }} persistentVolumeClaim: diff --git a/helm/templates/aggregator-deploy.yaml b/helm/templates/aggregator-deploy.yaml index 3951b77e5..38d8a8cac 100644 --- a/helm/templates/aggregator-deploy.yaml +++ b/helm/templates/aggregator-deploy.yaml @@ -85,7 +85,6 @@ spec: value: "{{ .Values.aggregator.collector.port }}" volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: aggregator-config-volume mountPath: {{ .Values.aggregator.mountRoot }}/config readOnly: true @@ -132,7 +131,6 @@ spec: value: "{{ .Values.aggregator.shipper.port }}" volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: aggregator-config-volume mountPath: {{ .Values.aggregator.mountRoot }}/config readOnly: true @@ -188,12 +186,7 @@ spec: name: {{ template "cloudzero-agent.validatorConfigMapName" . }} - name: lifecycle-volume emptyDir: {} - {{- if or .Values.existingSecretName .Values.apiKey }} - - name: cloudzero-api-key - secret: - secretName: {{ include "cloudzero-agent.secretName" . }} - {{- end }} - {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} + {{- include "cloudzero-agent.apiKeyVolume" . | nindent 8 }} - name: aggregator-config-volume configMap: name: {{ include "cloudzero-agent.aggregator.name" . }} diff --git a/helm/templates/backfill-job.yaml b/helm/templates/backfill-job.yaml index 94a988cbf..e6bfa08ab 100644 --- a/helm/templates/backfill-job.yaml +++ b/helm/templates/backfill-job.yaml @@ -167,13 +167,12 @@ spec: - name: insights-server-config mountPath: {{ include "cloudzero-agent.insightsController.configurationMountPath" $ }} {{- include "cloudzero-agent.apiKeyVolumeMount" $ | nindent 16 }} - {{- include "cloudzero-agent.extraVolumeMounts" $ | nindent 16 }} {{- if or $.Values.insightsController.volumeMounts $.Values.insightsController.tls.enabled }} {{- with $.Values.insightsController.volumeMounts }} {{- toYaml . | nindent 16 }} {{- end }} {{- end }} - {{- if or $.Values.insightsController.volumes $.Values.insightsController.tls.enabled (or $.Values.existingSecretName $.Values.apiKey) $.Values.extraVolumes }} + {{- if or $.Values.insightsController.volumes $.Values.insightsController.tls.enabled (ne (include "cloudzero-agent.apiKey.mode" $) "none") }} volumes: - name: insights-server-config configMap: @@ -183,12 +182,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.tlsSecretName" $ }} {{- end }} - {{- if or $.Values.existingSecretName $.Values.apiKey }} - - name: cloudzero-api-key - secret: - secretName: {{ include "cloudzero-agent.secretName" $ }} - {{- end }} - {{- include "cloudzero-agent.extraVolumes" $ | nindent 12 }} + {{- include "cloudzero-agent.apiKeyVolume" $ | nindent 12 }} {{- with $.Values.insightsController.volumes }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/helm/templates/config-loader-job.yaml b/helm/templates/config-loader-job.yaml index deb80bd00..294ae9057 100644 --- a/helm/templates/config-loader-job.yaml +++ b/helm/templates/config-loader-job.yaml @@ -91,7 +91,6 @@ spec: ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} - name: config-values mountPath: /cloudzero/config/values # values.yaml - name: config-volume @@ -123,12 +122,7 @@ spec: - name: config-aggregator configMap: name: {{ include "cloudzero-agent.aggregator.name" . }} - {{- if or .Values.existingSecretName .Values.apiKey }} - - name: cloudzero-api-key - secret: - secretName: {{ include "cloudzero-agent.secretName" . }} - {{- end }} - {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} + {{- include "cloudzero-agent.apiKeyVolume" . | nindent 8 }} {{- with .Values.insightsController.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/helm/templates/webhook-deploy.yaml b/helm/templates/webhook-deploy.yaml index 3aa2ffc7b..5b2cc8816 100644 --- a/helm/templates/webhook-deploy.yaml +++ b/helm/templates/webhook-deploy.yaml @@ -132,7 +132,6 @@ spec: - name: insights-server-config mountPath: {{ include "cloudzero-agent.insightsController.configurationMountPath" . }} {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - {{- include "cloudzero-agent.extraVolumeMounts" . | nindent 12 }} {{- if or .Values.insightsController.volumeMounts .Values.insightsController.tls.enabled }} {{- if .Values.insightsController.tls.enabled }} - name: tls-certs @@ -165,7 +164,7 @@ spec: successThreshold: {{ .Values.insightsController.server.healthCheck.successThreshold }} failureThreshold: {{ .Values.insightsController.server.healthCheck.failureThreshold }} {{- end }} - {{- if or .Values.insightsController.volumes .Values.insightsController.tls.enabled (or .Values.existingSecretName .Values.apiKey) .Values.extraVolumes }} + {{- if or .Values.insightsController.volumes .Values.insightsController.tls.enabled (ne (include "cloudzero-agent.apiKey.mode" .) "none") }} volumes: - name: insights-server-config configMap: @@ -175,12 +174,7 @@ spec: secret: secretName: {{ include "cloudzero-agent.tlsSecretName" . }} {{- end }} - {{- if or .Values.existingSecretName .Values.apiKey }} - - name: cloudzero-api-key - secret: - secretName: {{ include "cloudzero-agent.secretName" . }} - {{- end }} - {{- include "cloudzero-agent.extraVolumes" . | nindent 8 }} + {{- include "cloudzero-agent.apiKeyVolume" . | nindent 8 }} {{- with .Values.insightsController.volumes }} {{- toYaml . | nindent 8 }} {{- end }} diff --git a/helm/tests/api_key_mount_path_validation_test.yaml b/helm/tests/api_key_mount_path_validation_test.yaml deleted file mode 100644 index 9053ab3d6..000000000 --- a/helm/tests/api_key_mount_path_validation_test.yaml +++ /dev/null @@ -1,35 +0,0 @@ -suite: test external api key mount path validation -templates: - - templates/aggregator-deploy.yaml -tests: - - it: should fail when external mode is enabled and no extraVolumeMount matches serverConfig.containerSecretFilePath - set: - apiKey: null - existingSecretName: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - failedTemplate: - errorPattern: "containerSecretFilePath" - - - it: should allow external mode when an extraVolumeMount matches serverConfig.containerSecretFilePath - set: - apiKey: null - existingSecretName: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /etc/config/secrets - readOnly: true - asserts: - - isKind: - of: Deployment diff --git a/helm/tests/apikey_csi_volume_test.yaml b/helm/tests/apikey_csi_volume_test.yaml new file mode 100644 index 000000000..dd8025872 --- /dev/null +++ b/helm/tests/apikey_csi_volume_test.yaml @@ -0,0 +1,169 @@ +suite: test CSI volume rendering for secretProviderClass +templates: + - templates/aggregator-deploy.yaml + - templates/agent-deploy.yaml + - templates/agent-daemonset.yaml + - templates/config-loader-job.yaml + - templates/webhook-deploy.yaml + - templates/backfill-job.yaml +tests: + - it: should render CSI volume in aggregator when secretProviderClass is set + set: + apiKey: null + existingSecretName: null + components: + apiKey: + secretProviderClass: "my-secret-provider" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: my-secret-provider + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: cloudzero-api-key + mountPath: /etc/config/secrets/ + subPath: "" + readOnly: true + template: templates/aggregator-deploy.yaml + + - it: should render CSI volume in agent deployment when secretProviderClass is set + set: + apiKey: null + existingSecretName: null + components: + apiKey: + secretProviderClass: "my-secret-provider" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: my-secret-provider + template: templates/agent-deploy.yaml + + - it: should render CSI volume in webhook deployment when secretProviderClass is set + set: + apiKey: null + existingSecretName: null + components: + apiKey: + secretProviderClass: "my-secret-provider" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: my-secret-provider + template: templates/webhook-deploy.yaml + + - it: should render CSI volume in config-loader job when secretProviderClass is set + set: + apiKey: null + existingSecretName: null + components: + apiKey: + secretProviderClass: "my-secret-provider" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: my-secret-provider + template: templates/config-loader-job.yaml + + - it: should render secret volume (not CSI) when top-level apiKey is set + set: + apiKey: "test-key-123" + existingSecretName: null + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + secret: + secretName: RELEASE-NAME-api-key + template: templates/aggregator-deploy.yaml + - notContains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: my-secret-provider + template: templates/aggregator-deploy.yaml + + - it: should render secret volume when top-level existingSecretName is set + set: + apiKey: null + existingSecretName: "my-custom-secret" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + secret: + secretName: my-custom-secret + template: templates/aggregator-deploy.yaml + + - it: should use top-level apiKey over components.apiKey.secretProviderClass + set: + apiKey: "top-level-key" + existingSecretName: null + components: + apiKey: + secretProviderClass: "should-be-ignored" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + secret: + secretName: RELEASE-NAME-api-key + template: templates/aggregator-deploy.yaml + + - it: should render CSI volume in daemonset when secretProviderClass is set in federated mode + set: + apiKey: null + existingSecretName: null + configmapReload: + prometheus: + enabled: false + defaults: + federation: + enabled: true + components: + apiKey: + secretProviderClass: "my-secret-provider" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: cloudzero-api-key + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: my-secret-provider + template: templates/agent-daemonset.yaml diff --git a/helm/tests/apikey_secret_reference_test.yaml b/helm/tests/apikey_secret_reference_test.yaml index 5f66ff334..acf938ad8 100644 --- a/helm/tests/apikey_secret_reference_test.yaml +++ b/helm/tests/apikey_secret_reference_test.yaml @@ -2,8 +2,6 @@ suite: test apiKey secret name references in manifests templates: - aggregator-deploy.yaml tests: - # Test that existingSecretName is correctly referenced in volume definitions - - it: should reference custom existingSecretName in aggregator deployment volume template: aggregator-deploy.yaml set: @@ -17,8 +15,6 @@ tests: secret: secretName: my-custom-secret - # Test that default generated secret name is used when only apiKey is set - - it: should reference default secret name in aggregator deployment when apiKey is set template: aggregator-deploy.yaml set: @@ -31,3 +27,4 @@ tests: name: cloudzero-api-key secret: secretName: RELEASE-NAME-api-key + diff --git a/helm/tests/apikey_secret_validation_test.yaml b/helm/tests/apikey_secret_validation_test.yaml index bea98d9ce..bbaffa8a9 100644 --- a/helm/tests/apikey_secret_validation_test.yaml +++ b/helm/tests/apikey_secret_validation_test.yaml @@ -2,34 +2,18 @@ suite: test apiKey and existingSecretName validation templates: - aggregator-secret.yaml tests: - # Schema validation failure tests + # ===== Schema validation: top-level (legacy) ===== - - it: should fail when neither apiKey nor existingSecretName is set and no external volumes are provided + - it: should fail when no API key source is configured anywhere values: - - ../values.yaml # Use empty base values + - ../values.yaml set: apiKey: null existingSecretName: null host: api.cloudzero.com asserts: - failedTemplate: - errorPattern: "minItems" - - - it: should allow external volume mode when both apiKey and existingSecretName are null - set: - apiKey: null - existingSecretName: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - hasDocuments: - count: 0 + errorPattern: "secretProviderClass" - it: should fail when both apiKey and existingSecretName are set set: @@ -39,7 +23,7 @@ tests: - failedTemplate: errorPattern: "oneOf" - # Pattern validation tests + # ===== Pattern validation ===== - it: should fail with invalid apiKey characters (spaces) set: @@ -73,7 +57,7 @@ tests: - failedTemplate: errorPattern: "does not match pattern" - # Successful template rendering tests + # ===== Top-level: successful rendering ===== - it: should create secret when only apiKey is set (with existingSecretName null) set: @@ -91,7 +75,7 @@ tests: - it: should create secret when only apiKey is set (existingSecretName omitted) values: - - ../values.yaml # Use empty base values + - ../values.yaml set: apiKey: "test-key-xyz" host: api.cloudzero.com @@ -159,3 +143,43 @@ tests: asserts: - isKind: of: Secret + + # ===== components.apiKey.secretProviderClass ===== + + - it: should not create secret when secretProviderClass is set + set: + apiKey: null + existingSecretName: null + components: + apiKey: + secretProviderClass: "my-spc" + asserts: + - hasDocuments: + count: 0 + + # ===== Precedence: top-level wins over components.apiKey ===== + + - it: should use top-level apiKey even when secretProviderClass is set + set: + apiKey: "top-level-key" + existingSecretName: null + components: + apiKey: + secretProviderClass: "should-be-ignored" + asserts: + - isKind: + of: Secret + - equal: + path: data.value + value: dG9wLWxldmVsLWtleQ== # base64 of "top-level-key" + + - it: should use top-level existingSecretName even when secretProviderClass is set + set: + apiKey: null + existingSecretName: "my-existing-secret" + components: + apiKey: + secretProviderClass: "should-be-ignored" + asserts: + - hasDocuments: + count: 0 diff --git a/helm/tests/extra_volumes_test.yaml b/helm/tests/extra_volumes_test.yaml deleted file mode 100644 index 872e16a89..000000000 --- a/helm/tests/extra_volumes_test.yaml +++ /dev/null @@ -1,216 +0,0 @@ -suite: test extraVolumes and extraVolumeMounts support -templates: - - templates/aggregator-deploy.yaml - - templates/agent-deploy.yaml - - templates/agent-daemonset.yaml - - templates/config-loader-job.yaml - - templates/webhook-deploy.yaml - - templates/backfill-job.yaml -tests: - - it: should add extra volumes and mounts to the aggregator deployment - set: - clusterName: "test-cluster" - cloudAccountId: "123456789" - region: "us-east-1" - existingSecretName: "cloudzero-api-key" - apiKey: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - contains: - path: spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/aggregator-deploy.yaml - - contains: - path: spec.template.spec.containers[0].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/aggregator-deploy.yaml - - contains: - path: spec.template.spec.containers[1].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/aggregator-deploy.yaml - - - it: should add extra volumes and mounts to the clustered agent deployment - set: - clusterName: "test-cluster" - cloudAccountId: "123456789" - region: "us-east-1" - existingSecretName: "cloudzero-api-key" - apiKey: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - contains: - path: spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/agent-deploy.yaml - - contains: - path: spec.template.spec.initContainers[0].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/agent-deploy.yaml - - contains: - path: spec.template.spec.containers[1].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/agent-deploy.yaml - - - it: should add extra volumes and mounts to webhook and config-loader jobs - set: - clusterName: "test-cluster" - cloudAccountId: "123456789" - region: "us-east-1" - existingSecretName: "cloudzero-api-key" - apiKey: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - contains: - path: spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/webhook-deploy.yaml - - contains: - path: spec.template.spec.containers[0].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/webhook-deploy.yaml - - contains: - path: spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/config-loader-job.yaml - - contains: - path: spec.template.spec.containers[0].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/config-loader-job.yaml - - - it: should add extra volumes and mounts in federated mode and backfill - set: - clusterName: "test-cluster" - cloudAccountId: "123456789" - region: "us-east-1" - existingSecretName: "cloudzero-api-key" - apiKey: null - configmapReload: - prometheus: - enabled: false - defaults: - federation: - enabled: true - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - contains: - path: spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/agent-daemonset.yaml - - contains: - path: spec.template.spec.containers[0].volumeMounts - content: - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - template: templates/agent-daemonset.yaml - - - it: should add extra volumes and mounts to the backfill CronJob - documentIndex: 0 - set: - clusterName: "test-cluster" - cloudAccountId: "123456789" - region: "us-east-1" - existingSecretName: "cloudzero-api-key" - apiKey: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - contains: - path: spec.jobTemplate.spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/backfill-job.yaml - - - it: should add extra volumes and mounts to the backfill one-time Job - documentIndex: 1 - set: - clusterName: "test-cluster" - cloudAccountId: "123456789" - region: "us-east-1" - existingSecretName: "cloudzero-api-key" - apiKey: null - extraVolumes: - - name: custom-extra-volume - configMap: - name: custom-extra-config - extraVolumeMounts: - - name: custom-extra-volume - mountPath: /opt/custom-extra - readOnly: true - asserts: - - contains: - path: spec.template.spec.volumes - content: - name: custom-extra-volume - configMap: - name: custom-extra-config - template: templates/backfill-job.yaml diff --git a/helm/values.schema.json b/helm/values.schema.json index 2a43d03f5..021961a52 100644 --- a/helm/values.schema.json +++ b/helm/values.schema.json @@ -5444,28 +5444,6 @@ "additionalProperties": false, "allOf": [ { - "if": { - "properties": { - "apiKey": { - "type": "null" - }, - "existingSecretName": { - "type": "null" - } - } - }, - "then": { - "properties": { - "extraVolumes": { - "minItems": 1, - "type": "array" - }, - "extraVolumeMounts": { - "minItems": 1, - "type": "array" - } - } - }, "else": { "oneOf": [ { @@ -5490,6 +5468,33 @@ } } ] + }, + "if": { + "properties": { + "apiKey": { + "type": "null" + }, + "existingSecretName": { + "type": "null" + } + } + }, + "then": { + "properties": { + "components": { + "properties": { + "apiKey": { + "properties": { + "secretProviderClass": { + "minLength": 1, + "type": "string" + } + }, + "required": ["secretProviderClass"] + } + } + } + } } }, { @@ -5834,32 +5839,6 @@ "apiKey": { "type": ["string", "null"] }, - "extraVolumeMounts": { - "oneOf": [ - { - "items": { - "$ref": "#/$defs/io.k8s.api.core.v1.VolumeMount" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "extraVolumes": { - "oneOf": [ - { - "items": { - "$ref": "#/$defs/io.k8s.api.core.v1.Volume" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, "cloudAccountId": { "pattern": "^$|^[0-9]+$|^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$|^'[0-9]+'$|^'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'$", "type": "string" @@ -6230,6 +6209,15 @@ }, "type": "object" }, + "apiKey": { + "additionalProperties": false, + "properties": { + "secretProviderClass": { + "type": ["string", "null"] + } + }, + "type": "object" + }, "kubectl": { "additionalProperties": false, "deprecated": true, diff --git a/helm/values.schema.yaml b/helm/values.schema.yaml index c7942c440..aa547b0fb 100644 --- a/helm/values.schema.yaml +++ b/helm/values.schema.yaml @@ -377,22 +377,6 @@ properties: - "null" description: | The name of an existing Kubernetes secret containing the API key. - extraVolumeMounts: - oneOf: - - type: array - items: - $ref: "#/$defs/io.k8s.api.core.v1.VolumeMount" - - type: "null" - description: | - Additional Kubernetes VolumeMount definitions to add to CloudZero workloads. - extraVolumes: - oneOf: - - type: array - items: - $ref: "#/$defs/io.k8s.api.core.v1.Volume" - - type: "null" - description: | - Additional Kubernetes Volume definitions to add to CloudZero workloads. nameOverride: deprecated: true type: @@ -516,6 +500,23 @@ properties: additionalProperties: false type: object properties: + apiKey: + description: | + API key CSI configuration. Takes effect only when both top-level + apiKey and existingSecretName are null. + type: object + additionalProperties: false + properties: + secretProviderClass: + description: | + Name of a Kubernetes SecretProviderClass resource. When set, the + chart mounts the API key via the Secrets Store CSI Driver instead + of a Kubernetes Secret volume. The SecretProviderClass must be + created separately and configured to produce a file named after + serverConfig.containerSecretFileName at the mount path. + type: + - string + - "null" agent: description: | The CloudZero Agent. @@ -3067,9 +3068,9 @@ properties: allOf: # Conditional: API key source validation # - # Default mode: exactly one of apiKey or existingSecretName must be set. - # External volume mode: if both are null, require explicit extraVolumes and - # extraVolumeMounts so this remains intentional and not accidental. + # Top-level apiKey/existingSecretName take priority when set. If both are + # null, the chart falls back to components.apiKey where exactly one of + # value, name, or secretProviderClass must be non-null. - if: properties: apiKey: @@ -3078,12 +3079,14 @@ allOf: type: "null" then: properties: - extraVolumes: - type: array - minItems: 1 - extraVolumeMounts: - type: array - minItems: 1 + components: + properties: + apiKey: + properties: + secretProviderClass: + type: string + minLength: 1 + required: [secretProviderClass] else: oneOf: - properties: diff --git a/helm/values.yaml b/helm/values.yaml index f1a1a731d..330496401 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -39,10 +39,6 @@ region: null apiKey: null # -- If set, the agent will use the API key in this Secret to authenticate with CloudZero. existingSecretName: null -# -- Additional Kubernetes VolumeMount entries to add to the CloudZero workloads. -extraVolumeMounts: [] -# -- Additional Kubernetes Volume entries to add to the CloudZero workloads. -extraVolumes: [] # Agent largely contains top-level settings which are often shared by multiple # components within this chart, or used as defaults in case values are not @@ -284,6 +280,13 @@ integrations: # Component-specific configuration settings. components: + # API key configuration for CSI-driven secret mounts. + apiKey: + # -- Name of a SecretProviderClass resource. When set (and both top-level + # -- apiKey and existingSecretName are null), the chart mounts the API key + # -- via the Secrets Store CSI Driver instead of a Kubernetes Secret volume. + secretProviderClass: null + # The agent here refers to the CloudZero Agent, which is the component that # collects metrics from the cluster and sends them to the aggregator. agent: diff --git a/tests/helm/template/alloy.yaml b/tests/helm/template/alloy.yaml index 8ed6edc7f..ad07779c4 100644 --- a/tests/helm/template/alloy.yaml +++ b/tests/helm/template/alloy.yaml @@ -1060,6 +1060,8 @@ data: memory: 64Mi securityContext: {} tolerations: [] + apiKey: + secretProviderClass: null miscellaneous: configLoader: annotations: {} @@ -3040,13 +3042,13 @@ spec: volumeMounts: - name: insights-server-config mountPath: /etc/cloudzero-agent-insights - - name: tls-certs - mountPath: /etc/certs - readOnly: true - name: cloudzero-api-key mountPath: /etc/config/secrets/ subPath: "" readOnly: true + - name: tls-certs + mountPath: /etc/certs + readOnly: true livenessProbe: httpGet: scheme: HTTPS diff --git a/tests/helm/template/cert-manager.yaml b/tests/helm/template/cert-manager.yaml index ded942b32..2b5fd9eda 100644 --- a/tests/helm/template/cert-manager.yaml +++ b/tests/helm/template/cert-manager.yaml @@ -975,6 +975,8 @@ data: memory: 64Mi securityContext: {} tolerations: [] + apiKey: + secretProviderClass: null miscellaneous: configLoader: annotations: {} @@ -2934,13 +2936,13 @@ spec: volumeMounts: - name: insights-server-config mountPath: /etc/cloudzero-agent-insights - - name: tls-certs - mountPath: /etc/certs - readOnly: true - name: cloudzero-api-key mountPath: /etc/config/secrets/ subPath: "" readOnly: true + - name: tls-certs + mountPath: /etc/certs + readOnly: true livenessProbe: httpGet: scheme: HTTPS diff --git a/tests/helm/template/federated.yaml b/tests/helm/template/federated.yaml index 3bf4a2789..398190809 100644 --- a/tests/helm/template/federated.yaml +++ b/tests/helm/template/federated.yaml @@ -1063,6 +1063,8 @@ data: memory: 64Mi securityContext: {} tolerations: [] + apiKey: + secretProviderClass: null miscellaneous: configLoader: annotations: {} @@ -3217,13 +3219,13 @@ spec: volumeMounts: - name: insights-server-config mountPath: /etc/cloudzero-agent-insights - - name: tls-certs - mountPath: /etc/certs - readOnly: true - name: cloudzero-api-key mountPath: /etc/config/secrets/ subPath: "" readOnly: true + - name: tls-certs + mountPath: /etc/certs + readOnly: true livenessProbe: httpGet: scheme: HTTPS diff --git a/tests/helm/template/istio.yaml b/tests/helm/template/istio.yaml index df4965bfc..2f93b2b84 100644 --- a/tests/helm/template/istio.yaml +++ b/tests/helm/template/istio.yaml @@ -990,6 +990,8 @@ data: memory: 64Mi securityContext: {} tolerations: [] + apiKey: + secretProviderClass: null miscellaneous: configLoader: annotations: {} @@ -2950,13 +2952,13 @@ spec: volumeMounts: - name: insights-server-config mountPath: /etc/cloudzero-agent-insights - - name: tls-certs - mountPath: /etc/certs - readOnly: true - name: cloudzero-api-key mountPath: /etc/config/secrets/ subPath: "" readOnly: true + - name: tls-certs + mountPath: /etc/certs + readOnly: true livenessProbe: httpGet: scheme: HTTPS diff --git a/tests/helm/template/kubestate.yaml b/tests/helm/template/kubestate.yaml index 57b6e7ba6..c20f4ab45 100644 --- a/tests/helm/template/kubestate.yaml +++ b/tests/helm/template/kubestate.yaml @@ -1027,6 +1027,8 @@ data: memory: 64Mi securityContext: {} tolerations: [] + apiKey: + secretProviderClass: null miscellaneous: configLoader: annotations: {} @@ -2490,13 +2492,13 @@ spec: volumeMounts: - name: insights-server-config mountPath: /etc/cloudzero-agent-insights - - name: tls-certs - mountPath: /etc/certs - readOnly: true - name: cloudzero-api-key mountPath: /etc/config/secrets/ subPath: "" readOnly: true + - name: tls-certs + mountPath: /etc/certs + readOnly: true livenessProbe: httpGet: scheme: HTTPS diff --git a/tests/helm/template/manifest.yaml b/tests/helm/template/manifest.yaml index 16ef82b47..a43d2d6a1 100644 --- a/tests/helm/template/manifest.yaml +++ b/tests/helm/template/manifest.yaml @@ -990,6 +990,8 @@ data: memory: 64Mi securityContext: {} tolerations: [] + apiKey: + secretProviderClass: null miscellaneous: configLoader: annotations: {} @@ -2949,13 +2951,13 @@ spec: volumeMounts: - name: insights-server-config mountPath: /etc/cloudzero-agent-insights - - name: tls-certs - mountPath: /etc/certs - readOnly: true - name: cloudzero-api-key mountPath: /etc/config/secrets/ subPath: "" readOnly: true + - name: tls-certs + mountPath: /etc/certs + readOnly: true livenessProbe: httpGet: scheme: HTTPS