Please do not open a public issue for security problems. Use GitHub's private vulnerability reporting on this repository (Security > Report a vulnerability), and include steps to reproduce and the affected version.
We aim to acknowledge reports within a few business days. Gryvia is early-stage software; fixes ship in the next release and are noted in the changelog.
Only the latest release on main receives security fixes.
Gryvia is alpha software. Read this before exposing it beyond a lab. It is written from the code; nothing here has been penetration tested, and the OIDC and tenant paths have only been tested against a fake identity provider.
- Two roles. The API key and the browser sessions issued by
POST /api/auth/loginare the provider admin: full control of every route, including tenants, SKUs, network and security data. There is only one such identity (admin), so no per-user attribution or audit trail exists for key-based sessions. OIDC users are tenant users, limited to the namespaces of theGryviaTenantobjects they match;GRYVIA_OIDC_ADMIN_GROUPS(chartapiGateway.oidc.adminGroups, empty by default) promotes a group to admin. Cluster-wide routes (nodes, network, security, GPU metrics) are admin-only. The route-by-route rules are in the API reference. - Tenant isolation is enforced by the gateway, not by Kubernetes RBAC. A
GryviaTenantcreates atenant-<name>namespace with a ResourceQuota, a LimitRange and (whennetworkPolicy.isolated) a NetworkPolicy. It creates no Role or RoleBinding. Anyone who has Kubernetes credentials that can read or writegryvia.ioobjects bypasses the gateway's filtering entirely, so do not hand tenants kubeconfigs for the provider cluster unless you add your own RBAC. - OIDC tenant matching trusts your identity provider's claims. The token's
orgclaim (or, when there is noorg, each entry ofgroups) is matched against tenant names andtenant-<name>namespaces. Whoever can set those claims at the provider can place a user in any tenant, and a group named like a tenant grants that tenant. Unmatched tokens get 403.apiGateway.oidc.legacyNamespaces=truerestores the old behaviour (the claim is a namespace) and takes effect only while noGryviaTenantexists; leave it off. Keep the signing-key, issuer and audience checks of your provider correct; the gateway validates signature, issuer, audience and expiry. - The admin sees one namespace for job routes. Job, workspace, workflow and similar routes read the gateway's
GRYVIA_JOB_NAMESPACE(the release namespace in the chart) for the admin; that is a convenience, not a security boundary, since the admin can read everything else through other routes orkubectl. - Metering is an estimate.
GryviaUsageRecordobjects are computed by the quota operator from job wall-clock time and are custom resources. Once a record is sealed (spec.final: true, set when its job finishes) a validating webhook (quotaOperator.usageRecordWebhook.enabled, on by default) rejects any change to itsspec, including clearingfinal; creates, deletes, labels and annotations are not checked. That protects a finished record from edits, not from being deleted and recreated by someone allowed to do both, and a running record can still be changed until it is sealed. Invoices are computed on demand from the records and there is no payment processing. - Admission checks fail open. The
GryviaAIJobvalidating webhook (webhook.failurePolicy=Ignoreby default) admits jobs when the operator is down, and its quota and catalog policy admits a job when the quotas cannot be read. The quota operator's reactive enforcement rejects a violating job shortly after. Setwebhook.failurePolicy=Failif you prefer to block instead. The usage-record webhook is the exception: its failure policy isFail, so while the quota operator is down, updates to usage records are rejected.
- Well-known lab default. Installs default to the key
Admin@321so a quick start works. The dashboard shows a warning while it is in use. Change it for anything reachable from an untrusted network:--set auth.apiKey=<secret>, an existing Secret, orauth.apiKey=""to generate a random one.scripts/deploy-remote.shkeeps the key that is already installed on a redeploy and uses the default only on a first install. - Login hardening.
POST /api/auth/logincompares credentials in constant time, slows failed attempts and is rate limited per client address (10 per minute). It returns a signed session token that expires after 8 hours (GRYVIA_SESSION_TTL_SECONDS), so the browser never stores the API key; rotating the key (orGRYVIA_SESSION_SECRET) ends all sessions. The signing key is derived from the API key (or the session secret) with PBKDF2-HMAC-SHA256. There is no server-side session revocation for a single session. - Rate limiting trusts
X-Forwarded-Foronly when the connecting peer is a private or loopback address.
- TLS. The dashboard and gateway serve HTTPS. The default certificate is self-signed; use
tls.mode=certManagerorexistingSecretfor a trusted one. Traffic between the dashboard and the gateway inside the cluster uses the same certificate without verification, so enable the chart'snetworkPolicy.enabledon shared clusters. - Netra. When
apiGateway.netra.urlis set, the gateway calls that URL with the optional bearer token; TLS verification is on unlessapiGateway.netra.insecureTLS(GRYVIA_NETRA_INSECURE=1) is set.
- Operators and gateway. They run with broad Kubernetes RBAC on the
gryvia.ioresources, nodes and pods (seehelm/gryvia/templates/rbac.yaml). Install Gryvia only on clusters where that is acceptable. - Containers. The operators, gateway and dashboard run as non-root with a read-only root filesystem, no privilege
escalation and all capabilities dropped; the TLS Secret is mounted with
fsGroup, so no init container needs root. - NVIDIA GPU Operator (
nvidia.enabled=true). The release namespace (gryvia-system) is labelledpod-security.kubernetes.io/enforce: privilegedbecause NVIDIA's driver and toolkit pods are privileged and mount the host. Those pods, and any other pod you run in that namespace, are then not restricted by Pod Security admission. Install the sub-chart into a dedicated namespace if that matters to you. This path has not been run on real GPU hardware.
- Privileged DaemonSet. The collector (
helm/network-intelligence,ebpf.enabled=true) runs as root, privileged, withhostPIDand, by default,hostNetwork. It loads kernel programs and reads process and connection data for the whole node. Its image is in the signed release workflow, but no tagged release has published it yet; until one does, you build and vouch for it yourself. - hostNetwork. With the default
collector.hostNetwork=trueits port 9090 listens on the node's addresses, and a pod NetworkPolicy does not apply. Use node firewall rules, or setcollector.hostNetwork=falsebefore relying on a policy. - Most endpoints are unauthenticated.
/metrics,/healthz,/api/v1/ebpf/status,/api/v1/graph,/api/v1/anomalies,/api/v1/fabric,/api/v1/security/alerts, the GPU, AI and tuning endpoints answer any caller that can reach the port. They expose job names, service names and traffic timing. Do not create a Service or Ingress for the collector and restrict who can reach port 9090. - Flight Recorder. Only
GET /api/v1/flight/diagnoseauthenticates: an HMAC-SHA256 over method, request URI and timestamp with a shared token (at least 32 characters), constant-time compared, valid for 30 seconds. The token is not sent, but a signed request can be replayed unchanged for up to 30 seconds by anyone who can observe it, the signature does not cover the host, and collectors use plain HTTP inside the cluster. The gateway sends signed requests to every Running pod labelledapp.kubernetes.io/component=collectorinapiGateway.flightCollectorNamespace, so anyone who can create pods in that namespace can receive them: keep it operator-only. Tenant callers ofGET /api/flight/jobs/{job}are limited to their tenant namespaces; job attribution trusts thegryvia.io/jobpod label, so anyone who can create pods in a namespace can label a pod into that namespace's timeline. Details and limits: docs/flight-recorder.md. - Programs that change traffic. The fabric-signal programs are observe-only.
packet_filter(an XDP rule map) andsockops_optimize(sk_msg redirect) can affect traffic when they are attached (-iface,-cgroup-path). A mutating program that would pace or throttle traffic for quota enforcement (sometimes called quota-pace) is not in this repository; no shipped program enforces quotas in the data path. - Verification. The programs were verifier-loaded on Linux 7.0 x86_64 only; arm64 is compile-only, and GPU, NCCL, RDMA and GPUDirect Storage behaviour has not been checked on hardware.
- Images and charts. Release images are signed with cosign (keyless) and carry SBOM and provenance attestations; the OCI Helm charts are signed with cosign. The eBPF collector image is part of the release workflow (each architecture built natively), but no tagged release has published it yet.
See Authentication and TLS for configuration.