EQTY LabDocs

LLM Gateway Configuration

Chart values, environment variables, and startup validation for the LLM Gateway.

View as Markdown

The LLM Gateway is configured through the gateway-stack values of the platform chart, under gateway-stack.llmGateway. This page describes the chart values operators set, the environment variables the service reads outside the chart, and the checks it runs at startup.

Required Configuration Areas

  • Gateway database connection, the same PostgreSQL database the Control Plane uses. The platform chart supplies it from the gateway-dsn key of the platform database Secret.
  • Agent registration turned on, with a credential signer seed. The chart gives the gateway the Control Plane’s registration token secret and issuer, so set those once, in Control Plane Configuration.
  • The Auth Service URL, for agents that register with an API key.
  • The plugin runtime, with the same trusted signer keys, artifact storage, and plugin secrets key as the Control Plane, before you configure policies.
  • Project context, so project configurations and memberships apply.

Chart Values

The platform chart already points the gateway at the platform database and sets deploymentEnvironment to production. Set the rest yourself. <release> is your platform release name, such as guardian-platform.

yaml
gateway-stack:
  enabled: true
  llmGateway:
    registration:
      enabled: true
      credentialSigner:
        existingSecret: "guardian-gateway-credential-signer" # holds seed
    authServiceBaseURL: "http://<release>-auth-service:8080"
    plugins:
      enabled: true
      artifactStorage:
        provider: "gcs"
        bucket: "guardian-plugins"
      trustedSignerKeys:
        signer-v1: "did:key:z6Mk..."
      secrets:
        resolutionOrder: ["store"]
        encryptionKey:
          existingSecret: "guardian-plugin-secrets-key" # holds encryption-key
    projectContext:
      mode: "enforce"
  ingress:
    enabled: true
    className: "nginx"
    hosts:
      llmGateway: "gateway.example.com"
ValueDefaultNotes
signature.labelsigThe label Viper signs with. With any other label, every signed request is refused.
signature.defaultSigMaxAge / defaultClockSkew60s / 120sHow old a signature may be, and how far a client’s clock may drift.
registration.enabledfalseMust be true for agents to register, with a registration token or an API key.
registration.credentialSigner.existingSecret / seednoneA Secret with the Ed25519 seed the gateway signs registration credentials with, under secretKey (default seed), or the seed inline. With registration on, the gateway exits at startup without it.
authServiceBaseURLnoneTurns on API-key registration. Use the Auth Service URL the Control Plane uses, http://<release>-auth-service:8080 in the platform chart, so both derive the same identity issuer.
authServiceIdentityIssuer<authServiceBaseURL>/api/v1/authOverride only when the Control Plane reaches Auth Service at a different URL.
upstreams.anthropicURL / openaiURLthe public provider APIsThe ChatGPT backend has no chart value; override it with extraArgs: ["-chatgpt-backend-upstream-url=…"].
audit.enabledtrue
audit.retentionDays90Exchanges older than this are deleted every 24 hours, counted from pod start.
audit.queueMaxBytes10737418240 (10 GiB)The on-disk queue, an emptyDir. Once it is full, new audit records are dropped.
audit.batchSize / flushInterval100 / 1s
plugins.enabledfalseRuns the global and project plugin configurations. Without a trusted signer key, the gateway exits at startup.
plugins.pollInterval15sHow often the gateway reloads the active configurations.
plugins.authorizerShadowEnabledfalseCompares plugin decisions with the legacy authorizer, without enforcing the legacy result.
plugins.artifactStorage.*noneThe same provider, bucket, and prefix as controlPlane.plugins.artifactStorage, with credentials that can read them. The same keys as the Control Plane’s, except maxUploadBytes and gcs.kmsKeyName.
serviceAccount.annotationsnoneThe gateway runs as its own service account. Without a storage credentials Secret, bind the cloud identity that reads the artifact bucket here.
plugins.trustedSignerKeysnoneMap of key ID to did:key. The same keys as controlPlane.plugins.trustedSignerKeys, including the Control Plane’s publisher signer.
plugins.secrets.resolutionOrdernoneSet ["store"] so plugins can read the secrets stored through the Control Plane. Without it, plugins that need a secret fail.
plugins.secrets.encryptionKey.existingSecretnoneThe same Secret as controlPlane.plugins.secrets.encryptionKey. Required when resolutionOrder includes store.
plugins.secretEnvs / secretEnvsSecret.namenonePlugin secrets as environment variables, inline or from a Secret, for local development. With either set and resolutionOrder empty, the chart sets the resolution order to env.
projectContext.modedisabledobserve or enforce turns on project context; see Project Context.
extraArgsnoneCommand-line flags for settings without a chart value.
extraEnvnoneExtra environment variables, such as the OTEL_* exporter settings. See Observability.
replicaCount / autoscaling.* / podDisruptionBudget.*1 / off / off
probes.startup.failureThreshold / periodSeconds180 / 5Allows 15 minutes for database migrations before liveness checks start.

