diff --git a/README.md b/README.md index 9a300ec..0b078b6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This repository contains a Helm chart for deploying an Eclipse BaSyx Go based environment on Kubernetes. -The chart installs the BaSyx Go backend services, a PostgreSQL database, optional Keycloak-based authentication, optional ABAC authorization, ingress resources, certificates, the AAS Web UI and optional supporting runtime tests. +The chart installs the BaSyx Go backend services, a PostgreSQL database, optional Keycloak-based authentication, optional ABAC authorization, ingress resources (or Gateway API `HTTPRoute` resources as an opt-in alternative), certificates, the AAS Web UI and optional supporting runtime tests. The repository follows the common Helm multi-chart layout: @@ -50,6 +50,8 @@ Custom values files live outside the chart, for example: ```text values/values.catena-x.example.yaml values/values.example.yaml +values/values.gatewayapi-managed.example.yaml +values/values.gatewayapi.example.yaml values/values.minimal.yaml values/values.observability.example.yaml values/values.autoscaling.example.yaml @@ -416,6 +418,77 @@ ingress: Use `ingress.className` for AGIC instead of the legacy `kubernetes.io/ingress.class` annotation. Kubernetes rejects manifests when both values are set and do not match exactly. `null` removes an inherited default annotation, which is useful when switching away from nginx and avoiding nginx-specific annotations on non-nginx controllers. +### Gateway API (HTTPRoute) + +As an alternative to Ingress, each service can optionally be exposed through a [Gateway API](https://gateway-api.sigs.k8s.io/) `HTTPRoute` resource instead. This is opt-in and disabled by default per service; Ingress remains the default routing mechanism for the chart. + +Using this feature requires the Gateway API CRDs to already be installed in the cluster, and either a `Gateway` resource that already exists (bring-your-own, the default) or `gatewayApi.gateway.enabled: true` to let the chart create its own (see below). + +Enable `.httpRoute.enabled` per service to render its `HTTPRoute`. Every `HTTPRoute` needs at least one `parentRefs` entry, resolved in this order: + +1. `.httpRoute.parentRefs`, if non-empty. +2. Otherwise the chart-wide `gatewayApi.parentRefs` default. +3. Otherwise, if `gatewayApi.gateway.enabled: true`, a `parentRefs` entry pointing at the Gateway the chart itself creates (see below) - no need to also set `gatewayApi.parentRefs` in that case. +4. If all of the above are empty while `httpRoute.enabled: true`, the chart fails the render with an explicit error instead of emitting an `HTTPRoute` with an invalid empty `spec.parentRefs`, which the Gateway API rejects. + +Example pointing at an existing Gateway and enabling Gateway API routing for Keycloak: + +```yaml +gatewayApi: + parentRefs: + - name: my-gateway + namespace: gateway-system + sectionName: https + +keycloak: + httpRoute: + enabled: true +``` + +A service can override the chart-wide default by setting its own `.httpRoute.parentRefs`, which then takes precedence over `gatewayApi.parentRefs`. + +| Value | Description | +| --- | --- | +| `gatewayApi.parentRefs` | Chart-wide default `parentRefs`, used by any `HTTPRoute` that does not define its own. | +| `.httpRoute.enabled` | Enables rendering an `HTTPRoute` for the service. Disabled by default. | +| `.httpRoute.parentRefs` | Service-local `parentRefs`. Overrides `gatewayApi.parentRefs` when non-empty. | +| `.httpRoute.annotations` | Annotations added to the service's `HTTPRoute` metadata. | +| `.httpRoute.hosts` | Hostnames and paths routed to the service. Uses the Gateway API `pathType` values (`Exact`, `PathPrefix`, `RegularExpression`), which are not the same enum as the Ingress `pathType`. | + +#### Optionally letting the chart create its own Gateway + +A `Gateway` is cluster-operator-owned, shared infrastructure in the Gateway API model - normally one `Gateway` serves `HTTPRoute`s from many applications, and every self-created `Gateway` typically provisions its own LoadBalancer. For that reason `gatewayApi.gateway.enabled` defaults to `false` and bring-your-own via `gatewayApi.parentRefs` remains the primary, recommended path. Enable it for standalone/demo deployments that don't have a pre-existing shared `Gateway` to attach to: + +```yaml +gatewayApi: + gateway: + enabled: true + className: envoy-gateway # GatewayClass name - required, no cluster-portable default + +keycloak: + httpRoute: + enabled: true +``` + +This renders one `Gateway` (named `-gateway` unless `gatewayApi.gateway.name` is set, carrying the same `app.kubernetes.io/*`/`helm.sh/chart` labels as every other chart resource) with a fixed `http` listener and, unless `gatewayApi.gateway.tls.enabled: false`, a fixed `https` listener terminating TLS with the certificate named by `gatewayApi.gateway.tls.secretName` (defaults to `tls.secretName` / `-tls-secret` - the same secret name the Ingress path uses, so the two can share a certificate if you point both at the same issuer). Both listeners are scoped to `host`, matching how the Ingress path is host-scoped too - required for cert-manager's [gateway-shim](https://cert-manager.io/docs/usage/gateway/) to know which hostname to request a certificate for. + +To have cert-manager actually issue that certificate, set `gatewayApi.gateway.issuer` or `gatewayApi.gateway.clusterIssuer`; the chart then annotates the Gateway with `cert-manager.io/issuer`/`cert-manager.io/cluster-issuer` accordingly, so gateway-shim issues the certificate independently of whether any Ingress is ever rendered. This is deliberately its own, separate setting rather than a reuse of `ingress.issuer`/`ingress.clusterIssuer`/`ingress.certificateIssuer` - Gateway API usage should not implicitly depend on the Ingress-shaped values. Point it at the same Issuer name as the Ingress path (e.g. `internal-issuer` when using the internal CA, see `internal.certificateIssuer`) to reuse that certificate, or at a different one to issue the Gateway its own. `gatewayApi.gateway.annotations` always takes precedence over the derived annotation, for full manual control. If you need more control over listeners than these opinionated defaults offer, use the bring-your-own path (`gatewayApi.parentRefs`) against a `Gateway` you manage yourself instead. + +The derived `parentRefs` (see step 3 above) always target the `https` listener while `gatewayApi.gateway.tls.enabled` is `true` (the default). The `http` listener is still created and its port is still exposed, but no `HTTPRoute` attaches to it automatically, and the chart does not configure an HTTP-to-HTTPS redirect. To route plain HTTP traffic for a service instead, set that service's own `.httpRoute.parentRefs` with `sectionName: http` explicitly. + +| Value | Description | +| --- | --- | +| `gatewayApi.gateway.enabled` | Lets the chart create its own `Gateway` instead of requiring one to already exist. Disabled by default. | +| `gatewayApi.gateway.name` | Name of the chart-created `Gateway`. Defaults to `-gateway`. | +| `gatewayApi.gateway.className` | `GatewayClass` name. Required when enabled. | +| `gatewayApi.gateway.annotations` | Annotations added to the `Gateway` metadata. Takes precedence over the derived cert-manager annotation below. | +| `gatewayApi.gateway.issuer` | Namespaced cert-manager `Issuer` name, annotated as `cert-manager.io/issuer`. Independent of `ingress.issuer`. | +| `gatewayApi.gateway.clusterIssuer` | Cert-manager `ClusterIssuer` name, annotated as `cert-manager.io/cluster-issuer`. Independent of `ingress.clusterIssuer`. Ignored when `issuer` is also set. | +| `gatewayApi.gateway.port` | Port for the fixed `http` listener. Defaults to `80`. | +| `gatewayApi.gateway.tls.enabled` | Whether to also render the fixed `https` listener. Defaults to `true`. | +| `gatewayApi.gateway.tls.port` | Port for the `https` listener. Defaults to `443`. | +| `gatewayApi.gateway.tls.secretName` | TLS certificate secret for the `https` listener. Defaults to `tls.secretName` / `-tls-secret`. | + ### Additional CA Certificates BaSyx services sometimes need to call HTTPS endpoints that use private CAs. Add those CAs with `internal.CACertificates.trustStore`. @@ -1974,6 +2047,7 @@ kubectl -n debug -it pod/ \ | `no matches for kind "Certificate"` | cert-manager CRDs are missing. Install cert-manager with CRDs enabled. | | `no matches for kind "Cluster" in version "postgresql.cnpg.io/v1"` | CloudNativePG CRDs are missing. Install CloudNativePG. | | Ingress returns 404 | Check `host`, `paths.*`, ingress class and whether the service itself has a route for that path. | +| HTTPRoute has no effect | Check `.httpRoute.enabled`, that the Gateway API CRDs and the referenced `Gateway` exist in the cluster, and that `parentRefs` (service-local `.httpRoute.parentRefs` or chart-wide `gatewayApi.parentRefs`) resolve to that `Gateway`. | | Pods cannot verify Keycloak TLS | Check the internal CA secret, custom CA mounts and `SSL_CERT_DIR`. | | `Token verification failed: expected audience ...` | Check Keycloak protocol mappers and `environment.common.OIDC_AUDIENCE`. | | `ABAC(model): NO_MATCH` | Check token claims, ABAC object definitions, route patterns and whether pods rolled after config changes. | diff --git a/charts/basyx/Chart.yaml b/charts/basyx/Chart.yaml index 2403c23..fdef00b 100644 --- a/charts/basyx/Chart.yaml +++ b/charts/basyx/Chart.yaml @@ -5,7 +5,7 @@ description: > including AAS registries, repositories, discovery service, and optional Keycloak authentication with ABAC authorization. type: application -version: 3.13.0 +version: 3.14.0 appVersion: "1.0.12" home: https://github.com/eclipse-basyx/charts sources: diff --git a/charts/basyx/templates/_helpers.tpl b/charts/basyx/templates/_helpers.tpl index a662530..1114470 100644 --- a/charts/basyx/templates/_helpers.tpl +++ b/charts/basyx/templates/_helpers.tpl @@ -1160,6 +1160,82 @@ annotations: {{- end }} {{- end }} +{{/* +Name of the Gateway this chart creates when gatewayApi.gateway.enabled is +true. Shared between templates/gateway.yaml and the parentRefs fallback +below so both agree on the same name. +*/}} +{{- define "common.gatewayApi.gatewayName" -}} +{{- .Values.gatewayApi.gateway.name | default (printf "%s-gateway" .Release.Name) -}} +{{- end }} + +{{/* +Cert-manager annotations for the chart-created Gateway's https listener, +derived from gatewayApi.gateway.issuer/clusterIssuer - deliberately its own, +independent config rather than reusing ingress.issuer/clusterIssuer, so +Gateway API usage never implicitly depends on the Ingress-shaped values. +Explicit gatewayApi.gateway.annotations always take precedence over the +derived cert-manager annotation. +*/}} +{{- define "common.gatewayApi.gateway.annotations" -}} +{{- $root := . -}} +{{- $gateway := $root.Values.gatewayApi.gateway -}} +{{- $annotations := dict -}} +{{- if and $root.Values.tls.enabled $gateway.tls.enabled -}} +{{- if $gateway.issuer -}} +{{- $_ := set $annotations "cert-manager.io/issuer" ($gateway.issuer | toString) -}} +{{- else if $gateway.clusterIssuer -}} +{{- $_ := set $annotations "cert-manager.io/cluster-issuer" ($gateway.clusterIssuer | toString) -}} +{{- end -}} +{{- end -}} +{{- range $key, $value := ($gateway.annotations | default dict) -}} +{{- if kindIs "invalid" $value -}} +{{- $_ := unset $annotations $key -}} +{{- else -}} +{{- $_ := set $annotations $key (tpl (print $value) $root) -}} +{{- end -}} +{{- end -}} +{{- if $annotations -}} +{{- toYaml $annotations -}} +{{- end -}} +{{- end }} + +{{/* +Render parentRefs for a Gateway API HTTPRoute. Falls back, in order, to: the +chart-wide default parentRefs (.Values.gatewayApi.parentRefs), then - if the +chart is creating its own Gateway (.Values.gatewayApi.gateway.enabled) - a +parentRefs entry pointing at that Gateway, so enabling gatewayApi.gateway +alone is enough without also duplicating parentRefs. +*/}} +{{- define "common.httpRoute.parentRefs" -}} +{{- $parentRefs := .parentRefs -}} +{{- if not $parentRefs }} +{{- $parentRefs = .root.Values.gatewayApi.parentRefs }} +{{- end }} +{{- if and (not $parentRefs) .root.Values.gatewayApi.gateway.enabled }} +{{- $sectionName := "http" -}} +{{- if .root.Values.gatewayApi.gateway.tls.enabled }} +{{- $sectionName = "https" -}} +{{- end }} +{{- $parentRefs = list (dict "name" (include "common.gatewayApi.gatewayName" .root) "namespace" .root.Release.Namespace "sectionName" $sectionName) }} +{{- end }} +{{- if not $parentRefs }} +{{- fail "httpRoute is enabled but no parentRefs are configured — set .httpRoute.parentRefs, the chart-wide gatewayApi.parentRefs, or gatewayApi.gateway.enabled" }} +{{- end }} +{{- range $parentRefs }} +- name: {{ .name | quote }} + {{- if .namespace }} + namespace: {{ .namespace | quote }} + {{- end }} + {{- if .sectionName }} + sectionName: {{ .sectionName | quote }} + {{- end }} + {{- if .port }} + port: {{ .port }} + {{- end }} +{{- end }} +{{- end }} + {{- define "common.ingressTLS.annotations" -}} {{- if .Values.tls.enabled }} {{- if .Values.ingress.certificateIssuer.enabled }} diff --git a/charts/basyx/templates/aas-discovery/httproute.yaml b/charts/basyx/templates/aas-discovery/httproute.yaml new file mode 100644 index 0000000..d0ab032 --- /dev/null +++ b/charts/basyx/templates/aas-discovery/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.aasDiscovery.enabled -}} +{{- if .Values.aasDiscovery.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-aasDiscovery.fullname" . }} + labels: + {{- include "basyx-aasDiscovery.labels" . | nindent 4 }} + {{- with .Values.aasDiscovery.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.aasDiscovery.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.aasDiscovery.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.aasDiscovery.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-aasDiscovery.fullname" $ }} + port: {{ $.Values.aasDiscovery.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/aas-environment/httproute.yaml b/charts/basyx/templates/aas-environment/httproute.yaml new file mode 100644 index 0000000..e7aa1fe --- /dev/null +++ b/charts/basyx/templates/aas-environment/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.aasEnvironment.enabled -}} +{{- if .Values.aasEnvironment.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-aasEnvironment.fullname" . }} + labels: + {{- include "basyx-aasEnvironment.labels" . | nindent 4 }} + {{- with .Values.aasEnvironment.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.aasEnvironment.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.aasEnvironment.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.aasEnvironment.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-aasEnvironment.fullname" $ }} + port: {{ $.Values.aasEnvironment.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/aas-registry/httproute.yaml b/charts/basyx/templates/aas-registry/httproute.yaml new file mode 100644 index 0000000..0169a5c --- /dev/null +++ b/charts/basyx/templates/aas-registry/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.aasRegistry.enabled -}} +{{- if .Values.aasRegistry.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-aasRegistry.fullname" . }} + labels: + {{- include "basyx-aasRegistry.labels" . | nindent 4 }} + {{- with .Values.aasRegistry.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.aasRegistry.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.aasRegistry.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.aasRegistry.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-aasRegistry.fullname" $ }} + port: {{ $.Values.aasRegistry.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/aas-repository/httproute.yaml b/charts/basyx/templates/aas-repository/httproute.yaml new file mode 100644 index 0000000..9ddf23a --- /dev/null +++ b/charts/basyx/templates/aas-repository/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.aasRepository.enabled -}} +{{- if .Values.aasRepository.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-aasRepository.fullname" . }} + labels: + {{- include "basyx-aasRepository.labels" . | nindent 4 }} + {{- with .Values.aasRepository.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.aasRepository.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.aasRepository.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.aasRepository.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-aasRepository.fullname" $ }} + port: {{ $.Values.aasRepository.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/aas-web-gui/httproute.yaml b/charts/basyx/templates/aas-web-gui/httproute.yaml new file mode 100644 index 0000000..913aad5 --- /dev/null +++ b/charts/basyx/templates/aas-web-gui/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.aasWebGui.enabled }} +{{- if .Values.aasWebGui.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-aasWebGui.fullname" . }} + labels: + {{- include "basyx-aasWebGui.labels" . | nindent 4 }} + {{- with .Values.aasWebGui.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.aasWebGui.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.aasWebGui.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.aasWebGui.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-aasWebGui.fullname" $ }} + port: {{ $.Values.aasWebGui.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/cd-repository/httproute.yaml b/charts/basyx/templates/cd-repository/httproute.yaml new file mode 100644 index 0000000..959fefc --- /dev/null +++ b/charts/basyx/templates/cd-repository/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.cdRepository.enabled -}} +{{- if .Values.cdRepository.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-cdRepository.fullname" . }} + labels: + {{- include "basyx-cdRepository.labels" . | nindent 4 }} + {{- with .Values.cdRepository.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.cdRepository.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.cdRepository.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.cdRepository.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-cdRepository.fullname" $ }} + port: {{ $.Values.cdRepository.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/company-lookup/httproute.yaml b/charts/basyx/templates/company-lookup/httproute.yaml new file mode 100644 index 0000000..5073c13 --- /dev/null +++ b/charts/basyx/templates/company-lookup/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.companyLookup.enabled -}} +{{- if .Values.companyLookup.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-companyLookup.fullname" . }} + labels: + {{- include "basyx-companyLookup.labels" . | nindent 4 }} + {{- with .Values.companyLookup.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.companyLookup.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.companyLookup.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.companyLookup.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-companyLookup.fullname" $ }} + port: {{ $.Values.companyLookup.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/digital-twin-registry/httproute.yaml b/charts/basyx/templates/digital-twin-registry/httproute.yaml new file mode 100644 index 0000000..edc8f39 --- /dev/null +++ b/charts/basyx/templates/digital-twin-registry/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.digitalTwinRegistry.enabled -}} +{{- if .Values.digitalTwinRegistry.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-digitalTwinRegistry.fullname" . }} + labels: + {{- include "basyx-digitalTwinRegistry.labels" . | nindent 4 }} + {{- with .Values.digitalTwinRegistry.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.digitalTwinRegistry.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.digitalTwinRegistry.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.digitalTwinRegistry.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-digitalTwinRegistry.fullname" $ }} + port: {{ $.Values.digitalTwinRegistry.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/dpp-api/httproute.yaml b/charts/basyx/templates/dpp-api/httproute.yaml new file mode 100644 index 0000000..6c74154 --- /dev/null +++ b/charts/basyx/templates/dpp-api/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.dppApi.enabled -}} +{{- if .Values.dppApi.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-dppApi.fullname" . }} + labels: + {{- include "basyx-dppApi.labels" . | nindent 4 }} + {{- with .Values.dppApi.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.dppApi.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.dppApi.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.dppApi.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-dppApi.fullname" $ }} + port: {{ $.Values.dppApi.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/gateway.yaml b/charts/basyx/templates/gateway.yaml new file mode 100644 index 0000000..4fb71c0 --- /dev/null +++ b/charts/basyx/templates/gateway.yaml @@ -0,0 +1,42 @@ +{{- if .Values.gatewayApi.gateway.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: {{ include "common.gatewayApi.gatewayName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "basyx.labels" . | nindent 4 }} + {{- $gatewayAnnotations := include "common.gatewayApi.gateway.annotations" . }} + {{- if $gatewayAnnotations }} + annotations: + {{- $gatewayAnnotations | nindent 4 }} + {{- end }} +spec: + gatewayClassName: {{ required "gatewayApi.gateway.className is required when gatewayApi.gateway.enabled is true" (tpl (print .Values.gatewayApi.gateway.className) .) | quote }} + listeners: + - name: http + hostname: {{ tpl (print .Values.host) . | quote }} + protocol: HTTP + port: {{ .Values.gatewayApi.gateway.port }} + allowedRoutes: + namespaces: + from: Same + {{- if .Values.gatewayApi.gateway.tls.enabled }} + - name: https + # cert-manager's gateway-shim requires an explicit hostname on the + # listener to know which SAN to request - without it, it silently + # skips the listener ("Skipped a listener block: ... hostname cannot + # be empty") and never issues a Certificate for gatewayApi.gateway + # annotations like cert-manager.io/issuer. + hostname: {{ tpl (print .Values.host) . | quote }} + protocol: HTTPS + port: {{ .Values.gatewayApi.gateway.tls.port }} + tls: + mode: Terminate + certificateRefs: + - name: {{ .Values.gatewayApi.gateway.tls.secretName | default .Values.tls.secretName | default (printf "%s-tls-secret" .Release.Name) | quote }} + allowedRoutes: + namespaces: + from: Same + {{- end }} +{{- end }} diff --git a/charts/basyx/templates/keycloak/httproute.yaml b/charts/basyx/templates/keycloak/httproute.yaml new file mode 100644 index 0000000..fbf9c06 --- /dev/null +++ b/charts/basyx/templates/keycloak/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.keycloak.enabled }} +{{- if .Values.keycloak.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-keycloak.fullname" . }} + labels: + {{- include "basyx-keycloak.labels" . | nindent 4 }} + {{- with .Values.keycloak.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.keycloak.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.keycloak.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.keycloak.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-keycloak.fullname" $ }} + port: {{ $.Values.keycloak.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/submodel-registry/httproute.yaml b/charts/basyx/templates/submodel-registry/httproute.yaml new file mode 100644 index 0000000..7d8b0db --- /dev/null +++ b/charts/basyx/templates/submodel-registry/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.submodelRegistry.enabled -}} +{{- if .Values.submodelRegistry.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-submodelRegistry.fullname" . }} + labels: + {{- include "basyx-submodelRegistry.labels" . | nindent 4 }} + {{- with .Values.submodelRegistry.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.submodelRegistry.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.submodelRegistry.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.submodelRegistry.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-submodelRegistry.fullname" $ }} + port: {{ $.Values.submodelRegistry.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/templates/submodel-repository/httproute.yaml b/charts/basyx/templates/submodel-repository/httproute.yaml new file mode 100644 index 0000000..3f93bb4 --- /dev/null +++ b/charts/basyx/templates/submodel-repository/httproute.yaml @@ -0,0 +1,33 @@ +{{- if .Values.submodelRepository.enabled -}} +{{- if .Values.submodelRepository.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "basyx-submodelRepository.fullname" . }} + labels: + {{- include "basyx-submodelRepository.labels" . | nindent 4 }} + {{- with .Values.submodelRepository.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- include "common.httpRoute.parentRefs" (dict "root" $ "parentRefs" .Values.submodelRepository.httpRoute.parentRefs) | nindent 4 }} + hostnames: + {{- range .Values.submodelRepository.httpRoute.hosts }} + - {{ tpl .host $ | quote }} + {{- end }} + rules: + {{- range .Values.submodelRepository.httpRoute.hosts }} + {{- range .paths }} + - matches: + - path: + type: {{ .pathType }} + value: {{ tpl .path $ | quote }} + backendRefs: + - name: {{ include "basyx-submodelRepository.fullname" $ }} + port: {{ $.Values.submodelRepository.service.port }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/basyx/tests/README.md b/charts/basyx/tests/README.md index 759132c..ccc98e3 100644 --- a/charts/basyx/tests/README.md +++ b/charts/basyx/tests/README.md @@ -31,3 +31,5 @@ The suites cover stable chart contracts such as: - optional CPU and memory HorizontalPodAutoscalers for every shared BaSyx Go backend deployment - shared per-pod PostgreSQL pool defaults and Configuration Service propagation - keycloak init resources and a runtime `helm test` realm check +- Gateway API HTTPRoute rendering, parentRefs precedence and fail-fast validation +- optional self-managed Gateway rendering, className validation and derived HTTPRoute parentRefs diff --git a/charts/basyx/tests/gateway_test.yaml b/charts/basyx/tests/gateway_test.yaml new file mode 100644 index 0000000..f034cb2 --- /dev/null +++ b/charts/basyx/tests/gateway_test.yaml @@ -0,0 +1,236 @@ +suite: gateway api gateway +release: + name: basyx + namespace: basyx +templates: + - templates/gateway.yaml + - templates/keycloak/httproute.yaml +tests: + - it: renders no Gateway when gatewayApi.gateway is disabled by default + template: templates/gateway.yaml + asserts: + - hasDocuments: + count: 0 + + - it: fails when gatewayApi.gateway is enabled without a className + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + asserts: + - failedTemplate: + errorPattern: "className" + + - it: renders a Gateway with the default name, class and listeners + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + asserts: + - equal: + path: metadata.name + value: basyx-gateway + - equal: + path: spec.gatewayClassName + value: envoy-gateway + - equal: + path: spec.listeners[0].name + value: http + - equal: + path: spec.listeners[0].port + value: 80 + - equal: + path: spec.listeners[0].hostname + value: basyx.example.com + - equal: + path: spec.listeners[1].name + value: https + - equal: + path: spec.listeners[1].port + value: 443 + - equal: + path: spec.listeners[1].hostname + value: basyx.example.com + - equal: + path: spec.listeners[1].tls.certificateRefs[0].name + value: basyx-tls-secret + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: basyx + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: basyx + - equal: + path: metadata.labels["app.kubernetes.io/managed-by"] + value: Helm + + - it: uses a custom Gateway name when set + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + gatewayApi.gateway.name: custom-gateway + asserts: + - equal: + path: metadata.name + value: custom-gateway + + - it: uses tls.secretName over the release-name default when set + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + tls.secretName: shared-tls-secret + asserts: + - equal: + path: spec.listeners[1].tls.certificateRefs[0].name + value: shared-tls-secret + + - it: omits the https listener when gateway tls is disabled + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + gatewayApi.gateway.tls.enabled: false + asserts: + - lengthEqual: + path: spec.listeners + count: 1 + - equal: + path: spec.listeners[0].name + value: http + + - it: renders custom Gateway annotations + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + gatewayApi.gateway.annotations: + example.com/foo: bar + asserts: + - equal: + path: metadata.annotations["example.com/foo"] + value: bar + + - it: derives a cert-manager issuer annotation from gatewayApi.gateway.issuer + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + tls.enabled: true + gatewayApi.gateway.issuer: internal-issuer + asserts: + - equal: + path: metadata.annotations["cert-manager.io/issuer"] + value: internal-issuer + + - it: derives a cert-manager cluster-issuer annotation from gatewayApi.gateway.clusterIssuer + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + tls.enabled: true + gatewayApi.gateway.clusterIssuer: letsencrypt-prod + asserts: + - equal: + path: metadata.annotations["cert-manager.io/cluster-issuer"] + value: letsencrypt-prod + + - it: does not derive a cert-manager annotation from ingress.issuer or ingress.clusterIssuer + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + tls.enabled: true + ingress.issuer: internal-issuer + ingress.clusterIssuer: letsencrypt-prod + ingress.certificateIssuer.enabled: true + ingress.certificateIssuer.name: ingress-issuer + asserts: + - notExists: + path: metadata.annotations + + - it: lets explicit gatewayApi.gateway.annotations override the derived cert-manager issuer + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + tls.enabled: true + gatewayApi.gateway.issuer: internal-issuer + gatewayApi.gateway.annotations: + cert-manager.io/issuer: custom-issuer + asserts: + - equal: + path: metadata.annotations["cert-manager.io/issuer"] + value: custom-issuer + + - it: does not derive a cert-manager annotation when the Gateway https listener is disabled + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + gatewayApi.gateway.tls.enabled: false + tls.enabled: true + gatewayApi.gateway.issuer: internal-issuer + asserts: + - notExists: + path: metadata.annotations + + - it: does not derive a cert-manager annotation when tls is globally disabled + template: templates/gateway.yaml + set: + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + tls.enabled: false + gatewayApi.gateway.issuer: internal-issuer + asserts: + - notExists: + path: metadata.annotations + + - it: derives HTTPRoute parentRefs from the self-created Gateway when none are set + template: templates/keycloak/httproute.yaml + set: + keycloak.enabled: true + keycloak.httpRoute.enabled: true + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + asserts: + - equal: + path: spec.parentRefs[0].name + value: basyx-gateway + - equal: + path: spec.parentRefs[0].namespace + value: basyx + - equal: + path: spec.parentRefs[0].sectionName + value: https + + - it: derives HTTPRoute parentRefs with the http sectionName when gateway tls is disabled + template: templates/keycloak/httproute.yaml + set: + keycloak.enabled: true + keycloak.httpRoute.enabled: true + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + gatewayApi.gateway.tls.enabled: false + asserts: + - equal: + path: spec.parentRefs[0].sectionName + value: http + + - it: prefers explicit gatewayApi.parentRefs over the self-created Gateway + template: templates/keycloak/httproute.yaml + set: + keycloak.enabled: true + keycloak.httpRoute.enabled: true + gatewayApi.gateway.enabled: true + gatewayApi.gateway.className: envoy-gateway + gatewayApi.parentRefs: + - name: external-gateway + namespace: gateway-system + asserts: + - equal: + path: spec.parentRefs[0].name + value: external-gateway + - equal: + path: spec.parentRefs[0].namespace + value: gateway-system diff --git a/charts/basyx/tests/httproute_test.yaml b/charts/basyx/tests/httproute_test.yaml new file mode 100644 index 0000000..47fec9c --- /dev/null +++ b/charts/basyx/tests/httproute_test.yaml @@ -0,0 +1,123 @@ +suite: gateway api httproute +release: + name: basyx +templates: + - templates/keycloak/httproute.yaml + - templates/aas-registry/httproute.yaml +tests: + - it: renders no keycloak httproute when httpRoute is disabled by default + template: templates/keycloak/httproute.yaml + asserts: + - hasDocuments: + count: 0 + + - it: renders no aas registry httproute when httpRoute is disabled by default + template: templates/aas-registry/httproute.yaml + set: + aasRegistry.enabled: true + asserts: + - hasDocuments: + count: 0 + + - it: falls back to the chart-wide gatewayApi parentRefs when no local override is set + template: templates/keycloak/httproute.yaml + set: + keycloak.enabled: true + keycloak.httpRoute.enabled: true + gatewayApi.parentRefs: + - name: shared-gateway + namespace: gateway-system + asserts: + - equal: + path: spec.parentRefs[0].name + value: shared-gateway + - equal: + path: spec.parentRefs[0].namespace + value: gateway-system + + - it: prefers the component-local parentRefs over the chart-wide default + template: templates/aas-registry/httproute.yaml + set: + aasRegistry.enabled: true + aasRegistry.httpRoute.enabled: true + aasRegistry.httpRoute.parentRefs: + - name: aas-registry-gateway + namespace: aas-registry-ns + gatewayApi.parentRefs: + - name: shared-gateway + namespace: gateway-system + asserts: + - equal: + path: spec.parentRefs[0].name + value: aas-registry-gateway + - equal: + path: spec.parentRefs[0].namespace + value: aas-registry-ns + + - it: renders custom httpRoute annotations + template: templates/keycloak/httproute.yaml + set: + keycloak.enabled: true + keycloak.httpRoute.enabled: true + keycloak.httpRoute.annotations: + example.com/foo: bar + gatewayApi.parentRefs: + - name: shared-gateway + asserts: + - equal: + path: metadata.annotations["example.com/foo"] + value: bar + + - it: renders multiple hosts and paths as hostnames and rule matches + template: templates/aas-registry/httproute.yaml + set: + aasRegistry.enabled: true + aasRegistry.httpRoute.enabled: true + gatewayApi.parentRefs: + - name: shared-gateway + aasRegistry.httpRoute.hosts: + - host: basyx.example.com + paths: + - path: /aas-registry + pathType: PathPrefix + - path: /aas-registry-exact + pathType: Exact + - host: alt.example.com + paths: + - path: /alt-registry + pathType: PathPrefix + asserts: + - equal: + path: spec.hostnames[0] + value: basyx.example.com + - equal: + path: spec.hostnames[1] + value: alt.example.com + - equal: + path: spec.rules[0].matches[0].path.value + value: /aas-registry + - equal: + path: spec.rules[0].matches[0].path.type + value: PathPrefix + - equal: + path: spec.rules[1].matches[0].path.value + value: /aas-registry-exact + - equal: + path: spec.rules[1].matches[0].path.type + value: Exact + - equal: + path: spec.rules[2].matches[0].path.value + value: /alt-registry + - equal: + path: spec.rules[2].matches[0].path.type + value: PathPrefix + + - it: fails when httpRoute is enabled without any parentRefs configured + template: templates/keycloak/httproute.yaml + set: + keycloak.enabled: true + keycloak.httpRoute.enabled: true + gatewayApi.parentRefs: [] + asserts: + - failedTemplate: + errorPattern: "parentRefs" diff --git a/charts/basyx/values.schema.json b/charts/basyx/values.schema.json index 7f5a3d9..afb0e7c 100644 --- a/charts/basyx/values.schema.json +++ b/charts/basyx/values.schema.json @@ -1338,6 +1338,44 @@ } } }, + "gatewayApi": { + "type": "object", + "properties": { + "parentRefs": { + "type": "array", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { "type": "string" }, + "namespace": { "type": "string" }, + "sectionName": { "type": "string" }, + "port": { "type": "integer" } + } + } + }, + "gateway": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "name": { "type": "string" }, + "className": { "type": "string" }, + "annotations": { "type": "object" }, + "issuer": { "type": "string" }, + "clusterIssuer": { "type": "string" }, + "port": { "type": "integer" }, + "tls": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "port": { "type": "integer" }, + "secretName": { "type": "string" } + } + } + } + } + } + }, "general": { "type": "object", "properties": { diff --git a/charts/basyx/values.yaml b/charts/basyx/values.yaml index 9ff8bbb..48b3f8d 100644 --- a/charts/basyx/values.yaml +++ b/charts/basyx/values.yaml @@ -69,6 +69,54 @@ ingress: name: ingress-issuer spec: {} +# Gateway API HTTPRoute - alternative to Ingress for exposing services. +# Requires Gateway API CRDs and a Gateway resource already installed in the +# cluster (see: https://gateway-api.sigs.k8s.io/guides/). Disabled per +# component via .httpRoute.enabled; a component's own +# httpRoute.parentRefs takes precedence, otherwise the list below is used. +gatewayApi: + parentRefs: [] + # parentRefs: + # - name: my-gateway + # namespace: gateway-system + # sectionName: https + + # Optionally let the chart create its own Gateway instead of requiring one + # to already exist (bring-your-own via parentRefs above remains available + # and still takes precedence when explicitly set). Off by default: a + # Gateway is cluster-operator-owned, shared infrastructure in the Gateway + # API model, and every self-created Gateway typically provisions its own + # LoadBalancer - avoid enabling this across multiple releases that could + # otherwise share one Gateway. + gateway: + enabled: false + # Defaults to "-gateway" when empty. + name: "" + # GatewayClass name, e.g. "envoy-gateway". Required when enabled - unlike + # ingress.className, there is no cluster-portable default. + className: "" + annotations: {} + # Namespaced cert-manager Issuer used to annotate the Gateway with + # cert-manager.io/issuer, so cert-manager's gateway-shim issues a + # certificate for the https listener below. Deliberately independent of + # ingress.issuer - set this to the same Issuer name if you want the + # Gateway to reuse the certificate the Ingress path would otherwise use, + # e.g. "internal-issuer" when using the internal CA (see + # internal.certificateIssuer) or the name of an Issuer created via + # ingress.certificateIssuer. + issuer: "" + # cert-manager ClusterIssuer name, annotated as + # cert-manager.io/cluster-issuer. Only one of issuer/clusterIssuer should + # be set; issuer takes precedence when both are. + clusterIssuer: "" + port: 80 + tls: + enabled: true + port: 443 + # Defaults to tls.secretName / "-tls-secret" when empty, + # the same certificate already used by the Ingress path. + secretName: "" + paths: dashboard: /aas-dataspace-dashboard aasDiscovery: /aas-discovery @@ -467,6 +515,16 @@ keycloak: - path: "{{ .Values.paths.keycloak }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.keycloak }}" + pathType: PathPrefix + resources: {} # limits: @@ -575,6 +633,17 @@ submodelRepository: paths: - path: "{{ .Values.paths.submodelRepository }}" pathType: Prefix + + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.submodelRepository }}" + pathType: PathPrefix + environment: # Keep the Submodel Registry in sync when submodels are created, updated or deleted. GENERAL_SUBMODELREGISTRYINTEGRATION: true @@ -674,6 +743,17 @@ submodelRegistry: paths: - path: "{{ .Values.paths.submodelRegistry }}" pathType: Prefix + + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.submodelRegistry }}" + pathType: PathPrefix + environment: {} general: {} server: {} @@ -771,6 +851,16 @@ aasRegistry: - path: "{{ .Values.paths.aasRegistry }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.aasRegistry }}" + pathType: PathPrefix + # Content of application.yaml # central environment variables (will be set in configmap.yaml via tpl interpolation) environment: {} @@ -878,6 +968,16 @@ digitalTwinRegistry: - path: "{{ .Values.paths.digitalTwinRegistry }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.digitalTwinRegistry }}" + pathType: PathPrefix + # Content of application.yaml # central environment variables (will be set in configmap.yaml via tpl interpolation) environment: {} @@ -985,6 +1085,16 @@ aasRepository: - path: "{{ .Values.paths.aasRepository }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.aasRepository }}" + pathType: PathPrefix + # Content of application.yaml # central environment variables (will be set in configmap.yaml via tpl interpolation) environment: @@ -1089,6 +1199,16 @@ aasEnvironment: - path: "{{ .Values.paths.aasEnvironment }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.aasEnvironment }}" + pathType: PathPrefix + # AAS Environment bundles the AAS, submodel, concept description, registry # and discovery APIs in one service. Preconfigured AAS files can be imported # by setting general.aasPreconfigPaths and mounting matching files/directories below. @@ -1197,6 +1317,16 @@ dppApi: - path: "{{ .Values.paths.dppApi }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.dppApi }}" + pathType: PathPrefix + # The DPP API composes Digital Product Passport data with the shared BaSyx # database. The default history settings mirror the BaSyx DPP API example. environment: {} @@ -1298,6 +1428,16 @@ cdRepository: - path: "{{ .Values.paths.cdRepository }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.cdRepository }}" + pathType: PathPrefix + # Content of application.yaml # central environment variables (will be set in configmap.yaml via tpl interpolation) environment: {} @@ -1392,6 +1532,17 @@ companyLookup: paths: - path: "{{ .Values.paths.companyLookup }}" pathType: Prefix + + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.companyLookup }}" + pathType: PathPrefix + environment: {} general: {} server: {} @@ -1488,6 +1639,16 @@ aasDiscovery: - path: "{{ .Values.paths.aasDiscovery }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.aasDiscovery }}" + pathType: PathPrefix + # central environment variables (will be set in configmap.yaml via tpl interpolation) environment: {} general: {} @@ -1622,6 +1783,16 @@ aasWebGui: - path: "{{ .Values.paths.aasWebUi }}" pathType: Prefix + httpRoute: + enabled: false + parentRefs: [] + annotations: {} + hosts: + - host: "{{ .Values.host }}" + paths: + - path: "{{ .Values.paths.aasWebUi }}" + pathType: PathPrefix + resources: {} # limits: # cpu: 500m diff --git a/values/values.gatewayapi-managed.example.yaml b/values/values.gatewayapi-managed.example.yaml new file mode 100644 index 0000000..7e4888e --- /dev/null +++ b/values/values.gatewayapi-managed.example.yaml @@ -0,0 +1,172 @@ +# Example values for a BaSyx Go deployment where the chart creates its own +# Gateway API `Gateway` resource, instead of requiring one to already exist +# (see values.gatewayapi.example.yaml for that bring-your-own alternative, +# which remains the recommended path for anything beyond a standalone/demo +# deployment - a Gateway is normally shared cluster infrastructure, and each +# self-created Gateway typically provisions its own LoadBalancer). +# +# Prerequisite: the target cluster must already have the Gateway API CRDs +# and a Gateway API controller (e.g. Envoy Gateway, Traefik, Contour) +# installed, with a matching GatewayClass. This chart still does not create +# the GatewayClass or the controller itself - only the Gateway. +# +# Copy this file and adapt it for your own cluster: +# +# cp values/values.gatewayapi-managed.example.yaml values/values.my-environment.yaml +# +# Do not commit real passwords, client secrets or private certificate material. + +instanceName: example +host: basyx.example.com + +fullnameOverride: basyx + +tls: + enabled: true + hosts: + - basyx.example.com + +internal: + CACertificates: + trustStore: + useDefaultCAs: true + chartFileDirectory: "" + additionalCACertificates: "" + certificateIssuer: + name: internal-issuer + autocreateCa: true + autocreateCaSecretName: internal-issuer-ca + spec: + ca: + secretName: internal-issuer-ca + +ingress: + # Use this issuer when the chart should create and use its own internal CA. + issuer: internal-issuer + + # For a production setup with an existing cert-manager ClusterIssuer, use this instead: + # clusterIssuer: letsencrypt-prod + # issuer: "" + +# The chart creates its own Gateway (named "basyx-gateway" here, defaults to +# "-gateway" if `name` is left empty) with a fixed `http` +# listener and an `https` listener. No `gatewayApi.parentRefs` needed - it is +# derived automatically to point at this Gateway. +gatewayApi: + gateway: + enabled: true + name: basyx-gateway + className: envoy-gateway # GatewayClass name - matches your installed Gateway API controller + # Independent of ingress.issuer - point at the same Issuer name ("internal-issuer" + # here, matching internal.certificateIssuer below) to reuse that certificate, + # or at a different Issuer/ClusterIssuer to issue the Gateway its own. + issuer: internal-issuer + +database: + clusterName: basyx-database + instances: 1 + storage: + size: 10Gi + +keycloak: + enabled: false + +abac: + enabled: false + +aasDiscovery: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasRegistry: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasRepository: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasEnvironment: + enabled: false + + +dppApi: + enabled: false + + +submodelRegistry: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +submodelRepository: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +cdRepository: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasWebGui: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + infrastructureConfig: + infrastructures: + default: main + main: + name: "BaSyx Go {{ .Values.instanceName }}" + components: + aasDiscovery: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.aasDiscovery }}" + aasRegistry: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.aasRegistry }}" + submodelRegistry: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.submodelRegistry }}" + aasRepository: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.aasRepository }}" + submodelRepository: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.submodelRepository }}" + conceptDescriptionRepository: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.cdRepository }}" + companyLookup: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.companyLookup }}" + security: + type: None + config: null + +companyLookup: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +digitalTwinRegistry: + enabled: false diff --git a/values/values.gatewayapi.example.yaml b/values/values.gatewayapi.example.yaml new file mode 100644 index 0000000..fcdd418 --- /dev/null +++ b/values/values.gatewayapi.example.yaml @@ -0,0 +1,167 @@ +# Example values for a BaSyx Go deployment routed through the Kubernetes +# Gateway API (HTTPRoute) instead of a classic Ingress controller, against a +# Gateway you bring yourself (the recommended path - see +# values.gatewayapi-managed.example.yaml for the alternative where the chart +# creates its own Gateway instead). +# +# Prerequisite: the target cluster must already have the Gateway API CRDs +# installed and an existing `Gateway` resource (e.g. named "basyx-gateway" in +# the "gateway-system" namespace, with a listener named "https"). This chart +# does not create the Gateway itself, only HTTPRoute resources that attach to +# it via `gatewayApi.parentRefs`. +# +# Copy this file and adapt it for your own cluster: +# +# cp values/values.gatewayapi.example.yaml values/values.my-environment.yaml +# +# Do not commit real passwords, client secrets or private certificate material. + +instanceName: example +host: basyx.example.com + +fullnameOverride: basyx + +tls: + enabled: true + hosts: + - basyx.example.com + +internal: + CACertificates: + trustStore: + useDefaultCAs: true + chartFileDirectory: "" + additionalCACertificates: "" + certificateIssuer: + name: internal-issuer + autocreateCa: true + autocreateCaSecretName: internal-issuer-ca + spec: + ca: + secretName: internal-issuer-ca + +ingress: + # Use this issuer when the chart should create and use its own internal CA. + issuer: internal-issuer + + # For a production setup with an existing cert-manager ClusterIssuer, use this instead: + # clusterIssuer: letsencrypt-prod + # issuer: "" + +# Chart-wide default parentRefs used by every component's HTTPRoute unless a +# component sets its own .httpRoute.parentRefs. This must point at +# a Gateway that already exists in the cluster. +gatewayApi: + parentRefs: + - name: basyx-gateway + namespace: gateway-system + sectionName: https + +database: + clusterName: basyx-database + instances: 1 + storage: + size: 10Gi + +keycloak: + enabled: false + +abac: + enabled: false + +aasDiscovery: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasRegistry: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasRepository: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasEnvironment: + enabled: false + + +dppApi: + enabled: false + + +submodelRegistry: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +submodelRepository: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +cdRepository: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +aasWebGui: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + infrastructureConfig: + infrastructures: + default: main + main: + name: "BaSyx Go {{ .Values.instanceName }}" + components: + aasDiscovery: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.aasDiscovery }}" + aasRegistry: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.aasRegistry }}" + submodelRegistry: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.submodelRegistry }}" + aasRepository: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.aasRepository }}" + submodelRepository: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.submodelRepository }}" + conceptDescriptionRepository: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.cdRepository }}" + companyLookup: + baseUrl: "https://{{ .Values.host }}{{ .Values.paths.companyLookup }}" + security: + type: None + config: null + +companyLookup: + enabled: true + ingress: + enabled: false + httpRoute: + enabled: true + + +digitalTwinRegistry: + enabled: false