Skip to main content
The kubernetes connector provides Kubernetes API access to self-managed clusters (k3s, kubeadm, k0s, on-prem, bare-metal, dev) that are not fronted by a cloud provider API. It discovers credentials from the local kubeconfig, exactly as kubectl does, and enforces the cluster’s own RBAC policy client-side before attaching any credential. Connector id: kubernetes For managed Kubernetes clusters on cloud providers, use the dedicated connectors instead:

Quick start

Run Cynative from an environment with a working kubeconfig for the target cluster (the same one kubectl uses):

Credential discovery

Credential sources

The connector discovers the kubeconfig exactly as kubectl does:
  • KUBECONFIG — a list of kubeconfig files client-go loads and merges (colon-separated on Unix, semicolon-separated on Windows) before falling back to ~/.kube/config. This is the sole targeting and discovery signal.
It selects the current-context and supports exactly two credential modes:
  • Static bearer token — users[].user.token, or users[].user.tokenFile (re-read per request, so a rotated ServiceAccount token is picked up).
  • Client certificate (mTLS) — users[].user.client-certificate[-data] plus users[].user.client-key[-data].
The connector fails closed and is not registered when the selected context uses an exec credential plugin, an auth-provider plugin, impersonation, basic-auth username/password, insecure-skip-tls-verify: true, or a proxy-url. This means typical cloud kubeconfig contexts (GKE/EKS/AKS use exec plugins such as gke-gcloud-auth-plugin) are intentionally rejected — use the dedicated eks, gke, or aks connectors for those clusters. It also fails closed on: a non-https scheme, a non-ASCII host (write internationalized names in punycode), an address literal carrying a zone identifier, a port outside 1–65535, or no usable bearer/client-cert credential. References:

Registration and validation

After parsing the kubeconfig, Cynative eagerly validates the cluster at startup with a dial-guarded GET /apis/rbac.authorization.k8s.io/v1/clusterroles/<configured-role> fetch before registering. The connector registers only if the cluster is reachable and the fetch succeeds. This contrasts with the managed connectors (eks, gke, aks), whose validation is gated on the parent-cloud credential and whose Kubernetes API is validated only on the first request.

Setup prerequisite: reading the ClusterRole

The configured identity must be allowed to read the configured ClusterRole (default view). The built-in view role does not include get clusterroles, so an identity bound only to view cannot read its own policy source. Grant read access explicitly:
In practice, cloud connector credentials often already carry the needed read access, so this prerequisite most often affects hand-crafted self-managed identities.

Target selection

The kubernetes connector targets the single cluster named by the local kubeconfig’s current-context. There is no Cynative-level override — the connector targets the one cluster the selected context names.
  • To target a different cluster file, set $KUBECONFIG.
  • To select a different context, run kubectl config use-context <name>.
Cloud-style contexts (GKE/EKS/AKS use exec plugins) are rejected fail-closed — use the dedicated managed connectors for those.

TLS server name (IP endpoints with DNS-only certificates)

When the cluster endpoint is an IP literal but its CA-issued serving certificate has only DNS Subject Alternative Names (no IP SAN), set clusters[].cluster.tls-server-name in the kubeconfig. Cynative honors it: the dial stays pinned to the IP, while TLS verification uses the configured server name.

Request usage

Use auth_provider: "kubernetes". kubernetes_auth is optional and empty — the connector targets the single configured cluster:
The request authority (host and port) must match the kubeconfig cluster server. A self-managed API server typically listens on port 6443, so a request that omits the port is rejected rather than sent to 443. Minimal example:

Hardening

RBAC authorization

Cynative fetches the cluster’s live configured ClusterRole (default view) once per cluster via GET /apis/rbac.authorization.k8s.io/v1/clusterroles/<name>, parses it into an allow-only RBAC policy, and caches it for the rest of the session. Each request is then classified the way the kube-apiserver classifies it — verb, API group, resource, subresource, namespace, name — and authorized against that policy before any credential is attached. Non-resource requests (such as /version, /healthz, or discovery paths) are allowed only when they are GET or HEAD in a small, safe read-only allow-set. If the ClusterRole cannot be fetched or parsed, Cynative fails closed and denies every request.

Host and port pinning

The request host and port must both equal the configured cluster endpoint’s. The port is checked separately because the host check receives a port-stripped hostname and the dial guard sees only an IP — without a port check a request could reach a different TLS listener on the same address.

Dial-time IP authorization

The dialed IP must pass the shared forbidden-address floor (loopback, link-local, cloud metadata, IPv6 ULA are always rejected) and then match the endpoint pin: an IP-literal endpoint pins to that exact address; an FQDN endpoint is re-resolved per dial and the dialed IP must be in the resolved set. RFC1918 private addresses are allowed (on-prem clusters legitimately use them).

Credential injection

Model-supplied credentials are rejected before injection: requests carrying an Authorization, Proxy-Authorization, or X-Ms-Authorization-Auxiliary header, or URL userinfo (user:pass@), fail closed. Cynative attaches the bearer token (or presents the client certificate for mTLS) only after host and RBAC authorization pass.

Cynative configuration

The authorization ClusterRole is configurable (default view):
The configured identity must be able to read whichever ClusterRole you select (get clusterroles/<name>). Widening past view widens Cynative’s permitted verbs — including writes. The configured ClusterRole is shown in the startup inventory, for example:
  • access=default(read-only) when the ClusterRole is view; access=custom for any other ClusterRole.
  • enforced=client — Kubernetes decouples authn from authz; the in-process ClusterRole-based authorization check is the sole client-side control.
  • The trailing value is the API-server authority from the kubeconfig server — https:// plus that value is the base URL requests must use.

Defense at a glance

Managed Kubernetes connectors

For managed Kubernetes services, Cynative provides dedicated connectors that resolve cluster credentials and endpoints from the cloud provider API: All four Kubernetes connectors (including kubernetes) share the same RBAC authorization model, host/port pinning, dial-time IP authorization, and response redaction described in this page.

Limitations

  • The gate trusts the fetched role. Cynative enforces exactly the rules of the configured ClusterRole and adds no independent mutation-verb floor. Kubernetes’ built-in view is an aggregated role (rbac.authorization.k8s.io/aggregate-to-view), so if an administrator has aggregated write rules into view, Cynative honors them. For least privilege, point the connector at a dedicated, non-aggregated read-only ClusterRole.
  • The configured identity must be able to read the configured ClusterRole — see Setup prerequisites above.
  • Only static bearer-token and client-certificate (mTLS) credentials are supported. Exec credential plugins, auth-provider plugins, insecure-skip-tls-verify, and proxy-url are deliberately rejected.
  • One cluster per run (the selected context). Multi-cluster selection is not supported in this version.
  • A server URL carrying a path prefix (as some managed-cluster proxies emit) has that prefix dropped; such a cluster is not supported.
  • Credential rotation: a bearer tokenFile is re-read per request, but a rotated literal token or rotated client certificate requires re-running Cynative.
  • IDNA / internationalized hosts are not supported — write the hostname in punycode so the name Cynative pins is the name it dials.
  • RFC1918 dials are allowed (on-prem clusters legitimately use private addresses), but loopback, link-local, cloud metadata addresses, and IPv6 ULA remain unconditionally denied.
  • There is no client-side credential downscoping. Kubernetes decouples authentication from authorization; the in-process ClusterRole gate, host pinning, and dial-time IP authorization are the only client-side controls.