Registry Management API
The Registry API is a Quarkus-based credential and configuration gateway that serves as the central secrets broker for ETSI HypO. It acts as a wrapper around HashiCorp Vault, providing secure storage and retrieval of service registry credentials, image pull secrets, Kubernetes kubeconfigs, and Fabric controller credentials. All secrets are scoped to the caller's Keycloak group, enforcing strict multi-tenant isolation.
The service exposes both a REST northbound interface — consumed by ETSI HypO operators — and a Kafka-driven southbound interface consumed by the Package Manager during chart parsing, deployment, activation, and termination flows.
REST API
All REST endpoints are served at port 8091 under the /registry-api root path. Every request must carry a Keycloak JWT in the Authorization: Bearer <token> header.
| Resource | Base path | Purpose |
|---|---|---|
| Image pull secrets | /registry-api/image-pull |
Manage Docker image registry credentials |
| Package registry secrets | /registry-api/package-registry |
Manage Helm / artifact registry credentials |
| Kubernetes configuration | /registry-api/kube-conf |
List stored kubeconfigs and issue terminal access tokens |
| Vault group management | /registry-api/group |
Create, read, update, and delete Vault groups |
| Vault policy management | /registry-api/policy |
Create, read, update, and delete Vault policies |
| Group-policy provisioning | /registry-api/policy-group-flow |
Atomically provision a group with its default policies |
| Fabric Ziti credentials | /registry-api/fabric |
Retrieve Fabric network controller credentials |
| Log level control | /registry-api/admin/logs |
Dynamically change runtime log level |
Image Pull Secrets
| Method | Path | Description |
|---|---|---|
GET |
/secret/{secret-name} |
Retrieve an image pull secret |
GET |
/secrets |
List all image pull secrets for the caller's group |
POST |
/secret/{secret-name} |
Create a new image pull secret |
PATCH |
/secret/{secret-name} |
Update an existing image pull secret |
DELETE |
/secret/{secret-name} |
Delete an image pull secret |
Request body (POST / PATCH):
{
"username": "my-user",
"password": "my-password",
"url": "https://registry.example.com"
}
Package Registry Secrets
| Method | Path | Description |
|---|---|---|
GET |
/secret/{secret-name} |
Retrieve package registry credentials |
GET |
/secrets |
List all package registry secrets for the caller's group |
POST |
/secret/{secret-name} |
Store new package registry credentials |
PATCH |
/secret/{secret-name} |
Update existing package registry credentials |
DELETE |
/secret/{secret-name} |
Delete package registry credentials |
Secret names containing URL path segments (e.g., registry.example.eu/myrepo/charts) are sanitised to valid Vault path keys before storage.
Request body (POST / PATCH):
{
"username": "my-user",
"password": "my-password",
"url": "https://charts.example.com/myrepo"
}
Kubernetes Configuration
| Method | Path | Description |
|---|---|---|
GET |
/secrets |
List all kubeconfigs stored for the caller's group |
GET |
/token/{serviceId}/{id} |
Generate a terminal access token for a stored kubeconfig |
Kubeconfigs are not stored via this REST resource — they arrive through the dedicated Kafka channel described below.
Vault Group and Policy Management
These endpoints provide programmatic access to the Vault identity store. They are typically called during onboarding to provision a new ETSI HypO tenant.
Group operations (/group):
| Method | Path | Description |
|---|---|---|
GET |
/{group-name} |
Retrieve group information from Vault |
POST |
/ |
Create a new Vault group |
PATCH |
/{group-name} |
Update group metadata or attached policies |
DELETE |
/{group-name} |
Delete a Vault group |
Policy operations (/policy):
| Method | Path | Description |
|---|---|---|
GET |
/{policy-name} |
Retrieve a policy and its HCL rules |
POST |
/{policy-name} |
Create a new Vault policy |
PATCH |
/{policy-name} |
Update policy rules |
DELETE |
/{policy-name} |
Delete a policy |
Atomic group-policy provisioning (/policy-group-flow):
| Method | Path | Description |
|---|---|---|
POST |
/ |
Create a single Vault policy covering three secret paths and bind it to a new Vault group in one call |
This endpoint extracts the group name from the caller's Keycloak JWT, creates a single Vault policy named {groupName}_policy containing path rules for image-pull, package-registry, and kubernetes-config, and then creates the Vault group with that policy attached.
If group creation fails, the previously created policy is automatically rolled back.
Kafka API
In addition to the REST interface, the Registry API participates in the ETSI HypO Kafka bus. The Package Manager uses this channel to request credentials asynchronously without holding them itself.
| Topic | Message type | Purpose |
|---|---|---|
get-package-registry-incoming-channel |
KafkaRequestPayload (polymorphic on type) |
Credential requests from the Package Manager |
registry-store-kubernetes-config |
CloudEvent with kubeconfig YAML | Store a kubeconfig in Vault |
registry-retrieve-kubernetes-config |
serviceId string |
Retrieve a kubeconfig from Vault |
create-group-policy-incoming-channel |
GroupPolicyMessage |
Provision a Vault group and its policies |
fabric-ziti-creds-persist-incoming-channel |
FabricAuthCreds |
Persist Fabric Ziti controller credentials |
fabric-ziti-creds-delete-incoming-channel |
FabricAuthCreds |
Delete Fabric Ziti controller credentials |
| Topic | Message type | Purpose |
|---|---|---|
response-package-registry-outgoing-channel |
KafkaResponsePayload (polymorphic) |
Credential response to Package Manager |
registry-response-kubernetes-config-outgoing-channel |
VaultSecretResponseMessage |
Kubeconfig retrieval result |
registry-store-kubernetes-config-result |
CloudEvent result | Kubeconfig store completion |
Credential Request Flow (Package Manager Integration)
The get-package-registry-incoming-channel topic uses a polymorphic message format. The type field of the incoming payload determines the operation:
type value |
Message struct | Purpose |
|---|---|---|
parsing |
RegistryURLRequest |
Fetch Helm / OCI / Git repo credentials for chart acquisition |
deployment |
KubeConfigRequest |
Fetch kubeconfig (and optional image pull secret) for Helm install |
activation |
KubeConfigRequest |
Fetch kubeconfig for service activation or deactivation |
termination |
KubeConfigRequest |
Fetch kubeconfig for Helm uninstall |
Parsing request — sent by the Package Manager when the chart source is a private repository:
{
"type": "parsing",
"serviceOrderRequest": {
"kogitoprocinstanceid": "7aa45064-f4a7-4a25-a7a2-667afb07c3d1",
"serviceOrder": {
"serviceOrderId": "2c4fecbc-c436-4f8c-a5db-4a1159ebad2a",
"serviceId": "790daa4d-7f56-4575-8b64-c558cf518bed",
"serviceRepositoryURL": "https://charts.example.com/myrepo",
"serviceArtifactIdentifier": "my-chart",
"serviceArtifactVersion": "1.2.0"
}
},
"url": "https://charts.example.com/myrepo",
"schedulerNamespace": ""
}
Parsing response — published to response-package-registry-outgoing-channel:
{
"id": "790daa4d-7f56-4575-8b64-c558cf518bed",
"status": "SUCCESS",
"message": "",
"data": {
"type": "parsing",
"serviceOrderRequest": { "..." : "..." },
"repoCredentials": {
"username": "my-user",
"password": "my-password"
}
}
}
Deployment / lifecycle request — sent by the Package Manager before every Helm operation:
{
"type": "deployment",
"serviceOperationRequest": {
"kogitoprocinstanceid": "7aa45064-f4a7-4a25-a7a2-667afb07c3d1",
"serviceOrderId": "2c4fecbc-c436-4f8c-a5db-4a1159ebad2a",
"serviceId": "790daa4d-7f56-4575-8b64-c558cf518bed",
"activateService": true
},
"kubernetesServiceID": "c04f3d66-5350-49ea-8b31-ff325f149232",
"secretName": "my-app-pull-secret"
}
Deployment / lifecycle response — published to response-package-registry-outgoing-channel:
{
"id": "790daa4d-7f56-4575-8b64-c558cf518bed",
"status": "SUCCESS",
"message": "",
"data": {
"type": "deployment",
"serviceOperationRequest": { "..." : "..." },
"kubeConfigAsBase64": "<base64-encoded kubeconfig YAML>",
"imagePullSecret": {
"secretName": "my-app-pull-secret",
"username": "my-user",
"password": "my-password",
"url": "https://registry.example.com"
},
"schedulerNamespace": "p2code-scheduler-system"
}
}
Kubeconfig Store Flow
When a new Kubernetes cluster is registered with ETSI HypO, SONATA publishes the kubeconfig to registry-store-kubernetes-config.
The Registry API decodes the CloudEvent payload, stores the Base64-encoded kubeconfig in Vault, and publishes a completion acknowledgement to registry-store-kubernetes-config-result.
Two storage scopes are supported:
| Scope | Vault path | Use case |
|---|---|---|
CLUSTER (default) |
hypo/kubernetes-config/{group}/{serviceId} |
Full cluster admin kubeconfig |
NAMESPACE_SA |
hypo/kubernetes-sa-config/{group}/{serviceId} |
Namespace-scoped service account kubeconfig |
Vault Path Structure
All secrets are stored in the KV v2 engine. Paths are always scoped to the caller's Keycloak group, ensuring strict multi-tenant isolation:
| Secret type | Vault path | Keys |
|---|---|---|
| Image pull secret | hypo/image-pull/{group}/{secret-name} |
username, password, url |
| Package registry | hypo/package-registry/{group}/{secret-name} |
username, password, url |
| Cluster kubeconfig | hypo/kubernetes-config/{group}/{serviceId} |
kubeConfig (Base64 YAML) |
| Namespace kubeconfig | hypo/kubernetes-sa-config/{group}/{serviceId} |
kubeConfig (Base64 YAML) |
| Fabric Ziti credentials | hypo/fabric-secret/{group}/{controllerId} |
username, password |
| Service order metadata | hypo/service-order-data/{group}/{serviceId} |
schedulerNamespace |
Multi-Tenancy
Every REST and Kafka request carries a Keycloak JWT.
The Registry API extracts the first group from the token's groups claim, then exchanges the JWT for a scoped Vault token via the /auth/jwt/login endpoint.
Vault policies restrict that token exclusively to paths under the group's prefix, so one tenant cannot read or modify another tenant's secrets.
JWT validation differs between the two interfaces:
- REST: Quarkus OIDC intercepts every request before it reaches application code. It fetches Keycloak's public signing keys (JWKS) and cryptographically verifies the JWT signature, expiry (
exp), and issuer (iss). Only after this check passes is the request handled. - Kafka: There is no OIDC filter on the Kafka listeners. The JWT is extracted raw from the Kafka record's
Authorizationheader and its payload is base64-decoded locally to read thegroupsclaim — no signature or expiry verification is performed by the Registry API itself. Vault performs its own validation when the JWT is forwarded to/auth/jwt/login.
Adding Credentials
Package Registry or Helm Repository Credentials
Use these when the chart source (Helm repo, OCI registry, or Git host) requires authentication.
- Call
POST /registry-api/package-registry/secret/{secret-name}with your Keycloak JWT. - Set
{secret-name}to a value that identifies the registry — typically the hostname or URL of the repository. - Provide
usernameandpassword(and optionallyurl) in the request body.
The Package Manager looks up credentials by matching the serviceRepositoryURL field of the incoming ServiceOrder against stored secret names.
Adding Image Pull Secrets
Use these when deployed containers must pull images from a private Docker registry.
- Call
POST /registry-api/image-pull/secret/{secret-name}with your Keycloak JWT. - Choose a
{secret-name}you will reference in the Package Manager's deployment request (secretNamefield). - Provide
username,password, andurlin the request body.
Kubernetes Kubeconfigs
Kubeconfigs are never stored via the REST API. They are pushed to the registry-store-kubernetes-config Kafka topic as a CloudEvent by SONATA after cluster registration.
The Registry API stores the kubeconfig under the service ID and makes it available to the Package Manager on demand.
Vault Group and Policy Provisioning
When onboarding a new ETSI HypO tenant, call POST /registry-api/policy-group-flow/ with the tenant's Keycloak JWT.
The service will:
- Read the group name from the JWT
groupsclaim. - Create a single Vault policy (
{groupName}_policy) with path rules scoped to that group for image-pull, package-registry, and kubernetes-config secrets. - Create a Vault group and attach the policy.
- Roll back the created policy if the group creation step fails.