---
title: "Control Plane Configuration"
description: "Chart values, environment variables, and startup validation for the Control Plane."
source: "Guardian Platform"
---
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, set `LLM_GATEWAY_AGENT_REGISTRATION_ENABLED`, `LLM_GATEWAY_REGISTRATION_TOKEN_SECRET`, `LLM_GATEWAY_REGISTRATION_TOKEN_ISSUER`, and `LLM_GATEWAY_CREDENTIAL_SIGNER_SEED` on 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.

```yaml title="values.yaml"
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](../deployment/chart-values.mdx#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](../llm-gateway/configuration.mdx). 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_URL` or `ADAPTER_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](../deployment/chart-values.mdx) — where the gateway stack settings live in values.yaml
- [Control Plane Authentication and RBAC](./authentication-and-rbac.mdx) — what each bearer mode accepts
- [Policy as Code](../user-guide/policy-as-code.mdx) — publishing plugins once artifact storage and signing are configured
- [Control Plane Operations](./operations.mdx) — checks to run once the service is configured
- [Air-Gapped Install](../deployment/airgap-install.mdx) — mirroring the gateway stack images