Project Context

Project context is off unless you turn it on with projectContext.mode. While it is off, the gateway ignores the project an agent presents: project configurations, project membership, and project trust do not apply, and every request runs under the global configuration only. Set it to enforce (or observe, which currently behaves the same) once plugins are on; the chart refuses to render with project context on and plugins off. The gateway’s mode denies nothing itself: with either value, a request that presents a project is denied when no project membership entry can admit it, and otherwise the Project Membership entry’s own mode decides whether a failed membership check denies it; see Gateway Policies.

Environment Variables

Outside the chart, the gateway reads these variables. Every name starts with LLM_GATEWAY_, left out below. The service also reads a TOML file named by -config or LLM_GATEWAY_CONFIG_FILE, and accepts a command-line flag for most settings. A flag overrides its environment variable, which overrides the file.

CategoryVariableDefault
ServerLISTEN:10000
ServerMETRICS_LISTEN:10001
ServerDEPLOYMENT_ENVIRONMENTnone
ServerSERVICE_VERSIONnone; reported as dev
ServerMAX_REQUEST_BODY_BYTES33554432 (32 MiB)
DatabaseREGISTRY_DB_DSNAUDIT_DB_DSN; one of the two is required
DatabaseAUDIT_DB_DSNnone; required while audit is enabled
DatabaseBLOB_STORE_DB_DSNREGISTRY_DB_DSN
RegistrationAGENT_REGISTRATION_ENABLEDtrue
RegistrationREGISTRATION_TOKEN_SECRETnone; required when registration is enabled
RegistrationREGISTRATION_TOKEN_ISSUERcontrol-plane
RegistrationCREDENTIAL_SIGNER_SEEDnone; required when registration is enabled
RegistrationAUTH_SERVICE_BASE_URLnone; API-key registration is off without it
RegistrationAUTH_SERVICE_IDENTITY_ISSUER<AUTH_SERVICE_BASE_URL>/api/v1/auth
RegistrationAUTH_SERVICE_HTTP_TIMEOUT / AUTH_SERVICE_CACHE_TTL10s / 30s
VerificationSIGNATURE_LABELsig
VerificationDEFAULT_SIG_MAX_AGE / DEFAULT_CLOCK_SKEW60s / 120s
VerificationTRUSTED_YUBIKEY_ROOT_CERTSnone
UpstreamsANTHROPIC_UPSTREAM_URLhttps://api.anthropic.com
UpstreamsOPENAI_UPSTREAM_URLhttps://api.openai.com
UpstreamsCHATGPT_BACKEND_UPSTREAM_URLhttps://chatgpt.com/backend-api
AuditAUDIT_ENABLEDtrue
AuditAUDIT_QUEUE_DIR / AUDIT_QUEUE_MAX_BYTESdata/audit-queue / 10737418240 (10 GiB)
AuditAUDIT_BATCH_SIZE / AUDIT_FLUSH_INTERVAL100 / 1s
AuditAUDIT_RETENTION_DAYS90
BlobsBLOB_MAX_BYTES67108864 (64 MiB)
PluginsPLUGINS_ENABLEDfalse
PluginsPLUGIN_POLL_INTERVAL15s
PluginsPLUGIN_END_QUEUE_DIR / PLUGIN_END_QUEUE_MAX_BYTESdata/plugin-end-queue / 134217728 (128 MiB)
PluginsPLUGIN_REDACT_HEADERSnone
PluginsPLUGIN_ARTIFACT_CACHE_DIRdata/plugin-artifacts
PluginsPLUGIN_TRUSTED_SIGNER_KEYSnone; at least one is required when plugins are enabled
PluginsPLUGIN_SECRETS_RESOLUTION_ORDERnone
PluginsPLUGIN_SECRETS_ENCRYPTION_KEYnone
PluginsPLUGIN_SECRETS_ENV_PREFIXGUARDIAN_SECRET_
PluginsPLUGIN_AUTHORIZER_SHADOW_ENABLEDfalse
PluginsPLUGIN_WASM_INTERPRETERfalse
PluginsPLUGIN_ARTIFACT_STORAGE_*none; the Control Plane’s settings except MAX_UPLOAD_BYTES and GCS_KMS_KEY_NAME
ProjectsPROJECT_CONTEXT_MODEdisabled

