> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jedify.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets reference

> Every Secret Manager object and Kubernetes Secret a self-hosted installation uses, what each key does, who creates it, and how to rotate one.

Every credential lives in Secret Manager in your project. External Secrets, running as its own Google service account, copies each one into a Kubernetes Secret, and nothing holds a credential in a values file. A person handles exactly two objects, the application configuration and the realtime credentials; OpenTofu and the setup scripts generate the rest.

## Secret Manager objects

| Object | Created by | Holds |
| - | - | - |
| Your application configuration, for example `<prefix>-app-config` | You, then the Zitadel setup script adds keys | The application's configuration, as a JSON object. Named by `appSecrets.smKey`. |
| Your realtime credentials, for example `<prefix>-sockudo-app` | You | `app_id`, `app_key` and `app_secret`, as a JSON object. Named by `sockudoApp.smKey`. |
| Your identity provider's client secret, for example `<prefix>-oidc-client-secret` | You | The client secret, read by the setup script only |
| `<prefix>-postgres-connection-string` | OpenTofu | The application's Cloud SQL connection string, with a generated password no person ever sees |
| `<prefix>-zitadel-dsn` | OpenTofu | Zitadel's database connection, with its own generated password |
| `<prefix>-zitadel-masterkey` | OpenTofu | The key Zitadel encrypts its stored secrets with |

<Warning>
  Never regenerate `<prefix>-zitadel-masterkey`. Zitadel can't tell a new masterkey against its existing database from corruption, and every encrypted value becomes unreadable.
</Warning>

## Application configuration

Every key in this object becomes an environment variable, with the same name, in every application component. Nothing checks the names when you install, so spell them exactly.

| Key | Set by | Meaning |
| - | - | - |
| `AUTH_PROVIDER` | You, and the setup script | Must be `zitadel`. The application's default is a hosted identity provider your installation can't reach, and every sign-in then fails; the only sign of it is `auth provider: descope (AuthService)` in the API's startup log. |
| `CREDS_KEY` | You | A Fernet key, which encrypts the data-source credentials saved in Jedify. Without it, every connector with saved credentials fails. Keep it: a new key can't decrypt what the old one encrypted. |
| `COMPONENT_AUTH_TOKEN` | You | A random token for calls between the application's components. Without it they answer each other with `401`. |
| `LITELLM_PROXY_API_KEY` | You | The key the application sends with every model call, and also the bundled proxy's master key. Without it the proxy doesn't start. Generate it as `sk-` followed by random hex; a published example key such as `sk-1234` is refused. With your own gateway, the key your gateway issued. |
| `EXTRA_CA_PEM_B64` | You, optional | Your certificate authority's PEM, base64-encoded on one line. Read only with `componentsDefaults.trustExtraCA` on, and required then. |
| `ZITADEL_ISSUER`, `ZITADEL_API_URL`, `ZITADEL_HOST_HEADER`, `ZITADEL_ALLOW_INSECURE_HTTP`, `ZITADEL_ORG_ID`, `ZITADEL_PROJECT_ID`, `ZITADEL_AUDIENCES`, `ZITADEL_FE_CLIENT_ID`, `ZITADEL_MCP_CLIENT_ID`, `ZITADEL_MCP_CLIENT_SECRET` | The setup script | Zitadel's settings. See [Settings the application reads](/self-hosted/gcp/identity#settings-the-application-reads). |
| `MCP_SERVER_URL` | The setup script | `https://<your application host>`: the MCP server's root, not its `/mcp` path |
| `ZITADEL_MCP_JWT_SIGNING_KEY` | The setup script, on its first run | Signs the tokens the MCP server issues. A new key signs every MCP client out. |

The platform chart adds four more keys to the application's Kubernetes Secret itself. Don't put them in your object; if you do, the chart's value wins:

| Key | Comes from |
| - | - |
| `POSTGRES_CONNECTION_STRING` | `<prefix>-postgres-connection-string`, which OpenTofu writes. The queue workers derive their own database from it. |
| `PUSHER_APP_ID`, `PUSHER_KEY`, `PUSHER_SECRET` | Your realtime credentials object |
| `ZITADEL_PAT` | The management token Zitadel's setup job mints in the cluster, read live so a new token propagates on its own |

