Files
OpenShell/deploy/helm/openshell/values.yaml
5548405fcb feat(credentials): add provider credential storage drivers (#2437)
* feat(credentials): add provider credential storage drivers

Signed-off-by: Taylor Mutch <taylormutch@gmail.com>

* fix(credentials): harden credential update handling

Signed-off-by: Taylor Mutch <taylormutch@gmail.com>

* fix(credentials): harden credential driver security, correctness, and performance

Address review findings from the credential storage drivers PR:

- Route additional_credentials through the driver on refresh to prevent
  silent data loss for multi-credential providers (e.g. AWS STS)
- Clean up stored credential handles on CAS failure during refresh to
  prevent orphaned secrets in external backends
- Enforce namespace validation in the Kubernetes Secrets driver to
  prevent cross-namespace credential access when allow_reference_namespace
  is not enabled
- Cache Vault Kubernetes auth tokens with 80% TTL to avoid re-authenticating
  on every credential operation
- Parallelize resolve_credentials in all three drivers using try_join_all
  for faster sandbox startup
- Add existingSecret support for the KEK Secret to fix helm template/GitOps
  workflows where lookup returns empty and regenerates the key
- Document RBAC blast radius for the Kubernetes Secrets credential driver
  and recommend a dedicated namespace

Signed-off-by: Varsha Prasad <varshaprasad96@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>

* fix(credentials): add optimistic concurrency, fix thundering herd, parallelize operations

Use resourceVersion optimistic concurrency with retry loop for K8s
Secret ownership checks to prevent TOCTOU races. Switch Vault token
cache from RwLock to Mutex with double-check pattern to prevent
thundering herd on cache miss. Parallelize credential store and delete
operations across independent keys using try_join_all.

Signed-off-by: Varsha Prasad <varshaprasad96@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>

* fix(credentials): handle partial failures, add delete retry, consolidate cleanup

Replace try_join_all with join_all in credential store/delete operations
to handle partial failures — successfully-stored handles are cleaned up
when another key fails. Add retry loop with conflict detection to
db-credstore delete_credential, matching the K8s driver pattern.
Consolidate 4 manual cleanup_pre_stored_provider_credentials call sites
into a single error handler using an async block. Remove inconsistent
.trim() from db-credstore validate_handle_owner.

Signed-off-by: Varsha Prasad <varshaprasad96@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>

* fix(credentials): fix retry loop guard and remove unprotected validation

Remove attempt-count guard from 409/Aborted match arms in retry loops
so the post-loop Status::aborted error is reachable after exhausting
retries. Previously, last-attempt conflicts fell through to the
catch-all error arm, producing misleading Status::unavailable errors.

Remove duplicate validation calls that ran after
prepare_provider_credential_update but outside the cleanup-protected
async block, which would leak pre-stored handles on failure.

Signed-off-by: Varsha Prasad <varshaprasad96@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>

* fix(credentials): add workspace/provider UUID to credential backend paths

Include workspace and provider ID in credential backend object paths to ensure
cross-workspace uniqueness and prevent credential collision (GATOR-1806c9be-01).

- Updated credential driver proto to include workspace and provider_id fields
- Modified Vault driver to include workspace/provider_id in managed_secret_path
- Modified Kubernetes Secrets driver to include workspace/provider_id in
  credential_owner_id and managed_secret_name
- Updated all credential runtime calls to pass workspace/provider_id
- Updated tests to use the new signatures

This prevents two workspaces sharing the same external credential store from
colliding on provider names, which was a critical security issue (CWE-639).

* fix(credentials): preserve provider-level expiration for handle-backed credentials

Compute effective expiration from both provider and driver values using the
earliest non-zero timestamp and skip expired values before insertion
(GATOR-1806c9be-02).

- Modified resolve_provider_handles to check provider credential_expires_at_ms
- Skip expired credentials during resolution instead of returning them
- Use effective expiration (min of provider and driver) in resolution results
- Fix inference.rs to preserve earliest expiration when merging

This ensures handle-backed credentials respect the same expiration semantics
as inline credentials.

* fix(credentials): stage refresh changes under new handles before validation

Stage credential replacements under new immutable handles instead of reusing
existing handles to prevent overwriting committed values before validation/CAS
(GATOR-1806c9be-03).

- Stage credentials with empty existing_handles map to force new handle creation
- Validate and CAS before the new values are committed to backend storage
- Delete old handles only after successful CAS
- On CAS failure, delete only the newly staged handles
- This prevents CWE-362/CWE-367 race conditions where failed refreshes could
  still modify or delete the active credential

The fix ensures that a rejected refresh cannot modify the backend object still
referenced by the committed provider record.

* fix(credentials): add timeouts to credential driver RPCs

Apply configured timeouts to both startup capability negotiation and runtime
RPCs to prevent indefinite hangs (GATOR-1806c9be-05).

- Add DEFAULT_CREDENTIAL_DRIVER_RPC_TIMEOUT_SECS constant (30s)
- Apply timeout to GetCapabilities during startup connection
- Apply timeout to all runtime RPCs (store, delete, resolve)
- Use tokio::time::timeout to bound the entire GetCapabilities operation
  during startup, not just the socket connection
- Return contextual deadline errors on timeout

This prevents a faulty or overloaded driver from hanging gateway operations
indefinitely.

* fix(credentials): fix test to use consistent workspace/provider identity

The Kubernetes auth Vault resolve test was constructing a managed path with
test-workspace/test-provider-id but sending default/prov-123 in the request,
causing validation to reject the request (GATOR-18e32351-01).

- Update test to use test-workspace and test-provider-id in the request to
  match the logical_path construction
- This ensures the test exercises the intended code path and validates
  Kubernetes auth resolution properly

The test now passes and correctly validates identity enforcement.

* fix(credentials): use unique staging ID for refresh to avoid overwrites

Stage refresh replacements under genuinely distinct immutable handles using
a unique staging ID to prevent overwriting committed values (GATOR-1806c9be-03).

- Generate a unique staging ID using UUID for each refresh operation
- Use this staging ID when storing credentials instead of the real provider ID
- Pass the same staging ID during cleanup on failure to delete only staged objects
- This ensures deterministic paths (Vault) and object names (K8s) don't collide
  with the committed provider's credentials

The fix prevents failed refreshes from silently replacing active credentials
or breaking providers by deleting still-referenced backend objects.

* fix(credentials): wrap credential driver RPCs in local timeouts

Add local tokio::time::timeout wrappers around credential driver RPCs to
bound non-compliant or stalled UDS peers (GATOR-1806c9be-05).

- Wrap StoreCredential, DeleteCredential, and ResolveCredentials in local timeouts
- Return contextual deadline_exceeded errors when timeouts occur
- Keep existing gRPC timeout metadata for compliant implementations
- GetCapabilities during startup was already wrapped in previous commit

This ensures a faulty local driver cannot hang gateway operations indefinitely,
even if it accepts the connection but never responds to the RPC.

* fix(credentials): preserve ownership for staged refreshes

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* fix(credentials): bound startup capability probe

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* test(provider): authenticate credential handler requests

Signed-off-by: Seth Jennings <sjenning@redhat.com>

* fix(ci): grant actions read to credential driver e2e

Signed-off-by: Seth Jennings <sjenning@redhat.com>

---------

Signed-off-by: Taylor Mutch <taylormutch@gmail.com>
Signed-off-by: Varsha Prasad <varshaprasad96@gmail.com>
Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
Signed-off-by: Seth Jennings <sjenning@redhat.com>
Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
Co-authored-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
2026-08-05 16:29:41 +00:00

470 lines
22 KiB
YAML

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# Default values for OpenShell
# -- Number of OpenShell gateway replicas. Values greater than 1 require
# server.externalDbSecret because the default SQLite backend is per pod.
replicaCount: 1
workload:
# -- Gateway workload controller kind. Use `statefulset` for the default
# SQLite database, or `deployment` when server.externalDbSecret points at an
# external database.
kind: statefulset
# -- Allow replicaCount > 1 while rendering a StatefulSet. Prefer
# workload.kind=deployment for external database-backed multi-replica
# gateways; this override exists for operators who explicitly require
# StatefulSet identity or storage semantics.
allowMultiReplicaStatefulSet: false
image:
# -- Gateway image repository.
repository: ghcr.io/nvidia/openshell/gateway
# -- Gateway image pull policy.
pullPolicy: IfNotPresent
# -- Gateway image tag. Defaults to the chart appVersion when empty.
tag: ""
# Supervisor image for the openshell-sandbox binary injected into sandbox pods.
# The default repository and empty tag use the version-pinned image built into
# the gateway. Changing the repository or setting a tag enables a Helm override.
supervisor:
image:
# -- Supervisor image repository. Changing it uses the effective gateway image tag unless tag is also set.
repository: ghcr.io/nvidia/openshell/supervisor
# -- Supervisor image pull policy. Defaults to the gateway image pull policy when empty.
pullPolicy: ""
# -- Supervisor image tag override. Empty uses the version pinned into the gateway unless repository is changed.
tag: ""
# -- How the supervisor binary is delivered into sandbox pods.
# Empty (default) = auto-detect from cluster version:
# K8s >= v1.35 -> "image-volume" (ImageVolume enabled by default; GA in v1.36)
# K8s < v1.35 -> "init-container" (copies via init container + emptyDir)
# On K8s v1.33-v1.34 with the ImageVolume feature gate manually enabled,
# set this to "image-volume" explicitly.
sideloadMethod: ""
# -- Supervisor pod topology for Kubernetes sandboxes.
# "combined" runs the current single supervisor container in the agent pod.
# "sidecar" runs network enforcement in a dedicated sidecar and the process
# supervisor as a low-capability wrapper in the agent container.
topology: "combined"
sidecar:
# -- UID for relaxed long-running network sidecars in sidecar topology.
# Strict process/binary-aware sidecars run as UID 0 so Kubernetes grants
# the required /proc inspection capabilities into the effective set. The
# network init container installs nftables rules that exempt the effective
# sidecar UID.
proxyUid: 1337
# -- Keep process/binary-aware network policy enabled in sidecar topology.
# When false, the network sidecar runs as proxyUid, drops the extra /proc
# inspection capabilities, and enforces endpoint/L7 policy without matching
# policy.binaries.
processBinaryAwareNetworkPolicy: true
# -- Image pull secrets attached to gateway and helper pods.
imagePullSecrets: []
# -- Override the chart name used in generated resource names.
nameOverride: "openshell"
# -- Override the full generated resource name.
fullnameOverride: ""
serviceAccount:
# -- Create a service account for the gateway.
create: true
# -- Annotations to add to the generated service account.
annotations: {}
# -- Existing service account name to use when serviceAccount.create is false.
name: ""
sandboxServiceAccount:
# -- Create a service account for sandbox pods.
create: true
# -- Annotations to add to the generated sandbox service account.
annotations: {}
# -- Existing service account name for sandbox pods when sandboxServiceAccount.create is false.
name: ""
# -- Extra annotations to add to the gateway pod.
podAnnotations: {}
# -- Extra labels to add to the gateway pod.
podLabels: {}
podSecurityContext:
# -- fsGroup assigned to the gateway pod.
fsGroup: 1000
securityContext:
# -- Require the gateway container to run as a non-root user.
runAsNonRoot: true
# -- UID assigned to the gateway container.
runAsUser: 1000
# -- Whether the gateway container can gain additional privileges.
allowPrivilegeEscalation: false
capabilities:
# -- Linux capabilities dropped from the gateway container.
drop:
- ALL
service:
# -- Kubernetes Service type for the gateway.
type: ClusterIP
# -- Gateway gRPC/HTTP service port.
port: 8080
# -- Gateway health service port.
healthPort: 8081
# -- Gateway metrics service port.
metricsPort: 9090
# Pod restart behavior and health probe tuning.
podLifecycle:
# -- Grace period, in seconds, before Kubernetes terminates the gateway pod.
terminationGracePeriodSeconds: 5
probes:
startup:
# -- Startup probe period, in seconds.
periodSeconds: 2
# -- Startup probe timeout, in seconds.
timeoutSeconds: 1
# -- Startup probe failure threshold before the container is killed.
failureThreshold: 30
liveness:
# -- Liveness probe initial delay, in seconds.
initialDelaySeconds: 2
# -- Liveness probe period, in seconds.
periodSeconds: 5
# -- Liveness probe timeout, in seconds.
timeoutSeconds: 1
# -- Liveness probe failure threshold before the container is restarted.
failureThreshold: 3
readiness:
# -- Readiness probe initial delay, in seconds.
initialDelaySeconds: 1
# -- Readiness probe period, in seconds.
periodSeconds: 2
# -- Readiness probe timeout, in seconds.
timeoutSeconds: 1
# -- Readiness probe failure threshold before the pod is marked not ready.
failureThreshold: 3
# -- Gateway pod resource requests and limits.
resources: {}
# -- Node selector for the gateway pod.
nodeSelector: {}
# -- Tolerations for the gateway pod.
tolerations: []
# -- Affinity rules for the gateway pod.
affinity: {}
# Server configuration
server:
# -- Gateway log level.
logLevel: info
# -- Namespace where sandbox pods are created. Defaults to the Helm release
# namespace (.Release.Namespace) when left empty.
sandboxNamespace: ""
# -- Gateway database URL (used for the default SQLite backend).
dbUrl: "sqlite:/var/openshell/openshell.db"
# -- Name of a pre-existing Opaque Secret containing a PostgreSQL
# connection URI (key: uri). When set, the gateway reads OPENSHELL_DB_URL
# from this Secret instead of using dbUrl. The Secret must contain a
# `uri` key, e.g. postgresql://user:pass@host:5432/dbname.
externalDbSecret: ""
# -- Default sandbox image used when requests do not specify one.
sandboxImage: "ghcr.io/nvidia/openshell-community/sandboxes/base:latest"
# -- Kubernetes imagePullPolicy for sandbox pods. Empty = Kubernetes default
# (Always for :latest, IfNotPresent otherwise). Set to "Always" for dev
# clusters so new images are picked up without manual eviction.
sandboxImagePullPolicy: ""
# -- Image pull secrets attached to sandbox pods. Referenced Secrets must exist
# in the sandbox namespace.
sandboxImagePullSecrets: []
# -- Default storage size for the workspace PVC in sandbox pods.
# Uses Kubernetes quantity syntax (e.g. "2Gi", "10Gi", "500Mi").
# Empty = built-in default (2Gi).
workspaceDefaultStorageSize: ""
# -- Kubernetes StorageClass for the workspace PVC in sandbox pods.
# Empty (default) = omit storageClassName, using the cluster's default
# StorageClass. Set this on clusters with no default StorageClass, otherwise
# the workspace PVC stays Pending and the sandbox never starts.
workspaceStorageClass: ""
# -- Default Kubernetes runtimeClassName for sandbox pods.
# Applied when a CreateSandbox request does not specify one.
# Empty (default) = omit the field, using the cluster's default RuntimeClass.
# Set to a RuntimeClass name (e.g. "kata-containers", "nvidia") to apply it
# to all sandboxes that don't explicitly override it.
defaultRuntimeClassName: ""
# -- gRPC endpoint sandboxes call back into the gateway. Leave empty to derive
# it from the chart fullname, release namespace, service port, and
# disableTls flag, for example https://openshell.openshell.svc.cluster.local:8080.
# Override only when sandboxes must reach the gateway via a different
# hostname (e.g. an external ingress or a host alias).
grpcEndpoint: ""
# TLS configuration for the server. The server always terminates mTLS
# directly and requires client certificates.
# -- Host gateway IP for sandbox pod hostAliases. When set, sandbox pods get
# hostAliases entries mapping host.docker.internal and host.openshell.internal
# to this IP, allowing them to reach services running on the Docker host.
# Auto-detected by the cluster entrypoint script.
hostGatewayIP: ""
# -- Enable Kubernetes user namespace isolation (hostUsers: false) for sandbox
# pods. Requires Kubernetes 1.33+ with user namespace support available
# (beta through 1.35, GA in 1.36+), plus a supporting container runtime and
# Linux 5.12+. When enabled, container UID 0 maps to an unprivileged host
# UID and capabilities become namespaced.
enableUserNamespaces: false
# -- Kubernetes AppArmor profile requested for sandbox agent containers.
# Default Unconfined avoids runtime/default AppArmor blocking the supervisor's
# network namespace mount setup on AppArmor-enabled nodes. Set to "" to omit
# the field, "RuntimeDefault" to force the runtime default profile, or
# "Localhost/profile-name" for an operator-managed localhost profile.
appArmorProfile: "Unconfined"
# -- Disable TLS entirely - the server listens on plaintext HTTP.
# Set to true when a reverse proxy / tunnel terminates TLS at the edge.
disableTls: false
# -- Enable plaintext HTTP routing for loopback sandbox service URLs on
# TLS-enabled gateways.
enableLoopbackServiceHttp: true
# -- Posture when a candidate sandbox policy fails validation. `fail_closed`
# deactivates the previous policy; `retain_last_valid` keeps it active.
policyValidationFailureMode: fail_closed
# Optional gateway-wide gRPC request rate limit. Applies only to gRPC API
# traffic after protocol multiplexing; health, metrics, and loopback service
# HTTP routes are not rate limited. Both values must be positive to enable the
# limit, otherwise it is omitted from the rendered config and stays disabled.
grpcRateLimit:
# -- Maximum gRPC requests allowed per window. Must be positive (alongside
# windowSeconds) to enable rate limiting; 0 (default) disables it.
requests: 0
# -- gRPC rate-limit window length in seconds. Must be positive (alongside
# requests) to enable rate limiting; 0 (default) disables it.
windowSeconds: 0
# Default credential storage settings (used when no credential driver is
# enabled). The gateway encrypts provider credentials in the database using
# AES-256-GCM with a key-encryption key (KEK). By default, the Helm chart
# generates and retains a KEK Secret. For GitOps / helm-template workflows
# where `lookup` is unavailable, reference a pre-created Secret instead.
credentialStorage:
# -- Name of a pre-existing Secret containing the key-encryption key.
# When set, the chart does NOT generate a new Secret; it references this
# one instead. The Secret must contain a key named "key-encryption-key"
# with a base64-encoded 32-byte value. Required for GitOps workflows that
# render manifests with `helm template` (where `lookup` is unavailable).
existingSecret: ""
# Provider credential drivers store provider credential secret material in an
# external or native backend. When no driver is enabled, the gateway uses its
# default encrypted database credential storage with a retained Kubernetes
# Secret for the shared key-encryption key.
credentialDrivers:
kubernetesSecrets:
# -- Enable the in-tree Kubernetes Secret credential driver.
# WARNING: The RBAC Role grants read/write access to ALL Secrets in the
# configured namespace. Use a dedicated namespace to limit blast radius.
enabled: false
# -- Namespace where OpenShell-managed provider Secret objects are stored.
# Empty = Helm release namespace. A dedicated namespace is RECOMMENDED
# to isolate OpenShell-managed Secrets from other workloads.
namespace: ""
# -- Deprecated compatibility field. Credential storage no longer supports user-authored namespace references.
allowReferenceNamespace: false
rbac:
# -- Create a Role/RoleBinding granting the gateway ServiceAccount read/write access to managed provider Secrets.
create: true
vault:
# -- Enable the in-tree Vault credential driver.
enabled: false
# -- Vault service base URL, for example http://vault.vault.svc.cluster.local:8200.
address: ""
# -- Default KV mount name.
mount: secret
# -- Default KV engine version. Use "1" or "2".
kvVersion: "2"
# -- Authentication method. Use "kubernetes" in-cluster or "token_file" for local/dev validation.
authMethod: kubernetes
# -- Vault Kubernetes auth role when authMethod is kubernetes.
role: ""
# -- Vault Kubernetes auth mount.
kubernetesAuthMount: kubernetes
# -- ServiceAccount token path used for Kubernetes auth.
serviceAccountTokenPath: /var/run/secrets/kubernetes.io/serviceaccount/token
# -- Mounted token file path when authMethod is token_file.
tokenPath: ""
# -- HTTP request timeout in seconds. Empty = driver default.
timeoutSecs: ""
auth:
# -- UNSAFE: accept unauthenticated CLI/user requests as a local developer
# principal. Intended only for trusted local Skaffold/k3d development or a
# fully trusted fronting proxy. Leave false for shared or production clusters.
allowUnauthenticatedUsers: false
tls:
# -- K8s secret (type kubernetes.io/tls) with tls.crt and tls.key for the server.
certSecretName: openshell-server-tls
# -- K8s secret with ca.crt for client certificate verification (mTLS).
# Set to "" to disable mTLS and run HTTPS-only (use OIDC for auth instead).
clientCaSecretName: openshell-server-client-ca
# -- K8s secret mounted into sandbox pods for mTLS to the server.
clientTlsSecretName: openshell-client-tls
# Gateway-minted sandbox JWT signing keys. The certgen hook generates an
# Ed25519 keypair and writes it to a secret containing signing.pem (PKCS#8),
# public.pem (SPKI), and kid (plain text). The hook runs in full PKI mode when
# pkiInitJob.enabled=true unless certManager.enabled=true, which takes
# precedence and runs the hook in JWT-only mode.
sandboxJwt:
# -- Name of the Opaque Secret holding the signing key material. Empty
# falls back to the chart fullname with "-jwt-keys" appended.
signingSecretName: ""
# -- Stable gateway identity embedded in iss/aud of every minted token.
# Defaults to the release name so HA replicas share identity.
gatewayId: ""
# -- Token TTL in seconds. Defaults to 3600 (1h).
ttlSecs: 3600
# -- Lifetime (seconds) of the projected ServiceAccount token kubelet
# writes into each sandbox pod for the IssueSandboxToken bootstrap
# exchange. Kubelet enforces a minimum of 600s; the driver clamps
# values outside [600, 86400]. Default 3600 — generous, since the
# supervisor consumes the token within seconds of pod start.
k8sSaTokenTtlSecs: 3600
# -- File mode for the mounted JWT signing key Secret. Default 0400
# (owner-read only). Override to 0440 or 0444 if the container UID
# does not match the volume file owner.
secretDefaultMode: ""
# Dynamic provider token grants. When SPIFFE is enabled here, sandbox
# supervisors mount the SPIFFE Workload API socket so provider profiles can
# exchange JWT-SVIDs for upstream access tokens. Supervisor-to-gateway
# authentication still uses gateway-minted sandbox JWTs.
providerTokenGrants:
spiffe:
# -- Mount the SPIFFE Workload API socket into sandbox pods for dynamic provider token grants.
enabled: false
# -- Path to the SPIFFE Workload API socket mounted into sandbox pods.
workloadApiSocketPath: /spiffe-workload-api/spire-agent.sock
# OIDC (OpenID Connect) configuration for JWT-based authentication.
# When issuer is set, the server validates Bearer tokens on gRPC requests.
oidc:
# -- OIDC issuer URL (e.g. https://keycloak.example.com/realms/openshell).
issuer: ""
# -- Expected audience claim for the API resource server.
# This should match the server's --oidc-audience, NOT the CLI client ID.
audience: "openshell-cli"
# -- JWKS key cache TTL in seconds.
jwksTtl: 3600
# -- Dot-separated path to the roles array in the JWT claims.
# Keycloak: "realm_access.roles", Entra ID: "roles", Okta: "groups".
rolesClaim: ""
# -- Role name for admin access. Leave empty (with userRole also empty) for
# authentication-only mode. Both must be set or both empty.
adminRole: ""
# -- Role name for standard user access.
userRole: ""
# -- Dot-separated path to the scopes array in the JWT claims.
scopesClaim: ""
# -- Name of a ConfigMap containing a CA certificate bundle (key: ca.crt)
# for verifying the OIDC issuer's TLS certificate. Required when the
# issuer uses a non-public CA (e.g. OpenShift ingress, private PKI).
caConfigMapName: ""
# NetworkPolicy restricting SSH ingress on sandbox pods to the gateway only.
networkPolicy:
# -- Create a NetworkPolicy restricting SSH ingress on sandbox pods to the gateway.
enabled: true
# Built-in TLS PKI bootstrap via a pre-install/pre-upgrade hook Job.
# Runs `openshell-gateway generate-certs` to create the server and client TLS
# Secrets in-cluster. Key material is written directly to K8s Secrets and
# never appears in Helm release history. Idempotent: existing secrets are
# left untouched on upgrade. Reuses the gateway image - no extra image to
# mirror in air-gapped environments.
#
# The server certificate already includes the built-in cluster SANs
# (`openshell`, `openshell.openshell.svc`, the cluster.local FQDN, `localhost`,
# `openshell.localhost`, `*.openshell.localhost`, `host.docker.internal`, and
# `127.0.0.1`) baked into the gateway binary. The lists below are additional
# SANs appended on top. Wildcard DNS SANs also enable sandbox service URLs under
# that domain, for example `*.apps.example.com` enables
# `<sandbox>--<service>.apps.example.com`.
pkiInitJob:
# -- Run a pre-install/pre-upgrade Job that creates gateway and client mTLS
# Secrets. When certManager.enabled=true, cert-manager owns TLS and this same
# hook runs in JWT-only mode even if pkiInitJob.enabled remains true.
enabled: true
# -- Extra DNS SANs to append to the server certificate.
serverDnsNames: []
# -- Extra IP SANs to append to the server certificate.
serverIpAddresses: []
# cert-manager Certificate/Issuer resources (requires cert-manager CRDs in-cluster).
# Uses namespaced Issuers only (no ClusterIssuer). Does not install cert-manager itself.
certManager:
# -- Create cert-manager Issuer and Certificate resources. When enabled,
# cert-manager owns TLS and the chart runs a JWT-only certgen hook to create
# the sandbox JWT signing Secret that cert-manager does not manage.
enabled: false
# -- Secret created for the intermediate CA (Certificate with isCA: true).
caSecretName: openshell-ca-tls
# -- Mount gateway client CA from the server TLS secret's ca.crt (populated by
# cert-manager for certs issued by a CA Issuer). Avoids a separate
# openshell-server-client-ca Secret.
clientCaFromServerTlsSecret: true
# -- Duration for cert-manager-issued certificates.
certificateDuration: 8760h
# -- Renewal window for cert-manager-issued certificates.
certificateRenewBefore: 720h
# -- DNS SANs on the cert-manager-issued server certificate.
serverDnsNames:
- openshell
- openshell.openshell.svc
- openshell.openshell.svc.cluster.local
- localhost
- openshell.localhost
- "*.openshell.localhost"
- host.docker.internal
# -- IP SANs on the cert-manager-issued server certificate.
serverIpAddresses:
- 127.0.0.1
# Kubernetes Gateway API - HTTPRoute and Gateway resources.
# Requires a Gateway API controller in the cluster. Install Envoy Gateway via
# the skaffold.yaml releases or independently:
# helm install eg oci://docker.io/envoyproxy/gateway-helm \
# --version v1.4.1 -n envoy-gateway-system --create-namespace
grpcRoute:
# -- Create a Gateway API GRPCRoute for the gateway service.
enabled: false
# -- Hostnames the GRPCRoute matches on. Leave empty to match all hosts.
hostnames: []
gateway:
# -- When true, a Gateway resource is created in the release namespace.
# Set to false and provide name/namespace to attach to a pre-existing Gateway.
create: false
# -- GatewayClass to reference. Envoy Gateway installs one named "eg".
className: "eg"
# -- Name of the Gateway resource. Defaults to the chart fullname.
name: ""
# -- Namespace of the Gateway referenced by the GRPCRoute parentRef.
# Defaults to the release namespace.
namespace: ""
# Listener settings (only used when gateway.create is true).
listener:
# -- Listener port for the generated Gateway resource. Use 443 with protocol HTTPS.
port: 80
# -- Listener protocol for the generated Gateway resource: HTTP or HTTPS.
# HTTPS terminates TLS at the Envoy Gateway listener; pair it with
# server.disableTls=true so Envoy forwards plaintext to the gateway pod,
# and use OIDC for client identity (the gateway never sees the client cert).
protocol: HTTP
# -- "Same" restricts attached routes to the release namespace; "All" allows any namespace.
allowedRoutes: Same
# TLS settings for the listener. Used only when protocol is HTTPS
# (mode is always Terminate).
tls:
# -- certificateRefs for the HTTPS listener. Required when protocol is
# HTTPS. Each entry needs a `name` pointing at a kubernetes.io/tls Secret
# in the Gateway's namespace. May reference a cert-manager-issued Secret
# or the existing openshell-server-tls Secret (its SANs must include the
# external hostname).
certificateRefs: []