diff --git a/helm/litellm-helm/Chart.yaml b/helm/litellm-helm/Chart.yaml index 0aef2442bfe..868e1ad876e 100644 --- a/helm/litellm-helm/Chart.yaml +++ b/helm/litellm-helm/Chart.yaml @@ -18,7 +18,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.1.0 +version: 1.2.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/helm/litellm-helm/README.md b/helm/litellm-helm/README.md index 74e70f4aeb4..0b11e456b3e 100644 --- a/helm/litellm-helm/README.md +++ b/helm/litellm-helm/README.md @@ -53,6 +53,10 @@ If `db.useStackgresOperator` is used (not yet implemented): | `pdb.maxUnavailable` | Maximum number/percentage of pods that can be unavailable during **voluntary** disruptions (choose **one** of minAvailable/maxUnavailable) | `null` | | `pdb.annotations` | Extra metadata annotations to add to the PDB | `{}` | | `pdb.labels` | Extra metadata labels to add to the PDB | `{}` | +| `serviceMonitor.enabled` | Create a Prometheus Operator ServiceMonitor that scrapes the proxy's `/metrics/` endpoint | `false` | +| `serviceMonitor.authSecret.enabled` | Authenticate scrapes with a bearer token. The proxy requires authentication on `/metrics` unless `litellm_settings.require_auth_for_metrics_endpoint` is `false`. When `authSecret.name` is empty, the master key secret is used. The master key grants full admin access to the proxy, so consider pointing `authSecret.name`/`authSecret.key` at a secret holding a dedicated virtual key instead. | `true` | +| `serviceMonitor.authSecret.name` | Name of an existing Kubernetes Secret holding the bearer token used to scrape `/metrics/`. Must live in the same namespace as the ServiceMonitor (the release namespace). | `""` | +| `serviceMonitor.authSecret.key` | Key within `serviceMonitor.authSecret.name` that holds the token. Required when `authSecret.name` is set. | `""` | #### Example `proxy_config` ConfigMap from values (default): diff --git a/helm/litellm-helm/templates/servicemonitor.yaml b/helm/litellm-helm/templates/servicemonitor.yaml index 743098deb3f..446ebf63f65 100644 --- a/helm/litellm-helm/templates/servicemonitor.yaml +++ b/helm/litellm-helm/templates/servicemonitor.yaml @@ -31,6 +31,18 @@ spec: interval: {{ .interval }} scrapeTimeout: {{ .scrapeTimeout }} scheme: http + {{- if .authSecret.enabled }} + authorization: + type: Bearer + credentials: + {{- if .authSecret.name }} + name: {{ .authSecret.name }} + key: {{ required "serviceMonitor.authSecret.key is required when serviceMonitor.authSecret.name is set" .authSecret.key }} + {{- else }} + name: {{ $.Values.masterkeySecretName | default (printf "%s-masterkey" (include "litellm.fullname" $)) }} + key: {{ $.Values.masterkeySecretKey | default "masterkey" }} + {{- end }} + {{- end }} {{- if .relabelings }} relabelings: {{- toYaml .relabelings | nindent 4 }} diff --git a/helm/litellm-helm/tests/servicemonitor_tests.yaml b/helm/litellm-helm/tests/servicemonitor_tests.yaml new file mode 100644 index 00000000000..f9487ba3a8b --- /dev/null +++ b/helm/litellm-helm/tests/servicemonitor_tests.yaml @@ -0,0 +1,65 @@ +suite: test service monitor +templates: + - servicemonitor.yaml +release: + name: my-release +tests: + - it: should not render a ServiceMonitor when disabled + set: + serviceMonitor.enabled: false + asserts: + - hasDocuments: + count: 0 + - it: should authenticate scrapes with the generated masterkey secret by default + set: + serviceMonitor.enabled: true + asserts: + - isKind: + of: ServiceMonitor + - equal: + path: spec.endpoints[0].authorization.type + value: Bearer + - equal: + path: spec.endpoints[0].authorization.credentials.name + value: my-release-litellm-masterkey + - equal: + path: spec.endpoints[0].authorization.credentials.key + value: masterkey + - it: should authenticate scrapes with masterkeySecretName and masterkeySecretKey when set + set: + serviceMonitor.enabled: true + masterkeySecretName: my-masterkey-secret + masterkeySecretKey: my-key + asserts: + - equal: + path: spec.endpoints[0].authorization.credentials.name + value: my-masterkey-secret + - equal: + path: spec.endpoints[0].authorization.credentials.key + value: my-key + - it: should authenticate scrapes with a custom auth secret when set + set: + serviceMonitor.enabled: true + serviceMonitor.authSecret.name: metrics-token + serviceMonitor.authSecret.key: token + asserts: + - equal: + path: spec.endpoints[0].authorization.credentials.name + value: metrics-token + - equal: + path: spec.endpoints[0].authorization.credentials.key + value: token + - it: should fail when a custom auth secret name is set without a key + set: + serviceMonitor.enabled: true + serviceMonitor.authSecret.name: metrics-token + asserts: + - failedTemplate: + errorMessage: serviceMonitor.authSecret.key is required when serviceMonitor.authSecret.name is set + - it: should not send credentials when authSecret is disabled + set: + serviceMonitor.enabled: true + serviceMonitor.authSecret.enabled: false + asserts: + - notExists: + path: spec.endpoints[0].authorization diff --git a/helm/litellm-helm/values.yaml b/helm/litellm-helm/values.yaml index 6e30a6af444..51d7c13132a 100644 --- a/helm/litellm-helm/values.yaml +++ b/helm/litellm-helm/values.yaml @@ -417,6 +417,10 @@ serviceMonitor: # kubernetes.io/test: test interval: 15s scrapeTimeout: 10s + authSecret: + enabled: true + name: "" + key: "" relabelings: [] # - targetLabel: __meta_kubernetes_pod_node_name # replacement: $1