Skip to main content
Version: Next

Configuration reference

A TSG deployment is described by one YAML document. This page is the reference for apiVersion: tsg.dataspac.es/v1alpha2; run tsg --version to see which versions your CLI accepts.

apiVersion: tsg.dataspac.es/v1alpha2
kind: TsgDeployment
metadata:
name: alfa
spec:
namespace: tsg-alfa
dataspace: { ... }
admin: { ... }
stacks: [ ... ]

The CLI rejects unknown fields. Otherwise, a renamed field could be ignored and produce the wrong manifests without an error.

Core concepts​

These terms distinguish the deployment, its runtimes, and the identities hosted by those runtimes.

ConceptWhat it is
spec.dataspaceThe trust domain the stacks in this file join. Names the dataspace and states the authority's DID.
TsgDeploymentThe complete desired deployment described by this file.
spec.stacks[]Deployable TSG runtimes. A stack owns Kubernetes resources, and is the unit of apply, inventory and prune.
stack.managedTenancyManaged service configuration. Organizations are created or imported through Tenant Management.

Several organizations may deploy services for the same dataspace from separate files. Every file states the membership authority explicitly. Organizations are managed runtime records with canonical IDs, service bindings and lifecycle state; the deployment file does not create them from names or tenant slugs.

Document​

FieldTypeRequiredDescription
apiVersionStringYestsg.dataspac.es/v1alpha2
kindStringYesTsgDeployment
metadata.nameString (DNS label)YesDeployment identity. Derives inventory names and ownership labels, so two deployments in one namespace must not share it.
specDeploymentSpecYes

spec​

FieldTypeRequiredDefaultDescription
namespaceString (DNS label)YesKubernetes namespace for everything in this file.
dataspaceDataspaceYesThe trust domain being joined.
adminAdminYesInitial administrator of the SSO bridge.
authAuthClient authentication method for the components.
databaseDatabasePostgreSQL topology.
routingRoutingIngress and Gateway API settings.
imagesImagesImage overrides per component type.
patchesArray<Patch>[]Patches applied to the whole bundle.
extraManifestsArray<String>[]Extra manifest paths, relative to this file.
stacksArray<Stack>YesAt least one deployable runtime.

spec.dataspace​

FieldTypeRequiredDescription
nameStringYesDataspace name, a lowercase DNS label.
authority.didStringYesdid:web: identifier of the participant issuing the membership credential.
authority.domainStringYesHost serving the authority's credential type URLs.
authority.credentialTypeStringYesCredential type the components accept as proof of membership.

spec.admin​

FieldTypeRequiredDefaultDescription
usernameStringYesInitial administrator username.
emailStringDefaults to <username>@example.com.
require2FABooleanfalseForce TOTP enrolment on first login.
passwordSecretSecretRefYesExisting Secret holding the initial password.

spec.auth​

FieldTypeRequiredDefaultDescription
clientAuthMethodStringclient_secret_postclient_secret_post or private_key_jwt.
publicKeysDirStringkeysCommitted directory of public JWKs, relative to this file.

With private_key_jwt, the public JWK is a render input. The renderer does not contact the cluster and cannot read it from a Secret. Generate a pair with tsg keys generate <stack> <client>, which writes keys/<stack>-<client>.jwk to commit and the private half to a git-ignored directory. The CLI refuses a JWK containing a d parameter.

spec.database​

FieldTypeRequiredDefaultDescription
modeStringperStackperStack or shared.
defaults.instancesInteger1CloudNativePG instances per cluster.
defaults.storageSizeString1GiVolume size per instance.

Every component owns its database through a CloudNativePG DatabaseRole. The login role is named <stack>__<component>, and a separate basic-auth Secret holds its password. A component cannot read tables owned by another component, whether they share a stack or a Cluster.

shared puts every stack on one PostgreSQL instance. It saves resources in a demo, but it is not a hard security boundary because all stacks share the instance and its capacity. perStack is the default. Use it between organisations that do not trust each other.

PostgreSQL still grants CONNECT on a database to PUBLIC. Any role in the instance can connect and read catalog metadata such as table names, but table contents remain available only to their owner.

spec.routing​

At least one of ingress.enabled and gateway.enabled must be true. You can enable both while moving hosts from Ingress to Gateway API.

FieldTypeRequiredDefaultDescription
ingress.enabledBooleantrue
ingress.classNameStringnginx
ingress.clusterIssuerStringletsencryptcert-manager issuer annotation.
ingress.annotationsObjectAdded to every rendered Ingress.
gateway.enabledBooleanfalse
gateway.classNameStringegGatewayClass name.
gateway.clusterIssuerStringcert-manager ClusterIssuer annotation.
gateway.issuerStringcert-manager namespaced Issuer annotation.
gateway.redirectHTTPBooleantrueEmit an HTTP listener and an HTTP→HTTPS route.
gateway.allowedRoutesFromStringSameSame or All.
gateway.annotationsObjectAdded to every rendered Gateway.

