OpenTelemetry Operator for Kubernetes's ServiceMonitor bearerTokenFile reads arbitrary local file and sends contents as bearer auth
Description
OpenTelemetry Operator's TargetAllocator allows tenants to exfiltrate the Collector's service account token to a controlled endpoint.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
OpenTelemetry Operator's TargetAllocator allows tenants to exfiltrate the Collector's service account token to a controlled endpoint.
Vulnerability
The cmd/otel-allocator component of the OpenTelemetry Operator, specifically the TargetAllocator, improperly handles ServiceMonitor resources. It preserves the bearerTokenFile field, which is then used by the OpenTelemetry Collector to send its mounted service account JWT to a scrape target controlled by a tenant. This vulnerability affects versions of the OpenTelemetry Operator where this functionality is present and not guarded.
Exploitation
An attacker who can create or update a ServiceMonitor resource, and has control over a scrape target, can configure bearerTokenFile to point to the Collector's service account token file (/var/run/secrets/kubernetes.io/serviceaccount/token). This requires the OpenTelemetry Collector to be deployed with targetAllocator.prometheusCR.enabled: true and matching serviceMonitorSelector settings, and the Collector pod must have its service account token mounted and be able to reach the attacker-controlled target.
Impact
Successful exploitation allows a tenant to impersonate the OpenTelemetry Collector's service account when interacting with the Kubernetes API. The extent of the impact depends on the permissions granted to the Collector's service account, but typically includes the ability to enumerate pods, nodes, endpoints, namespaces, and services within the cluster, potentially leading to further compromise.
Mitigation
This issue was addressed by adding a feature to disable the functionality that reads arbitrary files from ServiceMonitor endpoints. Users can enable this feature to prevent the vulnerability. The specific fixed version and release date are not detailed in the provided references, but the change is documented in pull request #5104 [4].
AI Insight generated on Jun 10, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
195a8c2a3dc64feat: add support for arb sm toggle (#5104)
23 files changed · +658 −2
apis/v1alpha1/opentelemetrycollector_types.go+10 −0 modified@@ -411,6 +411,16 @@ type OpenTelemetryTargetAllocatorPrometheusCR struct { // Empty or nil map matches all service monitors. // +optional ServiceMonitorSelector map[string]string `json:"serviceMonitorSelector,omitempty"` + // DenyFSAccessThroughSMs causes the Target Allocator to drop ServiceMonitor and + // PodMonitor endpoints that reference arbitrary files on the file system. When + // enabled, endpoints with bearerTokenFile, tlsConfig.caFile, tlsConfig.certFile, + // or tlsConfig.keyFile are dropped from the produced scrape configuration while + // the remaining endpoints are kept. This prevents tenants from stealing the + // Collector's service account token via ServiceMonitor bearerTokenFile + // references. This is the equivalent of ArbitraryFSAccessThroughSMs.Deny from + // the Prometheus Operator. + // +optional + DenyFSAccessThroughSMs bool `json:"denyFSAccessThroughSMs,omitempty"` } // ScaleSubresourceStatus defines the observed state of the OpenTelemetryCollector's
apis/v1beta1/targetallocator_types.go+10 −0 modified@@ -22,6 +22,16 @@ type TargetAllocatorPrometheusCR struct { // If not configured, defaults to the target allocator's own namespace. // +optional SecretNamespaces []string `json:"secretNamespaces,omitempty"` + // DenyFSAccessThroughSMs causes the Target Allocator to drop ServiceMonitor and + // PodMonitor endpoints that reference arbitrary files on the file system. When + // enabled, endpoints with bearerTokenFile, tlsConfig.caFile, tlsConfig.certFile, + // or tlsConfig.keyFile are dropped from the produced scrape configuration while + // the remaining endpoints are kept. This prevents tenants from stealing the + // Collector's service account token via ServiceMonitor bearerTokenFile + // references. This is the equivalent of ArbitraryFSAccessThroughSMs.Deny from + // the Prometheus Operator. + // +optional + DenyFSAccessThroughSMs bool `json:"denyFSAccessThroughSMs,omitempty"` // Default interval between consecutive scrapes. Intervals set in ServiceMonitors and PodMonitors override it. // // Default: "30s"
bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml+4 −0 modified@@ -3363,6 +3363,8 @@ spec: type: object prometheusCR: properties: + denyFSAccessThroughSMs: + type: boolean enabled: type: boolean podMonitorSelector: @@ -8302,6 +8304,8 @@ spec: items: type: string type: array + denyFSAccessThroughSMs: + type: boolean denyNamespaces: items: type: string
bundle/community/manifests/opentelemetry.io_targetallocators.yaml+2 −0 modified@@ -2480,6 +2480,8 @@ spec: items: type: string type: array + denyFSAccessThroughSMs: + type: boolean denyNamespaces: items: type: string
bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml+1 −1 modified@@ -99,7 +99,7 @@ metadata: categories: Logging & Tracing,Monitoring,Observability certified: "false" containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator - createdAt: "2026-05-08T09:28:09Z" + createdAt: "2026-05-19T18:40:17Z" description: Provides the OpenTelemetry components, including the Collector operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml+4 −0 modified@@ -3362,6 +3362,8 @@ spec: type: object prometheusCR: properties: + denyFSAccessThroughSMs: + type: boolean enabled: type: boolean podMonitorSelector: @@ -8301,6 +8303,8 @@ spec: items: type: string type: array + denyFSAccessThroughSMs: + type: boolean denyNamespaces: items: type: string
bundle/openshift/manifests/opentelemetry.io_targetallocators.yaml+2 −0 modified@@ -2480,6 +2480,8 @@ spec: items: type: string type: array + denyFSAccessThroughSMs: + type: boolean denyNamespaces: items: type: string
bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml+1 −1 modified@@ -99,7 +99,7 @@ metadata: categories: Logging & Tracing,Monitoring,Observability certified: "false" containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator - createdAt: "2026-05-08T09:28:09Z" + createdAt: "2026-05-19T18:40:17Z" description: Provides the OpenTelemetry components, including the Collector operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
.chloggen/add-support-for-arb-sm-toggle.yaml+16 −0 added@@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action) +component: target allocator + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Add support for dropping ServiceMonitor/PodMonitor endpoints that reference arbitrary files" + +# One or more tracking issues related to the change +issues: [5104] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext:
cmd/otel-allocator/internal/config/config.go+10 −0 modified@@ -92,6 +92,16 @@ type PrometheusCRConfig struct { EvaluationInterval model.Duration `yaml:"evaluation_interval,omitempty"` ScrapeProtocols []monitoringv1.ScrapeProtocol `yaml:"scrape_protocols,omitempty"` ScrapeClasses []monitoringv1.ScrapeClass `yaml:"scrape_classes,omitempty"` + // DenyFSAccessThroughSMs causes the Target Allocator to drop ServiceMonitor and + // PodMonitor endpoints that reference arbitrary files on the file system. When + // true, endpoints with bearerTokenFile, tlsConfig.caFile, tlsConfig.certFile, or + // tlsConfig.keyFile referencing paths outside an operator-owned mount are + // dropped from the produced scrape configuration while the remaining endpoints + // are kept. This prevents tenants from stealing the Collector's service account + // token. This is the equivalent of ArbitraryFSAccessThroughSMs.Deny from the + // Prometheus Operator. + // +optional + DenyFSAccessThroughSMs bool `yaml:"deny_fs_access_through_sms,omitempty"` } type HTTPSServerConfig struct {
cmd/otel-allocator/internal/watcher/promOperator_denyfs_test.go+195 −0 added@@ -0,0 +1,195 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package watcher + +import ( + "log/slog" + "testing" + "time" + + "github.com/prometheus/common/config" + "github.com/prometheus/common/model" + promconfig "github.com/prometheus/prometheus/config" + "github.com/stretchr/testify/assert" +) + +func newDenyFSWatcher() *PrometheusCRWatcher { + return &PrometheusCRWatcher{ + denyFSAccessThroughSMs: true, + logger: slog.Default(), + } +} + +// TestFilterScrapeConfigsDropsCredentialsFile verifies that a scrape config +// with authorization.credentials_file is dropped. +func TestFilterScrapeConfigsDropsCredentialsFile(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{ + { + JobName: "unsafe", + HTTPClientConfig: config.HTTPClientConfig{ + Authorization: &config.Authorization{ + Type: "Bearer", + CredentialsFile: "/var/run/secrets/kubernetes.io/serviceaccount/token", + }, + }, + }, + }, + } + + tw.filterScrapeConfigs(cfg) + assert.Empty(t, cfg.ScrapeConfigs) +} + +// TestFilterScrapeConfigsDropsTLSFiles verifies the guard drops scrape configs +// that set tlsConfig.caFile / certFile / keyFile. +func TestFilterScrapeConfigsDropsTLSFiles(t *testing.T) { + for _, tc := range []struct { + name string + tls config.TLSConfig + }{ + {name: "ca_file", tls: config.TLSConfig{CAFile: "/path/to/ca.crt"}}, + {name: "cert_file", tls: config.TLSConfig{CertFile: "/path/to/cert.crt"}}, + {name: "key_file", tls: config.TLSConfig{KeyFile: "/path/to/key.key"}}, + } { + t.Run(tc.name, func(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{ + { + JobName: "tls-" + tc.name, + HTTPClientConfig: config.HTTPClientConfig{ + TLSConfig: tc.tls, + }, + }, + }, + } + + tw.filterScrapeConfigs(cfg) + assert.Empty(t, cfg.ScrapeConfigs) + }) + } +} + +// TestFilterScrapeConfigsEmpty verifies that an empty scrape config list is a +// no-op. +func TestFilterScrapeConfigsEmpty(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{}, + } + + tw.filterScrapeConfigs(cfg) + assert.Empty(t, cfg.ScrapeConfigs) +} + +// TestFilterScrapeConfigsKeepsSafeConfigs verifies that scrape configs without +// file references are kept. +func TestFilterScrapeConfigsKeepsSafeConfigs(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{ + { + JobName: "safe", + MetricsPath: "/metrics", + ScrapeInterval: model.Duration(30 * time.Second), + EnableCompression: true, + HTTPClientConfig: config.HTTPClientConfig{ + BasicAuth: &config.BasicAuth{ + Username: "user", + Password: "password", + }, + }, + }, + }, + } + + tw.filterScrapeConfigs(cfg) + assert.Len(t, cfg.ScrapeConfigs, 1) + assert.Equal(t, "safe", cfg.ScrapeConfigs[0].JobName) +} + +// TestFilterScrapeConfigsKeepsSafeDropsUnsafe verifies that in a mixed list, +// only the unsafe scrape configs are dropped. +func TestFilterScrapeConfigsKeepsSafeDropsUnsafe(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{ + { + JobName: "safe", + HTTPClientConfig: config.HTTPClientConfig{ + BasicAuth: &config.BasicAuth{ + Username: "user", + Password: "pass", + }, + }, + }, + { + JobName: "unsafe-credentials", + HTTPClientConfig: config.HTTPClientConfig{ + Authorization: &config.Authorization{ + Type: "Bearer", + CredentialsFile: "/var/run/secrets/kubernetes.io/serviceaccount/token", + }, + }, + }, + { + JobName: "unsafe-tls", + HTTPClientConfig: config.HTTPClientConfig{ + TLSConfig: config.TLSConfig{KeyFile: "/path/to/key.key"}, + }, + }, + }, + } + + tw.filterScrapeConfigs(cfg) + assert.Len(t, cfg.ScrapeConfigs, 1) + assert.Equal(t, "safe", cfg.ScrapeConfigs[0].JobName) +} + +// TestFilterScrapeConfigsNilAuthorization verifies nil Authorization fields do +// not cause panics or unintended drops. +func TestFilterScrapeConfigsNilAuthorization(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{ + { + JobName: "no-auth", + HTTPClientConfig: config.HTTPClientConfig{ + Authorization: nil, + }, + }, + }, + } + + tw.filterScrapeConfigs(cfg) + assert.Len(t, cfg.ScrapeConfigs, 1) +} + +// TestFilterScrapeConfigsEmptyTLSConfig verifies an empty TLSConfig keeps the +// scrape config. +func TestFilterScrapeConfigsEmptyTLSConfig(t *testing.T) { + tw := newDenyFSWatcher() + + cfg := &promconfig.Config{ + ScrapeConfigs: []*promconfig.ScrapeConfig{ + { + JobName: "empty-tls", + HTTPClientConfig: config.HTTPClientConfig{ + TLSConfig: config.TLSConfig{}, + }, + }, + }, + } + + tw.filterScrapeConfigs(cfg) + assert.Len(t, cfg.ScrapeConfigs, 1) +}
cmd/otel-allocator/internal/watcher/promOperator.go+47 −0 modified@@ -150,6 +150,7 @@ func NewPrometheusCRWatcher( resourceSelector: resourceSelector, store: store, prometheusCR: prom, + denyFSAccessThroughSMs: cfg.PrometheusCR.DenyFSAccessThroughSMs, }, nil } @@ -170,6 +171,7 @@ type PrometheusCRWatcher struct { resourceSelector *prometheus.ResourceSelector store *assets.StoreBuilder prometheusCR *monitoringv1.Prometheus + denyFSAccessThroughSMs bool } func getNamespaceInformer(ctx context.Context, allowList, denyList map[string]struct{}, promOperatorLogger *slog.Logger, clientset kubernetes.Interface, operatorMetrics *operator.Metrics) (cache.SharedIndexInformer, error) { @@ -649,6 +651,13 @@ func (w *PrometheusCRWatcher) LoadConfig(ctx context.Context) (*promconfig.Confi return nil, unmarshalErr } + // If denyFSAccessThroughSMs is enabled, drop scrape configs that reference + // arbitrary files on the file system. This prevents tenants from stealing + // the Collector's service account token. + if w.denyFSAccessThroughSMs { + w.filterScrapeConfigs(promCfg) + } + // set kubeconfig path to service discovery configs, else kubernetes_sd will always attempt in-cluster // authentication even if running with a detected kubeconfig for _, scrapeConfig := range promCfg.ScrapeConfigs { @@ -665,6 +674,44 @@ func (w *PrometheusCRWatcher) LoadConfig(ctx context.Context) (*promconfig.Confi return promCfg, nil } +// filterScrapeConfigs drops scrape configs that reference arbitrary files on +// the file system. This prevents tenants from stealing the Collector's service +// account token via ServiceMonitor bearerTokenFile (via +// authorization.credentials_file) or tlsConfig file references (caFile, +// certFile, keyFile). This is the equivalent guard from +// ArbitraryFSAccessThroughSMs.Deny in the Prometheus Operator. +func (w *PrometheusCRWatcher) filterScrapeConfigs(promCfg *promconfig.Config) { + filtered := promCfg.ScrapeConfigs[:0] + for _, sc := range promCfg.ScrapeConfigs { + if reason := deniedFSAccessReason(sc); reason != "" { + w.logger.Warn("dropping scrape config that references arbitrary file path", "job", sc.JobName, "reason", reason) + continue + } + filtered = append(filtered, sc) + } + promCfg.ScrapeConfigs = filtered +} + +// deniedFSAccessReason returns a non-empty reason if the scrape config +// references arbitrary files via authorization or TLS config, or "" if the +// config is allowed. +func deniedFSAccessReason(sc *promconfig.ScrapeConfig) string { + if auth := sc.HTTPClientConfig.Authorization; auth != nil && auth.CredentialsFile != "" { + return fmt.Sprintf("authorization.credentials_file: %s", auth.CredentialsFile) + } + tls := &sc.HTTPClientConfig.TLSConfig + if tls.CAFile != "" { + return fmt.Sprintf("tls_config.ca_file: %s", tls.CAFile) + } + if tls.CertFile != "" { + return fmt.Sprintf("tls_config.cert_file: %s", tls.CertFile) + } + if tls.KeyFile != "" { + return fmt.Sprintf("tls_config.key_file: %s", tls.KeyFile) + } + return "" +} + // WaitForNamedCacheSync adds a timeout to the informer's wait for the cache to be ready. // If the PrometheusCRWatcher is unable to load an informer within 15 seconds, the method is // cancelled and returns false. A successful informer load will return true. This method also
config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml+4 −0 modified@@ -3349,6 +3349,8 @@ spec: type: object prometheusCR: properties: + denyFSAccessThroughSMs: + type: boolean enabled: type: boolean podMonitorSelector: @@ -8288,6 +8290,8 @@ spec: items: type: string type: array + denyFSAccessThroughSMs: + type: boolean denyNamespaces: items: type: string
config/crd/bases/opentelemetry.io_targetallocators.yaml+2 −0 modified@@ -2478,6 +2478,8 @@ spec: items: type: string type: array + denyFSAccessThroughSMs: + type: boolean denyNamespaces: items: type: string
docs/api/opentelemetrycollectors.md+28 −0 modified@@ -13979,6 +13979,20 @@ All CR instances which the ServiceAccount has access to will be retrieved. This </tr> </thead> <tbody><tr> + <td><b>denyFSAccessThroughSMs</b></td> + <td>boolean</td> + <td> + DenyFSAccessThroughSMs causes the Target Allocator to drop ServiceMonitor and +PodMonitor endpoints that reference arbitrary files on the file system. When +enabled, endpoints with bearerTokenFile, tlsConfig.caFile, tlsConfig.certFile, +or tlsConfig.keyFile are dropped from the produced scrape configuration while +the remaining endpoints are kept. This prevents tenants from stealing the +Collector's service account token via ServiceMonitor bearerTokenFile +references. This is the equivalent of ArbitraryFSAccessThroughSMs.Deny from +the Prometheus Operator.<br/> + </td> + <td>false</td> + </tr><tr> <td><b>enabled</b></td> <td>boolean</td> <td> @@ -34859,6 +34873,20 @@ All CR instances which the ServiceAccount has access to will be retrieved. This AllowNamespaces Namespaces to scope the interaction of the Target Allocator and the apiserver (allow list). This is mutually exclusive with DenyNamespaces.<br/> </td> <td>false</td> + </tr><tr> + <td><b>denyFSAccessThroughSMs</b></td> + <td>boolean</td> + <td> + DenyFSAccessThroughSMs causes the Target Allocator to drop ServiceMonitor and +PodMonitor endpoints that reference arbitrary files on the file system. When +enabled, endpoints with bearerTokenFile, tlsConfig.caFile, tlsConfig.certFile, +or tlsConfig.keyFile are dropped from the produced scrape configuration while +the remaining endpoints are kept. This prevents tenants from stealing the +Collector's service account token via ServiceMonitor bearerTokenFile +references. This is the equivalent of ArbitraryFSAccessThroughSMs.Deny from +the Prometheus Operator.<br/> + </td> + <td>false</td> </tr><tr> <td><b>denyNamespaces</b></td> <td>[]string</td>
docs/api/targetallocators.md+14 −0 modified@@ -10364,6 +10364,20 @@ PrometheusCR defines the configuration for the retrieval of PrometheusOperator C AllowNamespaces Namespaces to scope the interaction of the Target Allocator and the apiserver (allow list). This is mutually exclusive with DenyNamespaces.<br/> </td> <td>false</td> + </tr><tr> + <td><b>denyFSAccessThroughSMs</b></td> + <td>boolean</td> + <td> + DenyFSAccessThroughSMs causes the Target Allocator to drop ServiceMonitor and +PodMonitor endpoints that reference arbitrary files on the file system. When +enabled, endpoints with bearerTokenFile, tlsConfig.caFile, tlsConfig.certFile, +or tlsConfig.keyFile are dropped from the produced scrape configuration while +the remaining endpoints are kept. This prevents tenants from stealing the +Collector's service account token via ServiceMonitor bearerTokenFile +references. This is the equivalent of ArbitraryFSAccessThroughSMs.Deny from +the Prometheus Operator.<br/> + </td> + <td>false</td> </tr><tr> <td><b>denyNamespaces</b></td> <td>[]string</td>
internal/manifests/targetallocator/configmap.go+4 −0 modified@@ -117,6 +117,10 @@ func ConfigMap(params Params) (*corev1.ConfigMap, error) { prometheusCRConfig["secret_namespaces"] = taSpec.PrometheusCR.SecretNamespaces } + if taSpec.PrometheusCR.DenyFSAccessThroughSMs { + prometheusCRConfig["deny_fs_access_through_sms"] = true + } + prometheusCRConfig["service_monitor_namespace_selector"] = taSpec.PrometheusCR.ServiceMonitorNamespaceSelector prometheusCRConfig["service_monitor_selector"] = taSpec.PrometheusCR.ServiceMonitorSelector
internal/manifests/targetallocator/configmap_test.go+55 −0 modified@@ -923,3 +923,58 @@ filter_strategy: relabel-config assert.Equal(t, expectedData[targetAllocatorFilename], actual.Data[targetAllocatorFilename]) }) } + +func TestDesiredConfigMapWithDenyFSAccessThroughSMs(t *testing.T) { + t.Run("should return expected target allocator config map with denyFSAccessThroughSMs", func(t *testing.T) { + require.NoError(t, colfg.GlobalRegistry().Set("operator.targetallocator.fallbackstrategy", true)) + t.Cleanup(func() { + require.NoError(t, colfg.GlobalRegistry().Set("operator.targetallocator.fallbackstrategy", false)) + }) + + expectedData := map[string]string{ + targetAllocatorFilename: `allocation_fallback_strategy: consistent-hashing +allocation_strategy: consistent-hashing +collector_selector: + matchlabels: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/instance: default.my-instance + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/part-of: opentelemetry + matchexpressions: [] +config: + scrape_configs: + - job_name: otel-collector + scrape_interval: 10s + static_configs: + - targets: + - 0.0.0.0:8888 + - 0.0.0.0:9999 +filter_strategy: relabel-config +prometheus_cr: + deny_fs_access_through_sms: true + enabled: true + pod_monitor_namespace_selector: null + pod_monitor_selector: null + probe_namespace_selector: null + probe_selector: null + scrape_config_namespace_selector: null + scrape_config_selector: null + service_monitor_namespace_selector: null + service_monitor_selector: null +`, + } + + targetAllocator := targetAllocatorInstance() + targetAllocator.Spec.PrometheusCR.Enabled = true + targetAllocator.Spec.PrometheusCR.DenyFSAccessThroughSMs = true + testParams := Params{ + Collector: collectorInstance(), + TargetAllocator: targetAllocator, + } + actual, err := ConfigMap(testParams) + assert.NoError(t, err) + + assert.Equal(t, "my-instance-targetallocator", actual.Name) + assert.Equal(t, expectedData, actual.Data) + }) +}
tests/e2e-targetallocator/targetallocator-prometheuscr-denyfs/00-assert.yaml+20 −0 added@@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: prometheus-cr-denyfs-collector +status: + readyReplicas: 1 + replicas: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-cr-denyfs-targetallocator +status: + readyReplicas: 1 + replicas: 1 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-cr-denyfs-targetallocator
tests/e2e-targetallocator/targetallocator-prometheuscr-denyfs/00-install.yaml+72 −0 added@@ -0,0 +1,72 @@ +apiVersion: v1 +automountServiceAccountToken: true +kind: ServiceAccount +metadata: + name: collector +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: collector-prometheuscr-denyfs +rules: +- apiGroups: + - "" + resources: + - pods + - nodes + - nodes/metrics + - services + - endpoints + - namespaces + verbs: + - get + - watch + - list +- nonResourceURLs: + - /metrics + - /metrics/cadvisor + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: (join('-', ['collector', $namespace])) +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: collector-prometheuscr-denyfs +subjects: +- kind: ServiceAccount + name: collector + namespace: ($namespace) +--- +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: prometheus-cr-denyfs +spec: + config: + receivers: + prometheus: + config: + scrape_configs: [] + exporters: + debug: + verbosity: detailed + service: + pipelines: + metrics: + receivers: [prometheus] + exporters: [debug] + mode: statefulset + serviceAccount: collector + targetAllocator: + enabled: true + prometheusCR: + enabled: true + scrapeInterval: 1s + denyFSAccessThroughSMs: true + serviceMonitorSelector: {} + podMonitorSelector: {} + serviceAccount: ta
tests/e2e-targetallocator/targetallocator-prometheuscr-denyfs/01-assert.yaml+18 −0 added@@ -0,0 +1,18 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: metrics-app +status: + availableReplicas: 1 +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: metrics-servicemonitor +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: check-denyfs-filtering +status: + succeeded: 1
tests/e2e-targetallocator/targetallocator-prometheuscr-denyfs/01-install.yaml+103 −0 added@@ -0,0 +1,103 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: metrics-app + labels: + app: metrics-app +spec: + replicas: 1 + selector: + matchLabels: + app: metrics-app + template: + metadata: + labels: + app: metrics-app + spec: + containers: + - name: metrics-app + image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-metrics-basic-auth:main + ports: + - containerPort: 9123 + env: + - name: BASIC_AUTH_USERNAME + value: user + - name: BASIC_AUTH_PASSWORD + value: pass +--- +apiVersion: v1 +kind: Service +metadata: + name: metrics-service + labels: + app: metrics-app +spec: + ports: + - name: metrics + port: 9123 + targetPort: 9123 + protocol: TCP + - name: safe-metrics + port: 9124 + targetPort: 9123 + protocol: TCP + selector: + app: metrics-app + type: ClusterIP +--- +# A ServiceMonitor with one unsafe endpoint (bearerTokenFile, references the +# Collector's mounted service account token) and one safe endpoint (no file +# references). With denyFSAccessThroughSMs enabled, only the safe endpoint +# should appear in the Target Allocator's scrape configs. +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: metrics-servicemonitor + labels: + app: metrics-app +spec: + selector: + matchLabels: + app: metrics-app + endpoints: + - port: metrics + interval: 10s + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + - port: safe-metrics + interval: 10s +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: check-denyfs-filtering +spec: + backoffLimit: 10 + template: + metadata: + labels: + checker: "true" + spec: + restartPolicy: OnFailure + containers: + - name: check-config + image: mirror.gcr.io/curlimages/curl:latest + args: + - /bin/sh + - -c + - | + set -e + CONFIG=$(curl -fs http://prometheus-cr-denyfs-targetallocator/scrape_configs) + echo "$CONFIG" + # The safe endpoint (port safe-metrics) must remain. + echo "$CONFIG" | grep -q "safe-metrics" + # The unsafe endpoint (bearerTokenFile) must be dropped: neither + # the credentials_file path nor the unsafe port should be present. + if echo "$CONFIG" | grep -q "credentials_file"; then + echo "credentials_file should have been dropped" + exit 1 + fi + if echo "$CONFIG" | grep -q "/var/run/secrets/kubernetes.io/serviceaccount/token"; then + echo "service account token path should have been dropped" + exit 1 + fi
tests/e2e-targetallocator/targetallocator-prometheuscr-denyfs/chainsaw-test.yaml+36 −0 added@@ -0,0 +1,36 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: targetallocator-prometheuscr-denyfs +spec: + steps: + - name: Setup Target Allocator RBAC + use: + template: ../../step-templates/target-allocator-rbac-comprehensive.yaml + with: + bindings: + - name: clusterRoleName + value: targetallocator-prometheuscr-denyfs + - name: clusterRoleBindingName + value: (join('-', ['ta', $namespace])) + - name: step-00-install-collector-with-deny + try: + - apply: + template: true + file: 00-install.yaml + - assert: + file: 00-assert.yaml + catch: + - podLogs: + selector: app.kubernetes.io/managed-by=opentelemetry-operator + - name: step-01-verify-unsafe-dropped-safe-kept + try: + - apply: + file: 01-install.yaml + - assert: + file: 01-assert.yaml + catch: + - podLogs: + selector: app.kubernetes.io/component=opentelemetry-targetallocator
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
3News mentions
0No linked articles in our index yet.