ProductDocumentationExamplesBlogRoadmapGitHubGet Started
Available

Auth & Security

API keys, bearer tokens, JWT/OIDC, fail-closed production mode, and the production checklist.

Krishiv supports four layers of authentication. Pick the right one for your topology, then verify that production mode (KRISHIV_PRODUCTION=1) is happy with the rest of your config.

1. API keys (Flight SQL and SQL API)

Static keys for short-lived clients and CI. Configure server-side:

# Comma-separated key=user pairs
export KRISHIV_API_KEYS="key1=alice,key2=ci-bot,key3="

Client-side:

krishiv sql --api-key key1 --query "SELECT 1"
import krishiv as ks
session = ks.Session.connect("http://coord:50051")
session.sql_as("key1", "SELECT 1")

API keys are intended for service-to-service auth, not for end users.

2. Bearer tokens (gRPC and HTTP management)

The default for production. Tokens are validated on every gRPC call and every /api/v1 HTTP call.

VariablePurpose
KRISHIV_COORDINATOR_BEARER_TOKENSingle static token. Set on the coordinator and on every client.
KRISHIV_COORDINATOR_BEARER_TOKEN_FILEFile path. Hot-reloaded when the file changes. Use for Kubernetes secrets mounted as files.
KRISHIV_COORDINATOR_BEARER_TOKENSComma/newline-separated list of accepted tokens. Use for rotation windows.
KRISHIV_COORDINATOR_BEARER_TOKENS_FILEFile with one token per line. Hot-reloaded.
KRISHIV_COORDINATOR_AUTH_RELOAD_INTERVAL_SECSHow often to re-read the file. Default: 60 s.
KRISHIV_EXECUTOR_TASK_BEARER_TOKENToken the executor presents to the coordinator's task-control gRPC.

Rotation

  1. Set KRISHIV_COORDINATOR_BEARER_TOKENS=<new>,<old> on the coordinator. Both are accepted.
  2. Roll clients to use the new token.
  3. Remove the old token from the list.

3. JWT / OIDC (SSO, end-user auth)

For end-user auth, plug in an OIDC provider. Krishiv validates the bearer token against a JWKS endpoint.

VariablePurpose
KRISHIV_OIDC_JWKS_URIOIDC JWKS URL. Set on the coordinator.
KRISHIV_OIDC_AUDIENCERequired in production. The aud claim must match.

Programmatic:

use krishiv_api::{Session, JwtAuthProvider};

let provider = Arc::new(JwtAuthProvider::new(jwks_url, audience));
let session = Session::connect("http://coord:50051")
    .with_auth(provider);

Roles: validate_grpc_auth / validate_grpc_auth_for_role enforce role-based access for management endpoints. Standard roles: admin, writer, reader.

4. UI bearer token

Separate from gRPC. Set KRISHIV_UI_TOKEN on the coordinator. The browser is prompted for the token; it is stored in localStorage and sent as Authorization: Bearer ... on every UI request.

/healthz always stays anonymous (so liveness probes work). All other UI routes require the token.

Production fail-closed

Set KRISHIV_PRODUCTION=1 (or any truthy value) to enable the production checks. The runtime will refuse to start, or refuse the offending command, if it detects:

CheckWhat it rejects
requires_http_authCoordinator or UI started without a bearer token in production.
requires_file_backed_stateState backend that is not RocksDB on local disk or a checkpointed object store.
allows_alpha_apiCalls to the alpha API surface (e.g. unbounded_memory_stream).
allows_memory_checkpoint_uriCheckpoint URI of memory:// or ephemeral://.
allows_unbounded_shuffle_storeShuffle store that has no upper bound (e.g. in-memory only).
forbids_simulation_connectorsConnectors marked as test/simulation in production.
profile_requires_durable_window_stateStateful streaming operators with non-durable state.
profile_requires_authenticated_flightFlight SQL exposed without auth.
profile_requires_authenticated_uiUI exposed without auth.
profile_requires_fail_closed_metadataMetadata store without fencing / leases.
profile_forbids_native_scalar_udfsNative scalar UDFs (which have full process access).
requires_manual_kafka_commitKafka sources where commits are not bound to checkpoints.
allow_legacy_task_fragmentsPre-R5 task fragment format.
allow_anonymous_http_overrideAnonymous HTTP enabled by an override env (only via ALLOW_ANONYMOUS_HTTP_ENV).

Policy hooks (table-level access control)

Beyond authentication, you can attach a PolicyHook to a session or to specific tables:

use krishiv_api::{Session, PolicyHook};

struct MyPolicy;
impl PolicyHook for MyPolicy {
    fn on_query(&self, q: &ParsedQuery) -> Result<(), PolicyError> {
        if q.references_table("pii") && !q.has_tag("allow_pii") { Err(PolicyError::Denied) }
    }
}
let session = Session::builder().with_policy(Arc::new(MyPolicy)).build().await?;

Production checklist

  • KRISHIV_PRODUCTION=1
  • KRISHIV_COORDINATOR_BEARER_TOKEN set (or OIDC configured)
  • KRISHIV_OIDC_AUDIENCE set if using OIDC
  • KRISHIV_UI_TOKEN set
  • KRISHIV_EXECUTOR_TASK_BEARER_TOKEN set on every executor
  • Checkpoint storage is an object store, not memory://
  • Durability profile is single-node-durable or distributed-durable
  • No anonymous HTTP overrides (KRISHIV_ALLOW_ANONYMOUS_HTTP=1)
  • No manual Kafka commit (requires_manual_kafka_commit)
  • OTLP tracing endpoint set (OTEL_EXPORTER_OTLP_ENDPOINT)

See also