The CLI renders one Gateway for each distinct host and assigns it to the first component on that host. Other components add an HTTPRoute. See the deployment guide for the mergeGateways requirement.

spec.images​

Image settings are keyed by component type. Set either tag or digest, but not both. If you omit both, the CLI derives the tag from its version.

FieldTypeDescription
controlPlaneImage
ssoBridgeImage
walletImage
tenantManagementImageManager image override.
dataPlanes.<type>ImageKeyed by data plane type, e.g. http-data-plane.
useCaseApps.<type>ImageKeyed by app type, e.g. analytics-orchestration.

Image​

FieldTypeDescription
repositoryStringDefaults to the component's own TSG image.
tagStringDefaults to v<cli-version>.
digestStringsha256:<64 hex>. Pin this for committed bundles.

A digest is immutable, so the rendered imagePullPolicy becomes IfNotPresent; a tag renders Always.

spec.stacks​

FieldTypeRequiredDefaultDescription
idString (DNS label)YesNames every rendered resource and the apply set.
nameStringYesDisplay name.
hostString (DNS name)YesPublic host. No scheme, no path.
routingStringpathpath or subdomain.
database{ instances, storageSize }Per-stack sizing. Rejected in shared mode.
componentsComponents
managedTenancy{ adminUserId, selfServiceCreation }YesStable platform administrator UUID and optional self-service creation flag.
patchesArray<Patch>[]Applied after the global ones, to this stack's set only.
extraManifestsArray<String>[]Paths relative to the configuration file.

With path routing, every component shares one host. The SSO bridge uses the root, the wallet uses /wallet, the control plane uses /control-plane, and a keyed component uses /<key>. This needs one certificate and one DNS record. With subdomain routing, each component gets its own host.

stack.components​

FieldTypeDescription
ssoBridgeWorkloadAlways rendered; this only overrides it.
walletWorkloadAlways rendered; this only overrides it.
controlPlaneWorkload + enabledMust explicitly set enabled: true.
tenantManagementWorkloadMust explicitly declare {} or workload settings.
dataPlanesRecord<key, DataPlane>Keyed by component name.
useCaseAppsRecord<key, UseCaseApp>Keyed by component name.

Wallet and SSO Bridge remain established stack components. Managed tenancy also requires an explicit Control Plane and Tenant Management component. The renderer rejects missing prerequisites rather than adding services to an old topology.

Tenant Management creates or imports organizations and provisions service bindings. Each service has persistent session/encryption Secrets. Browser clients are shared public clients; the manager's provisioning client has platform kind. All API tokens use strict audience validation. Removed auth selectors tokenValidationMode and legacyAccessTokenAudiences are rejected.

DataPlane​

Everything in Workload, plus:

FieldTypeDefaultDescription
typeStringthe keyhttp-data-plane or analytics-data-plane.
subPathStringthe keyPath segment, in path routing.
dnsPrefixStringthe keyDNS label, in subdomain routing.
databaseBooleantrueSet false for a data plane that keeps no state.

The HTTP data plane executes dataflows. Before deployment, provision its owner through Tenant Management, register the worker in the managed Control Plane and import its scoped OAuth credentials into sso-<stack>-<worker>-secret. config.controlPlane must contain the real controlplaneId, dataplaneId and nonempty executionScopes[] with issuer, matching controlPlaneId and canonical tenantId UUID. Set config.auth.openIdConfigurationURL to its managed issuer. The CLI never generates credentials or canonical tenant IDs for these owners.

Analytics workers also need an explicitly provisioned dedicated job namespace, unprivileged job service account and approved image list under config.orchestration. Runtime RBAC is limited to that job namespace, pod reads in the configured worker namespace and get on the exact namespace at cluster scope. See the worker prerequisites.

participant is retained in frozen input schemas but rejected when rendering. Migrate to canonical execution scopes. Dataset metadata and private backend configuration belong to the Control Plane and are published through its API.

UseCaseApp​

Everything in Workload, plus type, subPath and dnsPrefix. Participant seed bindings are rejected.

TypeBehavior
dataspace-starterStatic workload, public shared browser client and service proxy targets.
gaiax-credential-workbenchRequires separate managed server configuration and browser registration; rejected by this renderer.
analytics-orchestrationRequires separate tenant-specific provisioning; rejected by this renderer.

