Repository navigation
feat(prometheus-stack): guard Prometheus, Alertmanager and exporters behind authentication - #67
Open
Hanson-Tsai wants to merge 17 commits into
Open
Hanson-Tsai wants to merge 17 commits into
Hanson-Tsai wants to merge 17 commits into
Conversation
Prometheus and Alertmanager listen on 127.0.0.1 behind a kube-rbac-proxy sidecar (Services move to 9091 and 9095); kube-state-metrics and node-exporter turn on their subcharts' kubeRBACProxy. One cert-manager CA signs the four guards and Prometheus scrapes and alerts through them with its ServiceAccount token (OTTERSCALE-288). BREAKING CHANGE: Prometheus is no longer reachable on :9090. Clients need a token authorized for prometheuses/api and the CA in prometheus-stack-kube-prom-prometheus-tls, on :9091. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Under listenLocal config-reloader binds to localhost, but kube-prometheus-stack renders a reloader-web endpoint unconditionally in the Prometheus and Alertmanager self-monitoring ServiceMonitors. Drop it by relabeling instead of relying on how an unresolvable port behaves (OTTERSCALE-288). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…cs path The agent now queries prometheus-stack's kube-rbac-proxy with its own ServiceAccount token (OTTERSCALE-288). Bind it get/create on prometheuses/api for the Prometheus and get on the Secret holding the proxy's CA, and pass the URL and Secret explicitly instead of relying on the binary's defaults. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The kube-state-metrics chart's readiness probe targets the port named "metrics", which only the selfMonitor guard declares, so with kubeRBACProxy alone the pod never became Ready. Enable selfMonitor and scrape both the http and the telemetry endpoint through their guards (OTTERSCALE-288). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The kube-state-metrics subchart hardcodes probes on the named ports http and metrics, but with kubeRBACProxy the main container declares no ports and kubelet resolves a named probe port only against the probed container, so the pod never became Ready. Use KSM's --auth-filter (TokenReview and a SubjectAccessReview on nonResourceURL /metrics) plus --tls-config with a web-config ConfigMap instead, serving the same cert-manager certificate (OTTERSCALE-288). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… external URLs, upgrade notes Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
otterscale-agent ships otterscale:metrics-cluster-view (get prometheuses/api), bound to nobody, for cluster-scope metrics through the OtterScale server. kubevirt 1.1.2 keeps VMI namespace labels (honorLabels) so VM metrics land in the VM's namespace. Render tests run in CI. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…server checks The role's resourceNames followed metrics.prometheusName while the server always checks monitoring/prometheus-stack-kube-prom-prometheus: an override silently broke every binding to the role, and an http prometheusURL with an empty name rendered resourceNames: [""]. The rule is now the server's fixed attribute, and the values comment says that prometheusName moves only the agent's own grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ubuntu-latest's system Python is externally managed (PEP 668), so a bare pip install can refuse to run. setup-python is pinned to an exact release like setup-helm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- listenLocal makes the operator's probes exec sh in the container - the subchart's default -distroless image has no shell, never ready - pin quay.io/prometheus/prometheus:v3.14.0 and fix the comment - keep renovate from moving that image to a -distroless tag - move the guard render tests into tests/ and run them in make test - check that a listenLocal Prometheus does not run a distroless image - fetch the prometheus-stack subchart for make test and in ci
- split the prometheus clusterrole rule by resource - prometheuses/api gets get only, enough for scraping itself - alertmanagers/api keeps get and create for scraping and alerts - its token can no longer post /-/reload or /-/quit through the guard - test that scrape and alert verbs stay and create on itself is gone
- fail on kube-state-metrics and node-exporter namespaceOverride - their -tls certificate and web-config stay in the release namespace - fail when prometheus or alertmanager runs as another serviceaccount - the auth-delegator binding names the default ones - mirror the subchart helper so create=false falls back to default - naming the default account explicitly still renders
- an empty url did not disable the metrics proxy - the agent reads an empty env var as unset and uses its default - fail at render time instead and test it
- system:authenticated includes every serviceaccount - any pod could then query prometheus directly through the guard - point to an oidc:-prefixed group for opening it to all users
- remove the ticket key and a private release id from values comments - say why an override restates the sidecar list instead - state the config-reloader trade-off without citing a private spec
- honorLabels changes what namespace means on vm metrics - exported_namespace goes away, so this is not a patch release
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Jira: OTTERSCALE-288. Any Pod in the cluster can read prometheus-stack directly today, a tenant's Pod included:
:9090: every namespace's metrics.:9093: including silence creation.:8080: resource names across namespaces.:9100on each node.This PR puts an authenticating, authorizing guard in front of each of them, in the chart defaults, so Dashboard installs on external clusters and open-source users get it too.
prometheus-stack 1.1.0 → 1.2.0
:9090listenLocal, plus a kube-rbac-proxy sidecar on https:9091get/createonmonitoring.coreos.comprometheuses/api:9093listenLocal, plus a kube-rbac-proxy sidecar on https:9095alertmanagers/api:9100on the hostkubeRBACProxyon:9100; the exporter moves to127.0.0.1:8100getservices/prometheus-stack-prometheus-node-exporter:8080--auth-filterplus--tls-config/metricsgettemplates/kube-rbac-proxy-tls.yaml) signs all four serving certs.ca.crt+serverName).system:auth-delegator.getonprometheuses/api(to scrape itself) andget/createonalertmanagers/api(to scrape and send alerts) viaadditionalRulesForClusterRole. It has nocreateon its own API, so its token cannot POST/-/reloador/-/quitthrough the guard.externalUrlis https, so alert links work.listenLocal. Its metrics and theConfigReloaderSidecarErrorsalert are given up; the dead scrape endpoints are dropped by relabeling.validate.yamlrefuses to render if any of these is changed, because the guard wiring hardcodes them:prometheus-stack;monitoring;namespaceOverrideon kube-state-metrics or node-exporter;quay.io/prometheus/prometheus:v3.14.0. WithlistenLocal, the operator's probes runsh -c, and the upstream default-distrolessimage has no shell, so Prometheus would never become Ready. A renovate rule keeps the tag off-distroless.Why KSM is not behind kube-rbac-proxy. In the subchart's
kubeRBACProxymode, the KSM container declares no ports, but its liveness and readiness probes namehttpandmetrics. kubelet resolves probe port names per container, so the pod never becomes Ready (strconv.Atoi: parsing "http"). This is the case in the bundled 8.4.2 and in the latest 8.6.0. KSM's built-in--auth-filterdoes the same TokenReview + SubjectAccessReview (controller-runtimeWithAuthenticationAndAuthorization) on/metrics, and leaves/livez//readyzopen.otterscale-agent 1.1.2 → 1.2.0
<release>-metrics:get/createonprometheuses/apifor the Prometheusgeton the CA Secret, restricted byresourceNamesIt is a ClusterRole rather than a Role because
monitoringmay not exist yet when the agent is installed.metrics.{prometheusURL,prometheusName,caSecret}, passed to the agent as env. An emptymetrics.prometheusURLfails rendering: the agent would treat an empty env as unset and use its default.otterscale:metrics-cluster-view:getonprometheuses/apifor that Prometheus. It is the same attribute the guard checks and the hub's cluster scope asks about (feat: guard metrics in the cluster and authorize them per scope at the hub otterscale#310). Bind it to give someone cluster-wide metrics without cluster-admin. Do not bind it tosystem:authenticated: that includes every ServiceAccount, so any Pod could then query Prometheus directly. Bind anoidc:-prefixed group instead.kubevirt 1.1.1 → 1.2.0
honorLabels: true, so a VM metric'snamespaceis the VM's own, notkubevirt. The hub's namespace scope and the new dashboard select VM metrics bynamespace.exported_namespaceis gone), hence a minor bump. Upgrade it together with the new hub and dashboard: an old dashboard readsexported_namespace.:9090is gone. Use https:9091with a token authorized as above, and the CA from Secretprometheus-stack-kube-prom-prometheus-tls.:9093to:9095.The details are in
templates/NOTES.txt. Should this be 2.0.0 instead of 1.2.0?🚧 Draft: do not merge yet
release.ymlpublishes every new chart version on push tomain. The agent chart's defaultimage.tagis stillv1.5.0, and that agent cannot use the https path, so the dashboards would be empty. No token leaks: v1.5.0 sends none.otterscale-agentappVersionandimage.taghere to that release.Testing
make testruns the render tests now committed undertests/(also in CI,.github/workflows/test.yml): 26 checks.listenLocalis on;kube-prometheus-stack.enabled=false;metrics-cluster-view, and the kubevirt PodMonitor.make testbuilds the prometheus-stack subchart dependency when it is missing.helm lintpasses on prometheus-stack, otterscale-agent and kubevirt.:9090/:9093refuse connections. All four guards return 401 without a token and 403 with the Pod's own token.upover https. Watchdog reaches Alertmanager over https:9095.Related
🤖 Generated with Claude Code