PLUGIN_TRUSTED_SIGNER_KEYS is a comma-separated list of key_id=public_key pairs, where the public key may be a did:key; its flag, -plugin-trusted-signer-key, takes one pair and repeats. TRUSTED_YUBIKEY_ROOT_CERTS is a comma-separated list of PEM file paths. PLUGIN_SECRETS_RESOLUTION_ORDER is a comma-separated list of store and env: store reads the secrets stored through the Control Plane, and env reads environment variables named with PLUGIN_SECRETS_ENV_PREFIX, for local development. The credential signer seed and the plugin secrets key are base64, base64url, or hex; the seed may also be a path to a file that holds it.

PLUGIN_REDACT_HEADERS is a comma-separated list of extra header names, matched case-insensitively, whose values the gateway masks before request.end plugins and their on-disk queue see them. Headers whose names contain auth, token, secret, password, session, cookie, api-key or apikey, or end in -key, are always masked; use this setting for other upstream credential headers.

PLUGIN_WASM_INTERPRETER has no flag: true interprets plugin WebAssembly instead of compiling it to native code.

DEPLOYMENT_ENVIRONMENT is also reported to OpenTelemetry as deployment.environment unless OTEL_RESOURCE_ATTRIBUTES sets it. The service reads a few variables that are not listed here: REGISTRY_BACKEND, which accepts only postgres; the EXT_REGISTRY_* external registry settings, which are not supported in production; and PROJECT_CONTEXT_REQUIRE_MEMBERSHIP and PROJECT_TRUSTED_ISSUER_DIDS, which are deprecated and have no effect.

The Control Plane must use the same registration token secret and issuer, trusted signer keys, and plugin secrets key as the gateway, listed in Control Plane Configuration, as well as the same artifact storage and Auth Service URL.

Startup Validation

The gateway refuses to start when its configuration is inconsistent, and logs LLM Gateway failed: invalid config: followed by the setting at fault, usually in flag form. The checks include:

  • A database DSN is required.
  • The upstream URLs and the signature label must be set, and the upstream URLs must be http or https URLs with a host.
  • The request body and blob size limits must be above zero.
  • Registration requires a registration token secret.
  • An Auth Service identity issuer requires an Auth Service URL, the URL must be valid, and its timeout and cache TTL must be above zero.
  • Audit capture requires an audit DSN and a queue directory, and its queue size, batch size, flush interval, and retention must be above zero.
  • Plugins require at least one trusted signer key, a positive poll interval, their queue and cache directories, and a queue size above zero.
  • Project context must be disabled, observe, or enforce, and any mode other than disabled requires plugins.
  • Artifact storage needs a bucket once a provider is set, a region and credentials for s3, and exactly one of a connection string, an account key, or managed identity for Azure.

These also stop startup, with LLM Gateway failed: and the reason:

  • a missing credential signer seed while registration is on, or an unreadable seed
  • a store secret resolver without the plugin secrets key, or a resolver other than store or env
  • a trusted signer key that is not a valid public key
  • unreadable YubiKey root certificates
  • an active plugin configuration that cannot be loaded, such as one whose artifact is unreachable or signed by an untrusted key
  • an unreachable database

Keep secrets such as the credential signer seed, the plugin secrets key, and storage credentials in the deployment’s secret management system, not in values files.