Skip to main content
Version: v0.20.0

TSG deployment guide

This guide covers deploying the TNO Security Gateway to Kubernetes with the TSG CLI. For a first participant end to end, start with Getting started. The configuration reference documents every input field.

Prerequisites

Client tools

Helm is not used.

npm install -g @tsg-dsp/cli@latest

Cluster

  • Kubernetes 1.24 or newer. An ecosystem deployment needs roughly 4 CPU and 8 GB of allocatable capacity; a single participant about half that.
  • CloudNativePG 1.30 or newer, for the DatabaseRole CRD each component's database login depends on.
  • An Ingress controller, or the Gateway API CRDs plus a controller.
  • cert-manager, if the TLS Secrets the rendered routes reference should be issued automatically.

tsg deploy checks these against what the bundle actually renders and refuses to start if something is missing or too old. They are cluster-admin concerns; TSG never installs or removes them.

helm repo add cnpg https://cloudnative-pg.github.io/charts
helm upgrade --install cnpg cnpg/cloudnative-pg \
--namespace cnpg-system --create-namespace

Public HTTPS endpoints are required for DID document resolution, even for a single-cluster deployment.

Deployment shapes

One document describes a deployment. Its stacks determine whether it represents one participant, a complete ecosystem, or a managed service.

ShapeThe question it answersExample
ParticipantI am one organisation joining a dataspace somebody else runs.participant.yaml
EcosystemI want the authority and participants on one cluster.ecosystem.yaml
ManagedI operate TSG on behalf of other organisations.multi-tenant wallet stacks

The participant shape is the ordinary production one. The ecosystem shape is for demonstrations, hands-on sessions, and integration environments. It puts the authority and every participant in one namespace, usually in shared database mode so the whole thing fits on a laptop.

The CLI ships more of these under examples/ in the repository, including a composition cookbook and a use-case-app deployment.

Deploying

1. Write the configuration

Start from participant.yaml and change the marked values: the namespace, the admin username, your host, your participant id and name, and the authority's DID, domain and credential type as given to you by whoever runs the dataspace.

Point DNS at your ingress or gateway address before deploying. Certificate issuance and DID resolution both depend on it.

2. Create the Secrets

Rendered output only references credentials, so the Secrets it names must exist first. Supply them with SOPS, Sealed Secrets, External Secrets, or plain kubectl. For a demo, run:

For a participant joining an external authority, first create the namespace and store the pre-authorized code supplied by that authority. The CLI cannot invent this code:

kubectl create namespace tsg-alfa
kubectl -n tsg-alfa create secret generic tsg-alfa-preauth --from-literal=code=YOUR_CODE_HERE
tsg secrets generate participant.yaml --apply

This never overwrites material that already exists.

With auth.clientAuthMethod: private_key_jwt, generate a key pair per client first. The public half is a render input and can be committed. Keep the private half out of Git and deliver it as a Secret:

tsg keys generate alfa wallet
tsg keys generate alfa control-plane

3. Review what would change

tsg diff participant.yaml

This renders to a temporary bundle and shows the difference against the cluster, including anything that would be pruned. Add --verbose for the full object diff. The CLI redacts Secret values.

4. Deploy

tsg deploy participant.yaml

deploy renders, diffs, applies in ordered waves, waits for readiness, and prunes what the previous inventory named and this render no longer does. Use --context to pick a kubeconfig context, and -y for non-interactive runs.

5. Verify

kubectl get pods -n tsg-alfa
tsg status participant.yaml

With the participant example, the services are then reachable at:

  • SSO Bridge: https://alfa.example.com/
  • Wallet: https://alfa.example.com/wallet/
  • Control Plane: https://alfa.example.com/control-plane/
  • Data Plane: https://alfa.example.com/http-data-plane/
  • Dataspace Starter: https://alfa.example.com/dataspace-starter/

Sign in to the SSO Bridge with the administrator credentials and, for anything beyond a test deployment, enable two-factor authentication there.

Continuous deployment

tsg render does not contact a cluster or the network. The same inputs and CLI version produce the same bytes, so you can commit and review the manifests:

tsg render participant.yaml -o gitops/tsg

Argo CD or Flux then owns apply and prune. Do not use tsg deploy against the same resources. Pin spec.images.<component>.digest for a committed bundle so its image references do not change with the CLI version.

The continuous deployment guide has working Flux and Argo CD examples. It also explains ordering, Secret delivery, controller tracking, and the prune settings needed to protect database resources.

Outside a controller-managed deployment, you can apply a bundle rendered earlier without reinterpreting the configuration:

tsg apply gitops/tsg

Ongoing operations

Updating

Change the configuration and rerun tsg diff, then tsg deploy. A full deployment also reconciles removed stacks and retains their data.

Deploying part of a file

tsg deploy ecosystem.yaml -s alfa -s bravo

A stack-selected run never reconciles, because the stacks it did not render are unselected rather than absent. Add --include-infra when the shared infrastructure set also needs to be applied.

Uninstalling

tsg uninstall participant.yaml # retains databases and volumes
tsg uninstall participant.yaml --delete-data # destroys them

Uninstall works from the inventory recorded in the cluster, not from the configuration file, so it removes what was actually deployed.

Gateway API (Envoy Gateway)

The CLI can expose the applications through the Gateway API instead of an Ingress. This is opt-in. You can enable both while moving traffic one host at a time.

routing:
ingress:
enabled: false
gateway:
enabled: true
className: eg
clusterIssuer: letsencrypt

Prerequisites:

  • The Gateway API CRDs and a controller. The default class is Envoy Gateway (eg).
  • cert-manager started with --enable-gateway-api, so it issues certificates for Gateway listeners as it does for ingresses.
  • The eg GatewayClass created with mergeGateways: true.

The mergeGateways setting is easy to miss. TSG renders one Gateway per distinct host, so without it every host gets its own Envoy proxy fleet and its own cloud load balancer. An Ingress controller typically serves every host through one. In a live cluster test, four Gateway objects produced four separate external IPs before mergeGateways was applied.

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: merged-proxy-config
namespace: envoy-gateway-system
spec:
mergeGateways: true
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
parametersRef:
group: gateway.envoyproxy.io
kind: EnvoyProxy
name: merged-proxy-config
namespace: envoy-gateway-system

With mergeGateways: true every Gateway under the eg class shares one Envoy fleet and one external IP, routed by TLS SNI. See Deployment Mode for the constraint this relies on: the (port, protocol, hostname) tuple must be unique across merged listeners, which holds here because each Gateway uses a distinct host.

If you point DNS at the merged IP, reserve it as a static cloud address first. Envoy Gateway creates a Service with a dynamic address, which may change if Kubernetes recreates the Service.

You do not have to choose an owner within a stack. TSG renders the Gateway on the first component of each host and attaches the rest as HTTPRoutes.

Changing what is rendered

The typed configuration covers replicas, resources, nodeSelector, ingress class, and annotations. For other Kubernetes fields, add a patch. The CLI applies it after rendering and before apply:

patches:
- target:
kind: Deployment
allowMultiple: true
merge:
spec:
template:
spec:
imagePullSecrets:
- name: registry-credentials

See Patches for targets, operations and ordering.

For the previous Helm-generating CLI format, follow the manual CLI migration guide. tsg migrate does not convert that format.