Tenant Management configuration
The manager requires a stable SESSION_SECRET and TENANCY_SECRET with at least 32 characters, shared by its replicas. Inject them from Kubernetes Secrets. Never include production credentials in a ConfigMap. Register the exact manager service principal independently at SSO, Wallet and Control Plane before enabling provisioning.
The manager uses tenancy.mode: authority for global identity login. Managed
consumers use tenancy.mode: managed. Register both the browser client and the
separate provisioning service client before starting tenant creation.
Authorization deadlines use shared contract constants: 50 seconds of freshness
and renewal after 20 seconds. Consumers allow 10 seconds of clock skew when
accepting a future deadline, then check the stored validUntil without extending
it. These values are not independent deployment settings. See the
availability model before enabling managed mode.
For unattended local startup, initTenants declares canonical UUIDs, names,
slugs, profiles and owner principals from SSO initUsers. The manager queues
normal provisioning locally and retries while receiving services start. Optional
serviceGrants give explicitly configured SSO workload clients access to selected
services without making them human members. SSO workload clients remain bound to
the exact canonical UUID and request a separate audience for each service.
Optional members entries declare an existing SSO principal, an admin or
member role, and grants containing service IDs and permissions. Each member is
applied once per principal, independently of the tenant seed. New members can be
added to existing initialized tenants without changing ownership or resetting
state. Subsequent membership and grant edits survive restarts; changing an
already applied member entry fails with an idempotency conflict.
Initialization creates defaults once. Restarts preserve later membership, grant and lifecycle edits. Removing an entry does not delete a tenant. Changed entries or conflicting IDs/slugs fail; use the management API for later changes.
| Key | Required | Type | Description | Default |
|---|---|---|---|---|
InitialTenantConfig | ||||
initTenants | InitialTenantConfig[] | Create these tenants once at startup through managed provisioning. Restarts preserve memberships, grants and lifecycle changes; removal does not delete tenants | [] | |
initTenants[].tenantId | Yes | String | Explicit canonical UUID, also used in worker execution scopes | |
PrincipalDto | ||||
initTenants[].owner | Yes | PrincipalDto | Existing SSO login principal, for example from SSO initUsers | |
initTenants[].owner.issuer | Yes | String | Registered SSO issuer URL | |
initTenants[].owner.subject | Yes | String | Stable SSO user ID or workload client ID | |
InitialMemberConfig | ||||
initTenants[].members | InitialMemberConfig[] | Additional members applied once per principal, including to existing initialized tenants; restarts preserve later edits | ||
PrincipalDto | ||||
initTenants[].members[].principal | Yes | PrincipalDto | Existing SSO login principal | |
initTenants[].members[].principal.issuer | Yes | String | Registered SSO issuer URL | |
initTenants[].members[].principal.subject | Yes | String | Stable SSO user ID or workload client ID | |
initTenants[].members[].role | Yes | "admin" | "member" | Organization role; ownership stays with the configured owner | |
ManagedAccountGrantDto | ||||
initTenants[].members[].grants | Yes | ManagedAccountGrantDto[] | Initial service permissions for this member | |
initTenants[].members[].grants[].serviceInstanceId | Yes | String | Receiving service selected by the tenant profile | |
initTenants[].members[].grants[].permissions | Yes | String | Initial permissions for this member and service | |
InitialServiceGrantConfig | ||||
initTenants[].serviceGrants | InitialServiceGrantConfig[] | Additional initial service grants, for example tenant-bound workload clients registered in SSO initClients | ||
PrincipalDto | ||||
initTenants[].serviceGrants[].principal | Yes | PrincipalDto | Exact SSO workload issuer and subject | |
initTenants[].serviceGrants[].principal.issuer | Yes | String | Registered SSO issuer URL | |
initTenants[].serviceGrants[].principal.subject | Yes | String | Stable SSO user ID or workload client ID | |
initTenants[].serviceGrants[].serviceInstanceId | Yes | String | Receiving service selected by the tenant profile | |
initTenants[].serviceGrants[].permissions | Yes | String | Initial permissions for this principal and service | |
initTenants[].name | Yes | String | Organization display name | |
initTenants[].slug | Yes | String | Immutable URL slug | |
initTenants[].profile | Yes | String | Operator-selected service profile | |
ExistingTenantServiceGrantConfig | ||||
initServiceGrants | ExistingTenantServiceGrantConfig[] | Apply explicit workload grants once to existing tenants. Does not create human memberships; restarts preserve later revocation. Register tenant-bound workload clients in SSO separately | [] | |
initServiceGrants[].tenantId | Yes | String | Canonical UUID of an existing managed tenant | |
PrincipalDto | ||||
initServiceGrants[].principal | Yes | PrincipalDto | Exact SSO workload issuer and subject | |
initServiceGrants[].principal.issuer | Yes | String | Registered SSO issuer URL | |
initServiceGrants[].principal.subject | Yes | String | Stable SSO user ID or workload client ID | |
initServiceGrants[].serviceInstanceId | Yes | String | Receiving service selected by the tenant profile | |
initServiceGrants[].permissions | Yes | String | Initial permissions for this principal and service | |
SharedDataPlaneConfig | ||||
sharedDataPlanes | SharedDataPlaneConfig[] | Shared worker audiences available to operator-selected profiles | [] | |
sharedDataPlanes[].serviceInstanceId | Yes | String | Unique service instance ID referenced by profiles | |
sharedDataPlanes[].dataplaneId | Yes | String | Worker signaling audience; must match the worker's controlPlane.dataplaneId and an SSO managedSignalingTargets audience | |
AuditModuleConfig | ||||
audit | AuditModuleConfig | Audit logging configuration | ||
audit.enabled | Boolean | Enable audit logging | true | |
audit.minSeverity | "debug" | "info" | "warning" | "error" | "critical" | Minimum severity level to log | "info" | |
audit.logDenied | Boolean | Always log denied access attempts regardless of action type | true | |
audit.logDelegated | Boolean | Log delegated access attempts when enabled, while still respecting action-specific success filters | true | |
audit.logMutations | Boolean | Log successful mutation actions (create, update, delete, manage) | true | |
audit.logExecute | Boolean | Log successful execute actions | false | |
audit.logReads | Boolean | Log successful read actions — disabled by default as reads are frequent and rarely relevant for auditing | false | |
audit.sensitiveResources | Array | Resources logged regardless of minimum severity, while still respecting action-specific success filters | ["w.key","w.credential","sso.user"] | |
AuditHandlersConfig | ||||
audit.handlers | AuditHandlersConfig | Handler configuration | ||
audit.handlers.console | Boolean | Enable console audit log handler | false | |
audit.handlers.database | Boolean | Enable database audit log handler | true | |
audit.handlers.otlp | Boolean | Enable OTLP audit log handler | false | |
OtlpAuditHandlerConfig | ||||
audit.otlp | OtlpAuditHandlerConfig | OTLP audit log handler configuration | ||
audit.otlp.url | String | OTLP HTTP logs endpoint URL | "http://localhost:4318/v1/logs" | |
audit.otlp.headers | Object | Additional HTTP headers to include in OTLP requests | ||
audit.otlp.timeoutMillis | Number | OTLP export timeout in milliseconds | 5000 | |
audit.otlp.concurrencyLimit | Number | Maximum number of concurrent OTLP export requests | 1 | |
audit.otlp.serviceName | String | Service name included on OTLP log attributes | "tsg-dsp-api" | |
audit.otlp.serviceVersion | String | Optional service version included on OTLP log attributes | ||
DatabaseConfig | ||||
db | Yes | DatabaseConfig | Database configuration | |
db.retryAttempts | Number | Connection attempts during application startup, three seconds apart | 10 | |
db.type | Yes | "sqlite" | "postgres" | Type of database | |
db.database | Yes | String | Name of the database | |
db.synchronize | Boolean | Synchronize database schema | false | |
db{type=sqlite} | Yes | SQLiteConfig | Database configuration | |
db{type=sqlite}.retryAttempts | Number | Connection attempts during application startup, three seconds apart | 10 | |
db{type=sqlite}.type | "sqlite" | "postgres" | Type of database | "sqlite" | |
db{type=sqlite}.database | Yes | String | Name of the database | |
db{type=sqlite}.synchronize | Boolean | Synchronize database schema | false | |
db{type=postgres} | Yes | PostgresConfig | Database configuration | |
db{type=postgres}.host | Yes | String | Host of the database | |
db{type=postgres}.port | Yes | Number | Port of the database | |
db{type=postgres}.username | Yes | String | Username of the database | |
db{type=postgres}.password | Yes | String | Password of the database | |
db{type=postgres}.ssl | Object | SSL configuration of the database | false | |
db{type=postgres}.retryAttempts | Number | Connection attempts during application startup, three seconds apart | 10 | |
db{type=postgres}.type | "sqlite" | "postgres" | Type of database | "postgres" | |
db{type=postgres}.database | Yes | String | Name of the database | |
db{type=postgres}.synchronize | Boolean | Synchronize database schema | false | |
ServerConfig | ||||
server | Yes | ServerConfig | Server configuration | |
server.listen | String | IP address the server listens on | "0.0.0.0" | |
server.port | Number | Port the server listens on | 3000 | |
server.publicDomain | String | Public domain of the server | "localhost" | |
server.publicAddress | String | Public address of the server | "http://localhost:3000" | |
server.subPath | String | Sub path of the server | ||
AuthConfig | ||||
auth | Yes | AuthConfig | Management authentication configuration | |
auth.signalingId | String | Receiving plane identity for signaling tokens. Defaults to clientId. | ||
auth.expectedIssuer | String | Expected API token issuer; defaults to the discovered OpenID issuer | ||
auth.expectedAudience | String | Expected API token audience; defaults to clientId. | ||
auth.enabled | Boolean | Enable authentication | true | |
auth.openIdConfigurationURL | String | OpenID configuration URL | ||
auth.callbackURL | URL | Callback URL the auth service will redirect users | ||
auth.redirectURL | URL | Redirect URL to UI after login/logout | ||
auth.clientId | String | Client ID | ||
auth.clientSecret | String | Client secret (required for client_secret_post authentication) | ||
auth.tokenEndpointAuthMethod | "client_secret_post" | "private_key_jwt" | Token endpoint authentication method: client_secret_post (default) or private_key_jwt | "client_secret_post" | |
auth.privateKeyJwk | Object | Private key in JWK format for private_key_jwt authentication. Alternative to privateKeyJwkFile. | ||
auth.privateKeyJwkFile | String | Path to file containing private key JWK for private_key_jwt authentication. Alternative to privateKeyJwk. | ||
auth.permissionPath | String | JSON path to extract permissions from the token | "$.permissions[*]" | |
ProvisioningClientConfig | ||||
provisioning | Yes | ProvisioningClientConfig | Independently bootstrapped operator client; separate from the public browser login client | |
provisioning.clientId | Yes | String | OAuth client ID used for provisioning calls | |
provisioning.clientSecret | String | Client secret, for client_secret_post | ||
provisioning.tokenEndpointAuthMethod | "client_secret_post" | "private_key_jwt" | Token endpoint authentication method | "client_secret_post" | |
provisioning.privateKeyJwk | Object | Private JWK for private_key_jwt | ||
provisioning.privateKeyJwkFile | String | Path to a private JWK file for private_key_jwt | ||
ManagedTenancyConfig | ||||
tenancy | ManagedTenancyConfig | Tenancy authority configuration | ||
tenancy.mode | "managed" | "authority" | Tenancy mode: managed receives Tenant Management state; authority runs Tenant Management with global identity login. Both modes require strict OAuth validation and stable session secrets. | "managed" | |
tenancy.serviceInstanceId | String | Operator-registered receiving service instance | "" | |
tenancy.managementUrl | String | Tenant Management UI URL | ||
tenancy.provisioningIdentities | Object | Exact manager issuer/subject, audience and allowed provisioning operations | [] | |
tenancy.platformPrincipals | Object | Exact human principals permitted to change shared process settings; organization roles grant no platform authority | [] | |
RegisteredService | ||||
sso | Yes | RegisteredService | Operator-controlled issuer and provisioning destinations; never supplied by tenant callers | |
sso.serviceInstanceId | Yes | String | Unique service instance ID referenced by profiles and grants | |
sso.audience | Yes | String | Unique OAuth audience of the service | |
sso.apiUrl | Yes | URL | Base URL of the service's provisioning API | |
sso.uiUrl | URL | Public browser entry point; omit for services without a user interface | ||
sso.kind | Yes | "sso" | "wallet" | "control-plane" | "generic" | Service kind, which selects its provisioning contract | |
sso.outputFields | String | Provisioning outputs exposed to the tenant; only used for generic services | [] | |
sso.configuration | Object | Static configuration sent to generic services on provisioning | {} | |
RegisteredService | ||||
services | RegisteredService[] | Provisioned services that profiles can select | [] | |
services[].serviceInstanceId | Yes | String | Unique service instance ID referenced by profiles and grants | |
services[].audience | Yes | String | Unique OAuth audience of the service | |
services[].apiUrl | Yes | URL | Base URL of the service's provisioning API | |
services[].uiUrl | URL | Public browser entry point; omit for services without a user interface | ||
services[].kind | Yes | "sso" | "wallet" | "control-plane" | "generic" | Service kind, which selects its provisioning contract | |
services[].outputFields | String | Provisioning outputs exposed to the tenant; only used for generic services | [] | |
services[].configuration | Object | Static configuration sent to generic services on provisioning | {} | |
ConnectedApplicationConfig | ||||
applications | ConnectedApplicationConfig[] | Connected use-case app links. Their own APIs still enforce access; these are not provisioning targets | [] | |
applications[].id | Yes | String | undefined | |
applications[].name | Yes | String | undefined | |
applications[].uiUrl | Yes | URL | undefined | |
applications[].serviceInstanceId | Yes | String | Managed service whose tenant permissions authorize the application | |
applications[].profiles | Yes | String | Tenant profiles where this application is offered | |
applications[].permissions | Yes | String | At least one of these service permissions is needed to open the app | |
profiles | Object | Operator-owned service/profile and grant ceilings | {} | |
creators | Object | Exact human principals permitted to create tenants for themselves | [] | |
selfServiceCreation | Boolean | Allow authenticated humans to create tenants with themselves as owner | false | |
platformPrincipals | Object | Exact human platform administrators permitted to provision customer tenants, administer organizations, import tenants and recover owner service access | [] |