Tenant Secrets - EyevinnOSC/community GitHub Wiki
A tenant secret is a named credential stored at the tenant level, shared across all services and instances in your workspace. Unlike service secrets, which are scoped to a single service and must be recreated for each new instance, a tenant secret exists once and can be injected into any service instance through the materialize API.
Choosing between tenant secrets and service secrets? See Secrets vs Parameter Store for a decision guide.
Every tenant secret key must start with either system. or user..
user.* keys are created and managed by you. You can list, read, set, and delete these keys using the /mytenantsecrets API. Use this namespace for credentials you own: API keys, tokens, or any value you want to reuse across multiple service instances without copying it separately for each one.
system.* keys are written by the Open Source Cloud platform. You cannot overwrite or delete them. The platform uses this namespace for credentials it manages on your behalf, such as the Gitea admin token used by the Agentic SDLC pipeline and the SDLC webhook secret. You can read a system.* key to inspect its value, and you can inject it into a service instance via the materialize endpoint — but you cannot write to it.
All endpoints require a valid personal access token in the x-pat-jwt: Bearer <token> header. Replace $OSC_PAT_JWT with your OSC Personal Access Token from Settings → API.
Base URL: https://deploy.svc.prod.osaas.io
GET /mytenantsecrets
Returns a list of key names and their metadata (key, prefix, updatedAt). Values are never returned in the list.
curl -s "https://deploy.svc.prod.osaas.io/mytenantsecrets" \
-H "x-pat-jwt: Bearer $OSC_PAT_JWT"GET /mytenantsecrets/:key
Returns { "key": "...", "value": "..." }.
curl -s "https://deploy.svc.prod.osaas.io/mytenantsecrets/user.my-api-key" \
-H "x-pat-jwt: Bearer $OSC_PAT_JWT"Use PUT to create or update a user.* key (upsert):
PUT /mytenantsecrets/:key
Content-Type: application/json
{ "value": "sk-..." }
curl -X PUT "https://deploy.svc.prod.osaas.io/mytenantsecrets/user.my-api-key" \
-H "x-pat-jwt: Bearer $OSC_PAT_JWT" \
-H "Content-Type: application/json" \
-d '{"value":"sk-..."}'PUT is an upsert: it creates the key if it does not exist and replaces the value if it does. Use PUT for token rotation: write the new credential under the same key name and re-materialize into any services that use it.
To create a key only when it does not yet exist, use POST (returns 409 if the key already exists):
POST /mytenantsecrets/:key
Content-Type: application/json
{ "value": "sk-..." }
Attempting to PUT or POST a system.* key returns HTTP 403.
DELETE /mytenantsecrets/:key
curl -X DELETE "https://deploy.svc.prod.osaas.io/mytenantsecrets/user.my-api-key" \
-H "x-pat-jwt: Bearer $OSC_PAT_JWT"Permanently removes the tenant secret. Any service instances that previously had this value materialized as a service secret retain the materialized copy — they are not affected by the deletion.
Attempting to delete a system.* key returns HTTP 403.
Tenant secrets cannot be referenced directly in service instance parameters. To inject a tenant secret into a service instance, you first materialize it as a service secret.
POST /mytenantsecrets/:key/materialize
Content-Type: application/json
{
"serviceId": "eyevinn-my-service",
"secretName": "apikey"
}
curl -X POST "https://deploy.svc.prod.osaas.io/mytenantsecrets/user.my-api-key/materialize" \
-H "x-pat-jwt: Bearer $OSC_PAT_JWT" \
-H "Content-Type: application/json" \
-d '{"serviceId":"eyevinn-my-service","secretName":"apikey"}'The platform copies the value server-side into a service-scoped secret named apikey for eyevinn-my-service. The API returns:
{
"reference": "{{secrets.apikey}}"
}Pass this reference string as the value of the corresponding parameter when creating or updating a service instance. The orchestrator resolves it to the stored value at pod-creation time — the raw credential never passes through any API argument or MCP call.
This mechanism works for both user.* and system.* keys. For system.* keys, materialization is one way to consume the credential server-side without the raw value appearing in an API response.
When you rotate the tenant secret (PUT a new value), call the materialize endpoint again with the same serviceId and secretName to propagate the updated value to the service.
Use tenant secrets when:
- The same credential applies to multiple services or instances (for example, a shared API key for an external provider).
- You want to manage the credential in one place and push updates to all instances by re-materializing.
- The credential is managed by the platform (
system.*keys).
Use service secrets (via the UI or POST /mysecrets/:serviceId) when:
- The credential is specific to a single service instance.
- You do not plan to share it with other services.
- You are working in the dashboard UI where tenant secrets are not yet exposed as a direct configuration option.
Both types are encrypted at rest and never returned in plaintext by the API after the initial write.
| Method | Path | Description |
|---|---|---|
GET |
/mytenantsecrets |
List all secret key names and metadata (no values) |
GET |
/mytenantsecrets/:key |
Get the value of a single key |
POST |
/mytenantsecrets/:key |
Create a key (409 if already exists) |
PUT |
/mytenantsecrets/:key |
Upsert a key (403 if system.*) |
DELETE |
/mytenantsecrets/:key |
Delete a key (403 if system.*) |
POST |
/mytenantsecrets/:key/materialize |
Copy value into service-secret chain; body: { serviceId, secretName }
|
- My Apps: Git Credentials — credential management for private git repositories
- Developer Guide: Environment Variables — injecting secrets and config into My Apps
- Settings → API — your OSC Personal Access Token