Authentication Configuration

September 22, 2026 · View on GitHub

Operator reference for how health-event publishers authenticate to platform-connector: who may submit health events, and about which node.

The older docs/platform-connectors.md predates these changes and describes the previous behaviour. Where it disagrees with this document, this document is correct.


Health-event publishers (platform-connector)

global:
  platformConnectorAuth:
    enabled: true
    mode: enforce
    failOpenOnUnavailable: false
    audience: "platform-connector.nvsentinel.nvidia.com"
    tokenExpirationSeconds: 3600
    tokenMountPath: "/var/run/secrets/nvsentinel/platform-connector"
    crossNodeServiceAccounts: []

enabled

Must be a real YAML boolean and must be set explicitly — there is no default. A quoted "false" is refused rather than read as true, and null or 0 is refused rather than silently disabling enforcement. The connector also refuses to start if the ConfigMap omits the key, so an old chart driving new images fails loudly instead of guessing whether authentication is required.

Disabling this lets any caller that can reach the connector's socket submit an event naming any node. It is not a supported production configuration.

mode

enforce (default) rejects a request that violates the node-binding rule. audit validates every request and increments the same platform_connector_auth_violations_total counters by reason, but lets the request through instead of rejecting it.

Use audit to roll node-binding out against real traffic: run it for a period, confirm the violation counters stay at zero, then switch to enforce with evidence rather than finding out what it breaks in production. audit still requires enabled: true, and every request is still validated: a validator failure (including validator_unavailable and validator_timeout) is still recorded, it just no longer rejects the request. audit changes what happens after a violation is detected, not whether requests are checked.

One rejection is not affected by mode: an event with no node name from a caller resolved to verified cross-node scope (missing_node_name) is always rejected, in both audit and enforce. Nothing downstream can handle an empty node name, so forwarding that event would not be a useful preview of what enforce would do — it would just be an event enforce could never have produced, sitting in the datastore. This does not cover a caller that fell back to a degraded node-local scope under failOpenOnUnavailable: its identity was never verified as cross-node in the first place, so a blank name from it is stamped like any other node-local caller's — see failOpenOnUnavailable.

failOpenOnUnavailable

Distinguishes a validator that never reached a verdict from one that reached a verdict and rejected the credential. validator_unavailable and validator_timeout (the API server was unreachable, or the call timed out) say nothing about the caller — they are not evidence of a forged token, only of the validator's own availability. token_invalid (a rejected or malformed credential) does say something about the caller and is always rejected under mode: enforce, regardless of this setting.

Defaults to false: an unreachable validator rejects the request, matching behaviour before this setting existed. Set true to fall back to a degraded node-local scope instead — a guess, not a verified identity — so that a control-plane blip degrades publishers to their own node rather than blocking their health events outright:

  • An event with a blank or matching node name is accepted and stamped exactly as a verified node-local caller's would be, in either mode. This is the common case the setting exists for: most publishers present a token but leave the node name blank for platform-connector to fill in.
  • An event naming a different node is handled according to mode. Under mode: enforce it is refused as retryable Unavailable — the same code the validator itself returned — rather than as node_mismatch / PermissionDenied. The caller might really be an allowlisted cross-node publisher the outage prevented from being verified, not an actual mismatch, so it is not counted as node_mismatch (one of the reasons an operator would alert on as suspected credential abuse) and not rejected in a way publishers treat as non-retryable; it is retried once the validator recovers instead of being dropped for good. Under mode: audit that same Unavailable is what gets recorded and then let through by auditOrReject like any other violation, so the event is forwarded with whatever node name it carried.

audience

The single audience every publisher's token is minted for, and that platform-connector requires TokenReview to echo back in status.audiences. A token issued for a different service is not accepted.

tokenExpirationSeconds

Token lifetime. Kubernetes rejects a projected token lifetime below 600 seconds or above 2322^{32}, and rejects fractional values, so the chart enforces 600 <= x <= 4294967296 and whole numbers at render time rather than letting the API server reject the pod at creation.

tokenMountPath

Directory each publisher mounts the token at; the file is <mountPath>/token.

crossNodeServiceAccounts

Additional canonical usernames permitted to report health events about nodes other than the one they run on. Every entry grants the ability to have any node in the cluster cordoned, drained and rebooted — add sparingly.