### Keys not to set

| Key | Why |
| - | - |
| `IS_ON_PREM` | The application refuses to start while it's set, and names the settings that replaced it |
| `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` | Nothing in the installation uses them |
| `GCS_BUCKET_NAME`, `AWS_BUCKET_NAME`, `BUCKET_PREFIX` | Retired. Uploads use `STORAGE_BUCKET_NAME`, which the application values set. |
| `CONTEXT_GRAPH_S3_BUCKET` | Context Graph Versioning isn't supported in a self-hosted installation |
| Any variable that `values/jedify-be.yaml` sets | A plain environment variable overrides the same key from this object, so the value here would be ignored |

## Realtime credentials

| Key | Value |
| - | - |
| `app_id` | **Digits only.** The application's realtime client rejects anything else when it starts, and that crashes every application component, not only the parts that publish. sockudo itself accepts any string, so it looks fine in the secret. |
| `app_key` | A random string. It isn't secret: browsers receive it. |
| `app_secret` | A random string, which signs every publish |

Three things hold these values: sockudo, the application, and the web app, which takes `app_key` when its pods start and hands it to every browser. All three read the one object, so they can't disagree, but the web app picks up a new key only when it restarts. See [Rotate a secret](#rotate-a-secret).

## Kubernetes Secrets

| Namespace | Secret | Source | Holds |
| - | - | - | - |
| `jedify-be` | `app-secrets` | Your application configuration, plus the four keys above | Every application component's environment |
| `jedify` | `litellm-master-key` | `LITELLM_PROXY_API_KEY` from your application configuration | The bundled proxy's master key |
| `jedify` | `sockudo-app` | Your realtime credentials | sockudo's app and, through it, the web app's key |
| `jedify` | `zitadel-db`, `zitadel-masterkey` | OpenTofu's objects | Zitadel's database connection and masterkey |
| `jedify` | `zitadel-bootstrap-admin` | Generated once by External Secrets | The instance administrator's password. Never regenerated: Zitadel was set up with it. |
| `jedify` | `iam-admin-pat` | Zitadel's setup job | The token for Zitadel's management API, used by the application and the setup script |
| `jedify` | `jedify-tls` | You, cert-manager, or a placeholder the chart creates when a certificate map serves the certificate | The Gateway's serving certificate |

## Rotate a secret

<Steps>
  <Step title="Add a new version in Secret Manager">
    Change one key and keep the others. For example, for `COMPONENT_AUTH_TOKEN`:

    ```bash theme={null}
    gcloud secrets versions access latest --secret "${PREFIX}-app-config" --project "$PROJECT_ID" \
      | jq --arg value "$(openssl rand -hex 32)" '.COMPONENT_AUTH_TOKEN = $value' \
      | gcloud secrets versions add "${PREFIX}-app-config" --project "$PROJECT_ID" --data-file=-
    ```

    Secret Manager keeps earlier versions, so you can return to one.
  </Step>

  <Step title="Sync it into the cluster">
    External Secrets reads Secret Manager again every hour. To apply the change now:

    ```bash theme={null}
    kubectl -n jedify-be annotate externalsecret app-secrets force-sync="$(date +%s)" --overwrite
    kubectl -n jedify annotate externalsecret litellm-master-key force-sync="$(date +%s)" --overwrite
    kubectl -n jedify annotate externalsecret sockudo-app force-sync="$(date +%s)" --overwrite
    ```

    Reloader then restarts every application component and the proxy, because they read their environment only when they start.
  </Step>

  <Step title="Restart what Reloader doesn't">
    After a change to the realtime credentials, restart sockudo and the web app, which read their values only when their pods start. Until the web app restarts, browsers get the old key and realtime stays down, with nothing saying so.

    ```bash theme={null}
    kubectl -n jedify rollout restart deploy/jedify-infra-sockudo deploy/jedify-infra-frontend
    ```
  </Step>

  <Step title="Verify">
    ```bash theme={null}
    kubectl get externalsecret -A
    kubectl -n jedify-be get pods
    ```

    Expected: every ExternalSecret shows `SecretSynced`, and the application's pods were restarted a moment ago.
  </Step>
</Steps>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.