Control Plane Configuration
Chart values, environment variables, and startup validation for the Control Plane.
The Control Plane is configured through the gateway-stack values of the platform chart, under gateway-stack.controlPlane. 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 LLM Gateway uses.
- Registration token secret and issuer, plus agent registration turned on in the LLM Gateway with a credential signer. Once registration is on, the chart gives the gateway the same secret and issuer, so it accepts the tokens the Control Plane mints. Without it, the gateway answers a valid token with
404 registration_unavailable. Outside the chart, setLLM_GATEWAY_AGENT_REGISTRATION_ENABLED,LLM_GATEWAY_REGISTRATION_TOKEN_SECRET,LLM_GATEWAY_REGISTRATION_TOKEN_ISSUER, andLLM_GATEWAY_CREDENTIAL_SIGNER_SEEDon the gateway. - Authentication with Auth Service bearer mode, so Guardian users and API keys are accepted.
- Guardian adapter connections to Auth Service and Integrity Service, for the project-scoped routes Guardian uses.
- Plugin artifact storage, plugin signer keys, and the plugin secrets key, before publishing plugins.
Chart Values
The platform chart already turns on the Guardian adapter and bearer authentication in Auth Service mode, and points the adapter at the release’s Auth Service and Integrity Service. Set authentication on yourself: with bearer authentication on and authentication off, the Control Plane refuses to start.
gateway-stack:
enabled: true
llmGateway:
registration:
enabled: true
credentialSigner:
existingSecret: "guardian-gateway-credential-signer" # holds seed
controlPlane:
apiBasePath: "/api"
auth:
enabled: true
existingSecret: "guardian-control-plane-auth" # holds registrationTokenSecret
ingress:
enabled: true
controlPlanePath: "/api"
hosts:
controlPlane: "control-plane.example.com"| Value | Default | Notes |
|---|---|---|
apiBasePath | none | Set it to match ingress.controlPlanePath, /api in the standard deployment. |
auth.enabled | false | Must be true in the platform chart. |
auth.existingSecret / auth.registrationTokenSecret | change-me | A Secret with the registration token secret, or the secret inline. The chart refuses to render while it is change-me. |
auth.registrationTokenIssuer | control-plane | |
auth.allowedEmailDomains | none; any domain | |
auth.bearer.enabled / auth.bearer.mode | true / auth_service in the platform | Set by the platform chart. |
adapter.enabled | true in the platform | Set by the platform chart. |
adapter.authServiceBaseURL, integrityBaseURL | the release’s services | Override only when a service runs elsewhere. |
adapter.httpTimeout / integrityHTTPTimeout | 5s | |
adapter.projectRuntimeReadTimeout | 30s | |
adapter.integrityStatusCacheTTL | 5m | How often stored credential statuses are re-checked. |
adapter.trustedMembershipIssuerDIDs / trustedComplianceIssuerDIDs | none | Compliance issuers default to the membership issuers. They decide which agent certifications are trusted too. |
plugins.artifactStorage.provider / bucket / prefix | none | gcs, s3, azure, or file. The bucket is required once a provider is set. Give the gateway the same settings in llmGateway.plugins.artifactStorage. |
plugins.artifactStorage.s3.region / existingSecret | none | Required for s3. |
plugins.artifactStorage.gcs.existingSecret | none | A Secret with a service account JSON. Without it, grant access through serviceAccount.annotations. |
plugins.artifactStorage.azure.accountName / existingSecret / useManagedIdentity | none | For azure, the bucket is the container. Use exactly one of a Secret with an account key or connection string, or managed identity. |
plugins.artifactStorage.file.existingClaim | none | For file, a ReadWriteMany claim mounted at the bucket path, which must be absolute. |
plugins.publisherSigner.keyID / existingSecret | none | The Secret holds the Ed25519 seed the Control Plane signs uploads with. |
plugins.trustedSignerKeys | none | Map of key ID to did:key. Give the gateway the same keys in llmGateway.plugins.trustedSignerKeys. |
plugins.secrets.encryptionKey.existingSecret | none | Use the same Secret for llmGateway.plugins.secrets.encryptionKey. |
virusTotal.enabled / existingSecret | false / none | The Secret holds the VirusTotal API key. |
waitForRegistryViews.enabled | true | On a first install, holds startup until the LLM Gateway has created the registry views. It does not wait on upgrades. |
llmGateway.registration.enabled | false | Must be true for the gateway to accept registration tokens. |
llmGateway.registration.credentialSigner.existingSecret | none | The Secret holds the Ed25519 seed the gateway signs registration credentials with. Required with registration on. |
Environment Variables
Outside the chart, the Control Plane reads these variables. Every name starts with CONTROL_PLANE_, left out below. The service also reads a TOML file named by -config or CONTROL_PLANE_CONFIG_FILE, and accepts a command-line flag for most settings. A flag overrides its environment variable, which overrides the file.
| Category | Variable | Default |
|---|---|---|
| Server | LISTEN | :10010 |
| Server | DB_DSN | none, required |
| Server | API_BASE_PATH | none |
| Server | CORS_ALLOW_ALL | true |
| Server | SERVICE_VERSION | none; reported as dev |
| Authentication | AUTH_ENABLED | false |
| Authentication | AUTH_REGISTRATION_TOKEN_SECRET | none; required when authentication is enabled |
| Authentication | AUTH_REGISTRATION_TOKEN_ISSUER | control-plane |
| Authentication | AUTH_ALLOWED_EMAIL_DOMAINS | none; any domain |
| Authentication | AUTH_BEARER_ENABLED | false; required when authentication is on |
| Authentication | AUTH_BEARER_MODE | oidc |
| Authentication | AUTH_BEARER_AUTH_SERVICE_BASE_URL | ADAPTER_AUTH_SERVICE_BASE_URL |
| Authentication | AUTH_BEARER_ISSUER_URL / AUTH_BEARER_CLIENT_ID | none; required in oidc mode |
| Authentication | AUTH_BEARER_SCOPES | openid,profile,email |
| Guardian | ADAPTER_AUTH_ENABLED | false |
| Guardian | ADAPTER_AUTH_SERVICE_BASE_URL | none; required when the adapter is enabled |
| Guardian | ADAPTER_HTTP_TIMEOUT | 10s |
| Guardian | ADAPTER_PROJECT_RUNTIME_READ_TIMEOUT | 30s |
| Integrity | ADAPTER_INTEGRITY_BASE_URL | none; status refreshes are off without it |
| Integrity | ADAPTER_INTEGRITY_HTTP_TIMEOUT | 10s |
| Integrity | ADAPTER_INTEGRITY_STATUS_CACHE_TTL | 5m |
| Integrity | ADAPTER_TRUSTED_MEMBERSHIP_ISSUER_DIDS | none |
| Integrity | ADAPTER_TRUSTED_COMPLIANCE_ISSUER_DIDS | the membership issuers |
| Integrity | ADAPTER_ALLOW_EMBEDDED_CREDENTIAL_BOOTSTRAP | false |
| Plugins | PLUGIN_TRUSTED_SIGNER_KEYS | none |
| Plugins | PLUGIN_PUBLISHER_SIGNER_KEY_ID / PLUGIN_PUBLISHER_SIGNER_SEED_FILE | none |
| Plugins | PLUGIN_SECRETS_ENCRYPTION_KEY | none |
| Plugins | PLUGIN_ARTIFACT_STORAGE_PROVIDER | none |
| Plugins | PLUGIN_ARTIFACT_STORAGE_BUCKET | none; required when a provider is set |
| Plugins | PLUGIN_ARTIFACT_STORAGE_PREFIX | none |
| Plugins | PLUGIN_ARTIFACT_STORAGE_MAX_UPLOAD_BYTES | 536870912 (512 MiB) |
| Plugins | PLUGIN_ARTIFACT_STORAGE_GCS_CREDENTIALS_FILE / PLUGIN_ARTIFACT_STORAGE_GCS_KMS_KEY_NAME | Application Default Credentials; none |
| Plugins | PLUGIN_ARTIFACT_STORAGE_S3_ENDPOINT / PLUGIN_ARTIFACT_STORAGE_S3_REGION | none; region required for s3 |
| Plugins | PLUGIN_ARTIFACT_STORAGE_S3_ACCESS_KEY_ID / PLUGIN_ARTIFACT_STORAGE_S3_SECRET_ACCESS_KEY | none; required for s3 |
| Plugins | PLUGIN_ARTIFACT_STORAGE_S3_FORCE_PATH_STYLE | false |
| Plugins | PLUGIN_ARTIFACT_STORAGE_AZURE_ACCOUNT_NAME / PLUGIN_ARTIFACT_STORAGE_AZURE_ENDPOINT | none |
| Plugins | PLUGIN_ARTIFACT_STORAGE_AZURE_ACCOUNT_KEY / PLUGIN_ARTIFACT_STORAGE_AZURE_CONNECTION_STRING | none |
| Plugins | PLUGIN_ARTIFACT_STORAGE_AZURE_USE_MANAGED_IDENTITY | false |
| VirusTotal | VT_ENABLED / VT_API_KEY | false; none |
Lists such as email domains, scopes, and issuer DIDs are comma-separated; their command-line flags are singular and repeatable, and VT_API_KEY has no flag. PLUGIN_TRUSTED_SIGNER_KEYS is a comma-separated list of key_id=public_key pairs, where the public key may be a did:key.
ADAPTER_TRUSTED_COMPLIANCE_ISSUER_DIDS lists the issuers whose project compliance credentials and agent certifications the Control Plane trusts. Setting it replaces the fallback to ADAPTER_TRUSTED_MEMBERSHIP_ISSUER_DIDS, so keep every issuer you trust in it. For agent certification it must include the platform signing DID; see Agent Certification.
PLUGIN_ARTIFACT_STORAGE_PROVIDER accepts gcs, s3, azure, or file. Leave it unset and plugin artifacts cannot be uploaded. With file, the bucket is a folder path that both the Control Plane and the gateway can reach. Azure needs exactly one of a connection string, an account key, or managed identity, and an endpoint override cannot be combined with a connection string.
The LLM Gateway must use the same artifact storage and Auth Service URL as the Control Plane, and the same registration token secret and issuer, plugin trusted signer keys, and plugin secrets key; see LLM Gateway Configuration. Outside the chart, set these four on both services:
| Control Plane | LLM Gateway |
|---|---|
AUTH_REGISTRATION_TOKEN_SECRET | LLM_GATEWAY_REGISTRATION_TOKEN_SECRET |
AUTH_REGISTRATION_TOKEN_ISSUER | LLM_GATEWAY_REGISTRATION_TOKEN_ISSUER |
PLUGIN_TRUSTED_SIGNER_KEYS | LLM_GATEWAY_PLUGIN_TRUSTED_SIGNER_KEYS |
PLUGIN_SECRETS_ENCRYPTION_KEY | LLM_GATEWAY_PLUGIN_SECRETS_ENCRYPTION_KEY |
When the publisher signer is configured, the Control Plane signs the plugin artifacts and configurations an admin uploads unsigned, and adds its own key to the trusted signer keys. The gateway must trust the same public key. Without a publisher signer, uploads must carry their own signature, which guardian-plugin publish does not add. The plugin secrets key is 32 bytes in base64, base64url, or hex.
VirusTotal scanning runs only when VT_ENABLED is true and VT_API_KEY is set.
API Base Path
With a base path such as /api, the spec at /api/openapi.json and the API explorer at /api/docs/ are served only under the prefix. Every other route, including /health, answers both with and without it. A base path must start with /.
Startup Validation
The Control Plane refuses to start when its configuration is inconsistent, and logs invalid config: followed by the setting at fault, in flag form:
- Bearer authentication requires authentication, and authentication requires bearer authentication and a registration token secret.
- Auth Service mode requires an Auth Service URL, from either
AUTH_BEARER_AUTH_SERVICE_BASE_URLorADAPTER_AUTH_SERVICE_BASE_URL. OIDC mode requires an issuer URL, a client ID, and at least one scope. - The Guardian adapter requires the Auth Service URL.
- Timeouts and the maximum upload size must be above zero.
- Artifact storage needs a bucket once a provider is set, a region and credentials for
s3, and an account name for Azure unless a connection string is set. - The publisher signer needs both its key ID and its seed file.
An unknown storage provider, an unreadable signer seed, or an unreachable database also stops startup, with its own log line.
Keep secrets such as the registration token secret, the plugin secrets key, and storage credentials in the deployment’s secret management system, not in values files.
Related
- Chart Values — where the gateway stack settings live in values.yaml
- Control Plane Authentication and RBAC — what each bearer mode accepts
- Policy as Code — publishing plugins once artifact storage and signing are configured
- Control Plane Operations — checks to run once the service is configured
- Air-Gapped Install — mirroring the gateway stack images