The bundled cluster-scoped monitors — csp-health-monitor, kubernetes-object-monitor, nvcre-certification-monitor, slurm-drain-monitor and health-events-analyzer — are derived from the release namespace for whichever of them are enabled. They do not belong in this list, and installing into a namespace other than nvsentinel needs no edit.

List only publishers this chart does not ship. Entries are matched verbatim against the username TokenReview reports:

  • form system:serviceaccount:<namespace>:<name>
  • namespace: DNS-1123 label, ≤63 characters
  • name: DNS-1123 subdomain, ≤253 characters
  • no leading, trailing or internal whitespace; no uppercase

Nothing is trimmed or normalised for you. An entry that does not match exactly can never equal a real username, so the chart and the connector both reject it rather than accepting a rule that silently matches nothing.

Omitting the key means "no additional callers". Writing null is refused, because null and "none" are not the same statement.

The per-caller rule

A caller presenting a token is asked two independent questions.

1. Is the token being presented where it was issued? If it carries a node claim, that claim must name this connector's own node — for every caller, allowlisted or not. Rejected as node_claim_mismatch.

2. May this identity name other nodes? Only if it is on the allowlist. Otherwise it is pinned to the connector's node, and an event naming another node is rejected as node_mismatch.

An allowlisted caller must also present a token bound to a running pod on a scheduled node. kubectl create token <sa> --audience=… without --bound-object-ref produces a token with neither claim; it is refused for own-node events too, not merely downgraded.

Callers presenting no token are accepted and pinned to the connector's node. Reaching the socket already granted that much.

Where to run cross-node monitors

Their pods hold a credential platform-connector accepts for any node name. Run them on a system or control-plane node pool rather than GPU nodes serving tenants, using whichever of nodeSelector, affinity or tolerations your cluster already uses.

Metrics

MetricLabelsMeaning
platform_connector_auth_decisions_totaldecision = node_local | cross_nodeScope granted to a batch.
platform_connector_auth_violations_totalreason (below)Batches that violated the node-binding rule. Under mode: enforce these are rejected; under mode: audit they are recorded but let through.
platform_connector_auth_node_claim_totalresult = verified | absentWhether the token carried a node claim.

reason values:

ReasonMeaning
node_mismatchA node-local caller named a different node.
node_claim_mismatchThe token was issued on another node.
unbound_cross_node_tokenAn allowlisted caller presented a token bound to no pod.
cross_node_claim_absentPod-bound, but the pod was never scheduled.
token_missingDeployment platform connector only: the caller presented no token. There is no local node to pin a tokenless caller to.
unbound_tokenDeployment platform connector only: the token is bound to no pod.
node_claim_absentDeployment platform connector only: the token is bound to a pod that never scheduled, so there is no node to pin its events to.
missing_node_nameAn event carried no node name and none could be stamped.
token_invalidTokenReview rejected the token.
malformed_credentialsThe authorization header was duplicated, or did not use the Bearer scheme. On the node-local socket a completely absent header is not a violation — that caller is accepted and pinned to the connector's node; on the deployment platform connector it is counted as token_missing.
validator_unavailable / validator_timeout / validator_errorThe API server could not be reached, or returned no identity. With failOpenOnUnavailable: true, validator_unavailable and validator_timeout still increment this counter but fall back to a degraded node-local scope instead of rejecting the request — see failOpenOnUnavailable for how that scope treats a blank vs. a differently-named node.

A healthy cluster reports zero violations. A sustained non-zero validator_unavailable is an API-server problem, not a caller problem.


Migration

OldNew
crossNodeServiceAccounts listing the bundled monitorsRemove them; they are derived from the release namespace.

Upgrade the chart and the images together. New images against an old chart do not start: the connector requires enableNodeBindingAuth to be present, and an old chart does not write it.

Deployment platform connector

The deployment platform connector reads the same node-binding settings as the DaemonSet, from the same config.json: enableNodeBindingAuth, AuthAudience and AuthCrossNodeServiceAccounts mean exactly what they mean above, and node binding must be enabled for it (the connector refuses to start otherwise). One thing differs because it has no local node: every caller must present a token, bound to a running pod on a scheduled node. The node named in that token is the node the caller may report on; the cross-node list is the only way to name other nodes. AuthMode: audit and AuthFailOpenOnUnavailable are socket settings: with no node to fall back on, the deployment platform connector always enforces, and logs a warning when either is set.

Both roles read one AuthAudience, so a monitor's token stays valid when it switches from the socket to the Deployment; how the chart projects that token for a publisher is described with the chart.