Starter accepts config.clientId, defaulting to dataspace-starter, and config.tenants, defaulting to an empty list. Each tenant choice requires slug, name, canonical tenantId UUID and audience: control-plane-api. These are references to organizations that already exist. The CLI provisions no organization or grant from this list. Removed authorizationMode is rejected.

Component keys share one namespace because they name rendered resources. wallet, control-plane, sso-bridge and tenant-management are reserved.

Workload​

The typed customisation block covers common workload settings. Use a patch for other Kubernetes fields.

FieldTypeDescription
replicasInteger
resourcesObjectrequests and limits, each { cpu, memory }.
nodeSelectorObject
routing.classNameStringOverrides the Ingress or Gateway class for this component.
routing.hostStringExplicit public DNS host in v1alpha2; no scheme, path or wildcard.
routing.annotationsObjectAdded to this component's Ingress, Gateway and HTTPRoute.
configObjectApplication configuration, merged over the rendered defaults.

config is passed to the component's own configuration document. See the per-application configuration references under Applications.

SecretRef​

FieldTypeRequiredDescription
nameStringYesName of an existing Secret in the namespace.
keyStringYesKey within it.

Patches​

The CLI applies patches and extra manifests after rendering and before apply. This composition step covers Kubernetes settings outside the typed schema.

FieldTypeDefaultDescription
targetObjectgroup, version, kind, name, namespace, labelSelector, annotationSelector.
mergeObjectMaps merge recursively, arrays are replaced.
jsonPatchArrayRFC 6902 operations. Required for list surgery.
deleteBooleanfalseRemove the matched resources from the bundle.
optionalBooleanfalseAllow a target that matches nothing.
allowMultipleBooleanfalseAllow a target that matches several resources.
patches:
- target:
kind: Deployment
labelSelector: tsg.dataspac.es/component=control-plane
merge:
spec:
template:
spec:
imagePullSecrets:
- name: registry-credentials
  • Targets are Kustomize-compatible.
  • Patches run in declared order. Global patches run before stack patches.
  • Extra manifests load before patches, so patches can also target added objects.
  • A target matching zero resources fails unless optional: true; one matching several fails unless allowMultiple: true.
  • A deleted resource is absent from the bundle, and therefore prune-eligible.

The CLI adds identity labels before patches, which makes them available to a labelSelector. It validates the labels after patching and rejects changes to them.

Rendered names are part of the contract because patches target them. Component resources are <stack>-tsg-<component>, with suffixes such as -config, -ingress, -gateway, -route, -pvc, -role or -binding. Names are namespace-independent.

Secrets​

Rendered resources contain no credential values. They only reference existing Secrets, for database credentials, OAuth client credentials, private_key_jwt keys, the initial administrator password and persistent session/encryption keys.

Before applying anything, tsg deploy checks that every referenced Secret and key exists. A missing credential then fails at the CLI instead of leaving a workload in CrashLoopBackOff.

Deliver Secrets with SOPS, Sealed Secrets, External Secrets, or kubectl. For a demo:

tsg secrets generate participant.yaml --apply

It never overwrites material that already exists.

Patches, extra manifests and application config are caller-controlled and can still introduce credentials, so inspect those inputs before committing a bundle.

Versioning​

The CLI versions three formats independently:

FormatLives inMarker
Input configyour Git repositoryapiVersion
bundle.jsonrendered outputformatVersion
Inventorythe clusterformatVersion

This separation lets the input schema change without invalidating every bundle, and lets the bundle format change without invalidating cluster inventories. A CLI may read inventory written months earlier. It rejects an inventory format newer than it understands.

A released input version is not edited. Changes that break the input contract use a new version. Migrate a file with:

tsg migrate participant.yaml -w

The frozen v1alpha1 schema remains accepted and upgradeable. Its old seed semantics cannot render against managed-only runtime services. After migrate, remove participant seeds, declare managed tenancy and explicit manager/control plane components, then create or import organizations through Tenant Management. The converter does not assign canonical IDs or import tenant state.

The command rewrites the file at the newest version this CLI serves. It does not preserve comments or key order, so review the diff.

An apiVersion newer than any your CLI serves means the file was written for a newer CLI; upgrade rather than editing the marker.

Production notes​

  • private_key_jwt removes shared client secrets from the deployment. Set auth.clientAuthMethod: private_key_jwt, generate a pair per client with tsg keys generate, and commit only the public halves.
  • require2FA on the admin forces TOTP enrolment on first login.
  • database.mode: perStack gives each stack its own PostgreSQL instance.
  • Pin digests for anything committed, so the bundle and the running image cannot drift apart.
  • Review the rendered output. tsg render does not contact the cluster, so the manifests in a merge request are exactly what the controller will apply.