kubectl access kill switch (runbook)¶
Document type: operational runbook Scope: disabling and re-enabling kubectl access platform-wide or per cluster at runtime (ADR-0016).
Controls¶
| Level | Endpoint | Who |
|---|---|---|
| Platform default | PUT/DELETE /api/v1/platform/feature-flags/kubectl_access.enabled |
platform admin (org_creator on platform:inari) |
| Cluster override | PUT/DELETE /api/v1/tenants/{org}/clusters/{id}/feature-flags/kubectl_access.enabled |
tenant admin/operator (clusters.register) |
PUT body: {"value": true|false}. DELETE reverts to the wider scope / built-in default (true).
Precedence¶
INARI_KUBECTL_ACCESS_ENABLEDexplicitly set in the environment → env wins; runtime writes are accepted but inert (API responses showenvPinned: true). The env is per-binary: it must be set on BOTH inari-server and inari-kubeproxy, or you recreate the split-brain (proxy 410s while access-info still reports enabled). The Helm valuekubeproxy.kubectlAccessEnabled(non-null) pins it on both deployments automatically; prefer it over hand-editing one Deployment.- Env unset → runtime flag: cluster override → platform default → built-in
true.
Effects and latency¶
- Off: proxy and kubeconfig return 410 ("kubectl access is disabled by platform policy"); new tunnel streams are rejected (
CodeUnavailable); live tunnel sessions are closed by the kubeproxyFlagWatcher. - Propagation: generation-bump invalidation is immediate with the redis cache backend; with per-process memory caches, convergence within
INARI_CACHE_FLAGS_TTL(default 10s), plus the watcher poll interval (~2s) for live-session teardown. - Re-enable: no agent restart needed — the tunnel agent's backoff loop reconnects on its own (worst case bounded by its backoff ceiling).
Examples¶
# Disable kubectl platform-wide
curl -X PUT -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"value": false}' \
https://$INARI/api/v1/platform/feature-flags/kubectl_access.enabled
# Disable one cluster only
curl -X PUT -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"value": false}' \
https://$INARI/api/v1/tenants/acme/clusters/clu-123/feature-flags/kubectl_access.enabled
# Revert cluster override (inherits the platform value again)
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
https://$INARI/api/v1/tenants/acme/clusters/clu-123/feature-flags/kubectl_access.enabled
# Inspect effective state
curl -H "Authorization: Bearer $TOKEN" https://$INARI/api/v1/platform/feature-flags
Audit¶
Every write appends featureflags.set / featureflags.cleared audit rows and a featureflags.updated outbox event with actor, scope, and value.
External flag UI (optional, Flipt)¶
The chart ships an optional Flipt subchart (Apache-2.0, built-in UI, OIDC login free in OSS, OFREP-native). Enable with flipt.enabled=true (or flagsProvider.url for a BYO OFREP endpoint) — the server Deployment then gets INARI_FLAGS_PROVIDER=ofrep pointing at the subchart service. The Flipt UI manages external-allowed platform product/rollout flags only; kubectl_access.enabled and any cluster-scoped flag stay DB-authoritative and keep being managed via the API above, never in Flipt. OIDC login for the Flipt UI is configured under flipt.flipt.config.authentication (Keycloak example in values.yaml).