From 1053c49b50ff141ed6f633e30d1ca48921da8e11 Mon Sep 17 00:00:00 2001 From: Andrew Block Date: Mon, 22 Jun 2026 09:12:29 -0500 Subject: [PATCH 1/2] Added tls termination at a pod level for qtodo Signed-off-by: Andrew Block --- charts/qtodo/templates/_helpers.tpl | 22 +++++++++++++++- charts/qtodo/templates/app-deployment.yaml | 26 ++++++++++++++++--- charts/qtodo/templates/app-route.yaml | 4 +-- charts/qtodo/templates/app-service.yaml | 9 ++++--- .../qtodo/templates/qtodo-network-policy.yaml | 2 +- charts/qtodo/values.yaml | 11 ++++++++ 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/charts/qtodo/templates/_helpers.tpl b/charts/qtodo/templates/_helpers.tpl index bd2b94d2..1260c996 100644 --- a/charts/qtodo/templates/_helpers.tpl +++ b/charts/qtodo/templates/_helpers.tpl @@ -37,4 +37,24 @@ Generate the JWT Audience {{- else }} {{- print .Values.app.vault.audience }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Returns true if the termination is secure (https) and false otherwise +*/}} +{{- define "qtodo.isSecureTermination" }} +{{- if or (eq .Values.app.route.termination "reencrypt") (eq .Values.app.route.termination "passthrough") }} +true +{{- end }} +{{- end }} + +{{/* +Returns the port the application should list on +*/}} +{{- define "qtodo.app.port" -}} +{{- if include "qtodo.isSecureTermination" . -}} +{{ .Values.app.securePort }} +{{- else -}} +{{ .Values.app.insecurePort }} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/charts/qtodo/templates/app-deployment.yaml b/charts/qtodo/templates/app-deployment.yaml index 2c78c92f..e4b30860 100644 --- a/charts/qtodo/templates/app-deployment.yaml +++ b/charts/qtodo/templates/app-deployment.yaml @@ -198,8 +198,8 @@ spec: image: {{ template "qtodo.image" (dict "value" .Values.app.images.main "context" $ "useRegistry" true) }} imagePullPolicy: {{ .Values.app.images.main.pullPolicy }} ports: - - containerPort: 8080 - name: http + - containerPort: {{ template "qtodo.app.port" . }} + name: {{ if (include "qtodo.isSecureTermination" .) }}https{{ else }}http{{ end }} protocol: TCP envFrom: - configMapRef: @@ -219,7 +219,17 @@ spec: - name: QUARKUS_HTTP_HOST value: '0.0.0.0' - name: QUARKUS_HTTP_PORT - value: '8080' + value: {{ .Values.app.insecurePort | quote }} +{{- if include "qtodo.isSecureTermination" . }} + - name: QUARKUS_HTTP_SSL_PORT + value: {{ .Values.app.securePort | quote }} + - name: QUARKUS_TLS_KEY_STORE_PEM_QTODO_CERT + value: /certs/tls.crt + - name: QUARKUS_TLS_KEY_STORE_PEM_QTODO_KEY + value: /certs/tls.key + - name: QUARKUS_HTTP_INSECURE_REQUESTS + value: 'disabled' +{{- end }} - name: QUARKUS_HIBERNATE_ORM_SCHEMA_MANAGEMENT_STRATEGY value: 'drop-and-create' {{- if not .Values.app.spire.enabled }} @@ -273,6 +283,11 @@ spec: - name: ztvp-trusted-ca mountPath: /etc/pki/ca-trust/extracted/pem readOnly: true +{{- end }} +{{- if include "qtodo.isSecureTermination" . }} + - name: tls-certs + mountPath: /certs + readOnly: true {{- end }} resources: {} serviceAccountName: qtodo @@ -304,4 +319,9 @@ spec: configMap: name: qtodo-truststore-java {{- end }} +{{- if include "qtodo.isSecureTermination" . }} + - name: tls-certs + secret: + secretName: {{ .Values.app.tls.secret }} +{{- end }} {{- end }} \ No newline at end of file diff --git a/charts/qtodo/templates/app-route.yaml b/charts/qtodo/templates/app-route.yaml index 0bb8bbc1..a1436eb0 100644 --- a/charts/qtodo/templates/app-route.yaml +++ b/charts/qtodo/templates/app-route.yaml @@ -7,10 +7,10 @@ metadata: name: qtodo spec: port: - targetPort: 8080-tcp + targetPort: {{ printf "%s-tcp" (include "qtodo.app.port" .) }} tls: insecureEdgeTerminationPolicy: Redirect - termination: edge + termination: {{ .Values.app.route.termination }} to: kind: Service name: qtodo diff --git a/charts/qtodo/templates/app-service.yaml b/charts/qtodo/templates/app-service.yaml index ecb46edb..3bfdd699 100644 --- a/charts/qtodo/templates/app-service.yaml +++ b/charts/qtodo/templates/app-service.yaml @@ -3,16 +3,19 @@ kind: Service metadata: annotations: argocd.argoproj.io/sync-wave: '51' + {{- if eq .Values.app.tls.serviceServing true }} + service.beta.openshift.io/serving-cert-secret-name: {{ .Values.app.tls.secret | quote }} + {{- end }} labels: app: qtodo name: qtodo namespace: qtodo spec: ports: - - name: 8080-tcp - port: 8080 + - name: {{ printf "%s-tcp" (include "qtodo.app.port" .) }} + port: {{ template "qtodo.app.port" . }} protocol: TCP - targetPort: 8080 + targetPort: {{ template "qtodo.app.port" . }} selector: app: qtodo sessionAffinity: None diff --git a/charts/qtodo/templates/qtodo-network-policy.yaml b/charts/qtodo/templates/qtodo-network-policy.yaml index 1e2fc5e2..3d358ad6 100644 --- a/charts/qtodo/templates/qtodo-network-policy.yaml +++ b/charts/qtodo/templates/qtodo-network-policy.yaml @@ -17,7 +17,7 @@ spec: # to generate the correct ACLs for host-network ingress traffic. - ports: - protocol: TCP - port: 8080 + port: {{ include "qtodo.app.port" . }} from: - namespaceSelector: matchLabels: diff --git a/charts/qtodo/values.yaml b/charts/qtodo/values.yaml index d8ba6ac5..0cadeddf 100644 --- a/charts/qtodo/values.yaml +++ b/charts/qtodo/values.yaml @@ -15,6 +15,8 @@ global: # QTodo application configuration app: name: qtodo + insecurePort: 8080 + securePort: 8443 images: main: name: quay.io/validatedpatterns/qtodo @@ -62,10 +64,19 @@ app: name: "oidc-client-secret" vaultPath: "secret/data/apps/qtodo/qtodo-oidc-client" + # Route configuration + route: + termination: reencrypt + spire: enabled: true # Enable SPIFFE + OIDC integration by default sidecars: true + # TLS Configuration + tls: + secret: qtodo-tls + serviceServing: true + # Vault configuration for SPIFFE integration # Uses SPIFFE JWT to authenticate and fetch DB password vault: From 3521a66f1d6001a28a7f21041856135e7cadd475 Mon Sep 17 00:00:00 2001 From: Manuel Lorenzo Date: Tue, 23 Jun 2026 16:25:44 +0200 Subject: [PATCH 2/2] Add qtodo e2e documentation Signed-off-by: Manuel Lorenzo --- docs/multi-tier.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/multi-tier.md b/docs/multi-tier.md index 9f322cca..8f76747f 100644 --- a/docs/multi-tier.md +++ b/docs/multi-tier.md @@ -45,3 +45,40 @@ Switch back to the qtodo application and enter the username and password on the Once you have authenticated to RHBK, you will be instructed to change the temporary password and set a more permanent password. Once complete, you will be redirected to the qtodo application verifying the OIDC based authentication functions properly. Feel free to add new items to the list of todos. By being able to add and remove items from the page, the integration between the Quarkus application and the backend PostgreSQL database using credentials sourced from HashiCorp Vault was successful. + +## TLS Termination Options + +The qtodo application uses `reencrypt` TLS termination on the OpenShift Route by default, ensuring that traffic is encrypted end-to-end from the client to the pod. Ingress TLS communication is terminated at the OpenShift Router and reencrypted with a certificate generated using the [Service Serving Certificate feature](https://docs.redhat.com/en/documentation/openshift_container_platform/4.21/html/security_and_compliance/configuring-certificates#add-service-serving). + +### Configuration + +The qtodo Helm chart provides options to control how and where TLS communication is terminated: + +* **`app.route.termination`** — Specifies the TLS termination type for the OpenShift Route + * `reencrypt` (default) — TLS is terminated at the Router and reencrypted to the pod using the certificate specified in `app.tls.secret` + * `passthrough` — TLS traffic passes through the Router without decryption and is terminated at the pod + * `edge` — TLS is terminated at the Router; backend communication uses HTTP + +* **`app.securePort`** — The HTTPS port used by the application (default: `8443`) + * Used when `app.route.termination` is set to `reencrypt` or `passthrough` + +* **`app.insecurePort`** — The HTTP port used by the application (default: `8080`) + * Used when `app.route.termination` is set to `edge` or when TLS is disabled + +* **`app.tls.secret`** — Name of the Kubernetes Secret containing the TLS certificate and key (default: `qtodo-tls`) + * Used for pod-level TLS termination with `reencrypt` or `passthrough` routes + +* **`app.tls.serviceServing`** — Enable automatic certificate generation via Service Serving Certificates (default: `true`) + * When enabled, OpenShift automatically generates and rotates the certificate in `app.tls.secret` + * When using custom certificates (e.g., for `passthrough` mode), set this to `false` and provide your own certificate in the secret + +### Termination Types + +| Termination Type | TLS at Router | TLS to Pod | Certificate Source | Use Case | +| --- | --- | --- | --- | --- | +| `reencrypt` (default) | Yes | Yes | Service Serving Certificate | End-to-end encryption with automatic cert rotation | +| `passthrough` | No | Yes | User-provided in `app.tls.secret` | Custom certificates or strict no-decrypt requirement | +| `edge` | Yes | No | Route certificate | Legacy apps without TLS support | + +> [!NOTE] +> When using `passthrough` termination with custom certificates, ensure the certificate's Subject Alternative Name (SAN) matches the Route hostname. The Service Serving Certificate feature cannot be used in this mode.