Skip to content

fix: the operator's metrics reach nothing, and two comments say otherwise - #184

Merged
stxkxs merged 1 commit into
mainfrom
fix/operator-metrics-scrape
Aug 8, 2026
Merged

fix: the operator's metrics reach nothing, and two comments say otherwise#184
stxkxs merged 1 commit into
mainfrom
fix/operator-metrics-scrape

Conversation

@stxkxs

@stxkxs stxkxs commented Aug 8, 2026

Copy link
Copy Markdown
Member

The defect

Five alert rules and the whole agent-operator dashboard read controller-runtime metrics from the eks-agent-platform operator. Those metrics have never reached AMP, because nothing discovers the operator.

charts/operator serves /metrics over HTTPS behind controller-runtime's authn/authz filter whenever metrics.secure is true — the chart default, overridden nowhere. The chart then suppresses its own prometheus.io/scrape annotations while secure, deliberately, because an annotation scrape is plaintext and unauthenticated and that endpoint rejects it.

Rendering the chart against this repo's values emits zero scrape annotations.

Every candidate path is closed:

path why it doesn't carry
otel-agent annotation job annotation-gated; the operator has no annotations
chart's ServiceMonitor this fleet installs prometheus-operator-crds and no controller that consumes one
AMP managed scraper none exists

Two comments in this repo asserted the opposite as fact — that metrics "reach AMP via the operator pod's prometheus.io/scrape annotation". Both are corrected here. A comment describing a wiring that does not exist is the same defect as the wiring being absent, and harder to find, because it answers the question a reader would otherwise go and check.

(This is partly self-announcing: OperatorMetricsAbsent, severity page, fires on exactly this condition. It was the gap being silent in the docs, not in the alerting.)

The fix

A dedicated scrape job on the otel-agent taking the authenticated route: HTTPS, the agent's own ServiceAccount token as bearer credential, TLS verification skipped because controller-runtime generates a self-signed cert in memory — there is no CA to pin, and the token is what gates access. Same reasoning the chart's own ServiceMonitor records.

No new grant is needed, and that is worth stating precisely rather than assuming. The endpoint authorizes with a TokenReview plus a SubjectAccessReview on the /metrics nonResourceURL, and this collector's ClusterRole already carries:

- nonResourceURLs: ["/metrics", "/metrics/cadvisor"]
  verbs: ["get"]

So the agent presents its own token rather than mounting the chart's metrics-reader Secret — which lives in another namespace and could not be mounted anyway.

metrics.secure stays true. Setting it false at this layer would have been one line and would have reopened exactly the info-disclosure gap the chart closed on purpose.

Discovery is namespace- and node-scoped, matching every other job here, so each operator pod is scraped exactly once by the agent co-located with it. The container-port keep is not cosmetic: pod discovery yields one target per declared container port, so without it the agent would also scrape the probe port on 8081 and log a failure every interval.

Verified

Rendered collector chart 0.166.0 against the committed values and extracted the emitted config — the job is present with the intended scheme, token file and relabel set:

jobs: ['kubernetes-pods', 'cadvisor', 'kube-state-metrics', 'hubble', 'eks-agent-platform-operator']

Those scrape configs then passed promtool check config. The check was itself checked — injecting an invalid relabel action makes promtool exit 1 with unknown relabel action "bogus_action", so the pass means it parsed something rather than skipping.

task validate passes.

What this does not do

It does not make the four latency burn rules correct — they were fixed separately in #181. It makes them able to evaluate at all. Whether the reconcile rate clears the minimum-traffic gate added there is now an observable question rather than a theoretical one.

https://claude.ai/code/session_012iMnbboJuiUMSvu7n8oRhz

…wise

Five alert rules and the whole agent-operator dashboard read controller-runtime
metrics from the eks-agent-platform operator. Those metrics have never reached
Amazon Managed Prometheus, because nothing discovers the operator.

charts/operator serves /metrics over HTTPS behind controller-runtime's
authentication and authorization filter whenever metrics.secure is true, which
is the chart default and is overridden nowhere. The chart then suppresses its
own prometheus.io/scrape annotations while secure — deliberately, because an
annotation scrape is plaintext and unauthenticated and that endpoint rejects it.
Rendering the chart against this repo's values emits zero scrape annotations.

The otel-agent's only pod job is annotation-gated, so it never sees the
operator. The chart also renders a ServiceMonitor for the authenticated path,
but this fleet installs prometheus-operator-crds and no controller that consumes
one, so it is read by nothing. There is no AMP managed scraper either. The
result is five rules and a dashboard wired to a metric that never arrives.

Two comments in this repo asserted the opposite as fact — that the metrics
"reach AMP via the operator pod's prometheus.io/scrape annotation". Both are
corrected here. A comment describing a wiring that does not exist is the same
defect as the wiring being absent, and harder to find, because it answers the
question a reader would otherwise go and check.

─────────────────────────── the fix ───────────────────────────

A dedicated scrape job on the otel-agent that takes the authenticated route:
HTTPS, the agent's own ServiceAccount token as the bearer credential, TLS
verification skipped because controller-runtime generates a self-signed cert in
memory and there is no CA to pin — the token is what gates access, which is the
same reasoning the chart's own ServiceMonitor records.

No new grant is needed, and that is worth stating precisely rather than
assuming: the endpoint authorizes with a TokenReview plus a SubjectAccessReview
on the /metrics nonResourceURL, and this collector's ClusterRole already carries
`nonResourceURLs: ["/metrics"], verbs: ["get"]` for the kubelet scrape. So the
agent presents its own token rather than mounting the chart's metrics-reader
Secret, which lives in another namespace and could not be mounted anyway.

metrics.secure stays true. Setting it false at this layer would have been one
line and would have reopened exactly the info-disclosure gap the chart closed on
purpose.

Discovery is namespace-scoped and node-scoped, matching every other job here, so
each operator pod is scraped exactly once by the agent co-located with it. The
container-port keep is not cosmetic: pod discovery yields one target per
declared container port, and without it the agent would also scrape the probe
port on 8081 and log a failure every interval.

Verified by rendering collector chart 0.166.0 against the committed values and
extracting the emitted config: the job is present with the intended scheme,
token file and relabel set. Those scrape configs were then checked with
`promtool check config`, which passes — and the check was itself checked by
injecting an invalid relabel action, which promtool rejects with
`unknown relabel action`, so the pass means it parsed something.
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

CI Results

Check Status
Zero-placeholder gate ✅ success
YAML Lint ✅ success
Dashboard gate (live grafana.com ids + AMG-saveable) ✅ success
Kyverno policy tests (+ verify-images contract) ✅ success
Fork-safety gate (no hardcoded org, blocking) ✅ success
Helm-render (every addon × every env) ✅ success
Policy-admission (Enforce-tier Kyverno vs the fleet) ✅ success
ApplicationSet schema + sync waves ✅ success
Appset render (Karpenter subnet selector) ✅ success
Secret scan (gitleaks) ✅ success
Render + assert + schema + misconfig (all environments) ✅ success

All checks passed.

@stxkxs
stxkxs merged commit f887241 into main Aug 8, 2026
20 checks passed
@stxkxs
stxkxs deleted the fix/operator-metrics-scrape branch August 8, 2026 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant