From e82d2d136667a878f0d061f0296d50f7b0e99c39 Mon Sep 17 00:00:00 2001 From: EmmanuelNwa247 Date: Fri, 6 Mar 2026 16:43:48 -0500 Subject: [PATCH 1/6] Add Traefik ingress controller chart and ingress/middleware manifests --- charts/traefik/README.md | 40 ++++++ charts/traefik/values-azure.yaml | 126 +++++++++++++++++ charts/traefik/values.yaml | 124 ++++++++++++++++ .../traefik-ingress-dataingestion.yaml | 132 ++++++++++++++++++ k8-manifests/traefik-ingress-main.yaml | 64 +++++++++ k8-manifests/traefik-ingressroute-cached.yaml | 23 +++ .../traefik-middleware-body-limit.yaml | 11 ++ .../traefik-middleware-cached-headers.yaml | 11 ++ k8-manifests/traefik-middleware-headers.yaml | 10 ++ 9 files changed, 541 insertions(+) create mode 100644 charts/traefik/README.md create mode 100644 charts/traefik/values-azure.yaml create mode 100644 charts/traefik/values.yaml create mode 100644 k8-manifests/traefik-ingress-dataingestion.yaml create mode 100644 k8-manifests/traefik-ingress-main.yaml create mode 100644 k8-manifests/traefik-ingressroute-cached.yaml create mode 100644 k8-manifests/traefik-middleware-body-limit.yaml create mode 100644 k8-manifests/traefik-middleware-cached-headers.yaml create mode 100644 k8-manifests/traefik-middleware-headers.yaml diff --git a/charts/traefik/README.md b/charts/traefik/README.md new file mode 100644 index 000000000..d0273485f --- /dev/null +++ b/charts/traefik/README.md @@ -0,0 +1,40 @@ +# Traefik Ingress Controller + +Traefik v3.x replaces the NGINX Ingress Controller for NBS7 Kubernetes deployments. + +[https://doc.traefik.io/traefik/migrate/nginx-to-traefik/] + +## Deployment + +### AWS (EKS) + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update +helm install traefik-crds traefik/traefik-crds --namespace traefik --create-namespace +helm install traefik traefik/traefik --namespace traefik --values values.yaml --skip-crds +``` + +### Azure (AKS) + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update +helm install traefik-crds traefik/traefik-crds --namespace traefik --create-namespace +helm install traefik traefik/traefik --namespace traefik --values values-azure.yaml --skip-crds --set service.spec.loadBalancerIP=XX.XX.XX.XX +``` + +## Files + +| File | Description | +|------|-------------| +| `values.yaml` | Helm values for AWS (EKS) with NLB | +| `values-azure.yaml` | Helm values for Azure (AKS) with internal load balancer | + +## Verification + +```bash +kubectl get pods -n traefik +kubectl get svc -n traefik +kubectl get ingressclass +``` \ No newline at end of file diff --git a/charts/traefik/values-azure.yaml b/charts/traefik/values-azure.yaml new file mode 100644 index 000000000..2a7d650f4 --- /dev/null +++ b/charts/traefik/values-azure.yaml @@ -0,0 +1,126 @@ +# Traefik Ingress Controller - Azure (AKS) Configuration +# Replaces: charts/nginx-ingress/values-azure.yaml +# Chart: traefik/traefik (v3.6.x) + +image: + registry: docker.io + repository: traefik + tag: "v3.6.2" + pullPolicy: IfNotPresent + +deployment: + enabled: true + kind: Deployment + replicas: 1 + podAnnotations: + linkerd.io/inject: enabled + +ingressClass: + enabled: true + isDefaultClass: true + +providers: + kubernetesCRD: + enabled: true + allowCrossNamespace: false + allowEmptyServices: true + kubernetesIngress: + enabled: true + allowEmptyServices: true + publishedService: + enabled: true + +ports: + traefik: + port: 9000 + expose: + default: false + protocol: TCP + + web: + port: 8000 + expose: + default: true + exposedPort: 80 + protocol: TCP + forwardedHeaders: + insecure: true + transport: + respondingTimeouts: + readTimeout: "300s" + writeTimeout: "300s" + idleTimeout: "300s" + + websecure: + port: 8443 + expose: + default: true + exposedPort: 443 + protocol: TCP + http: + tls: {} + forwardedHeaders: + insecure: true + transport: + respondingTimeouts: + readTimeout: "300s" + writeTimeout: "300s" + idleTimeout: "300s" + + metrics: + port: 9100 + expose: + default: false + protocol: TCP + +service: + enabled: true + type: LoadBalancer + spec: + externalTrafficPolicy: "Local" + loadBalancerIP: XX.XX.XX.XX #Populate your private IP here OR by passing it to your helm command + annotations: + #For private IP and private cluster use the following: + service.beta.kubernetes.io/azure-load-balancer-internal: "true" + service.beta.kubernetes.io/azure-load-balancer-internal-health-probe-request-path: "/ping" + prometheus.io/scrape: "true" + prometheus.io/port: "9100" + prometheus.io/path: /metrics + +additionalArguments: + - "--serversTransport.forwardingTimeouts.dialTimeout=300s" + - "--serversTransport.forwardingTimeouts.responseHeaderTimeout=300s" + - "--serversTransport.forwardingTimeouts.idleConnTimeout=300s" + - "--entryPoints.websecure.http.tls" + +metrics: + prometheus: + entryPoint: metrics + addEntryPointsLabels: true + addRoutersLabels: true + addServicesLabels: true + +logs: + general: + level: INFO + access: + enabled: true + +ingressRoute: + dashboard: + enabled: true + entryPoints: ["traefik"] + +resources: + requests: + cpu: "100m" + memory: "128Mi" + limits: + cpu: "500m" + memory: "512Mi" + +rbac: + enabled: true + +# Run the following helm command after updating the load balancer IP: +# helm upgrade --install traefik traefik/traefik --namespace traefik -f values-azure.yaml --set service.spec.loadBalancerIP=XX.XX.XX.XX \ No newline at end of file diff --git a/charts/traefik/values.yaml b/charts/traefik/values.yaml new file mode 100644 index 000000000..9f56dd698 --- /dev/null +++ b/charts/traefik/values.yaml @@ -0,0 +1,124 @@ +# Traefik Ingress Controller - AWS (EKS) Configuration +# Replaces: charts/nginx-ingress/values.yaml +# Chart: traefik/traefik (v3.6.x) + +image: + registry: docker.io + repository: traefik + tag: "v3.6.2" + pullPolicy: IfNotPresent + +deployment: + enabled: true + kind: Deployment + replicas: 1 + podAnnotations: + linkerd.io/inject: enabled + +ingressClass: + enabled: true + isDefaultClass: true + +providers: + kubernetesCRD: + enabled: true + allowCrossNamespace: false + allowEmptyServices: true + kubernetesIngress: + enabled: true + allowEmptyServices: true + publishedService: + enabled: true + +ports: + traefik: + port: 9000 + expose: + default: false + protocol: TCP + +# HTTP entrypoint + web: + port: 8000 + expose: + default: true + exposedPort: 80 + protocol: TCP + forwardedHeaders: + insecure: true + transport: + respondingTimeouts: + readTimeout: "300s" + writeTimeout: "300s" + idleTimeout: "300s" + +# HTTPS entrypoint + websecure: + port: 8443 + expose: + default: true + exposedPort: 443 + protocol: TCP + http: + tls: {} + forwardedHeaders: + insecure: true + transport: + respondingTimeouts: + readTimeout: "300s" + writeTimeout: "300s" + idleTimeout: "300s" + +# Metrics port for Prometheus scraping + metrics: + port: 9100 + expose: + default: false + protocol: TCP + +service: + enabled: true + type: LoadBalancer + annotations: + service.beta.kubernetes.io/aws-load-balancer-type: nlb + prometheus.io/scrape: "true" + prometheus.io/port: "9100" + prometheus.io/path: /metrics + +additionalArguments: + - "--serversTransport.forwardingTimeouts.dialTimeout=300s" + - "--serversTransport.forwardingTimeouts.responseHeaderTimeout=300s" + - "--serversTransport.forwardingTimeouts.idleConnTimeout=300s" + - "--entryPoints.websecure.http.tls" + +metrics: + prometheus: + entryPoint: metrics + addEntryPointsLabels: true + addRoutersLabels: true + addServicesLabels: true + +logs: + general: + level: INFO + access: + enabled: true + +# DASHBOARD +# Traefik includes a built-in dashboard - useful for debugging routes +# Do NOT expose externally in production +ingressRoute: + dashboard: + enabled: true + entryPoints: ["traefik"] + +resources: + requests: + cpu: "100m" + memory: "128Mi" + limits: + cpu: "500m" + memory: "512Mi" + +rbac: + enabled: true \ No newline at end of file diff --git a/k8-manifests/traefik-ingress-dataingestion.yaml b/k8-manifests/traefik-ingress-dataingestion.yaml new file mode 100644 index 000000000..5cea675ad --- /dev/null +++ b/k8-manifests/traefik-ingress-dataingestion.yaml @@ -0,0 +1,132 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: traefik-dataingestion-ingress + namespace: default + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-production" +spec: + ingressClassName: traefik + tls: + - secretName: EXAMPLE_DOMAIN_DATA_HOSTNAME + hosts: + - EXAMPLE_DOMAINDATA_HOSTNAME + rules: + - host: EXAMPLE_DOMAIN_DATA_HOSTNAME + http: + paths: + # Data Ingestion Service + - path: "/ingestion/" + pathType: Prefix + backend: + service: + name: dataingestion-service + port: + number: 8081 + + # Reporting Services + - path: "/reporting/person-svc/" + pathType: Prefix + backend: + service: + name: person-reporting-service + port: + number: 8091 + - path: "/reporting/organization-svc/" + pathType: Prefix + backend: + service: + name: organization-reporting-service + port: + number: 8092 + - path: "/reporting/investigation-svc/" + pathType: Prefix + backend: + service: + name: investigation-reporting-service + port: + number: 8093 + - path: "/reporting/observation-svc/" + pathType: Prefix + backend: + service: + name: observation-reporting-service + port: + number: 8094 + - path: "/reporting/post-processing-svc/" + pathType: Prefix + backend: + service: + name: post-processing-reporting-service + port: + number: 8095 + - path: "/reporting/ldfdata-svc/" + pathType: Prefix + backend: + service: + name: ldfdata-reporting-service + port: + number: 8096 + + # Data Processing Service + - path: "/rti/" + pathType: Prefix + backend: + service: + name: data-processing-service + port: + number: 8082 + + # NND Service + - path: "/extraction/" + pathType: Prefix + backend: + service: + name: nnd-service + port: + number: 8083 + + # SRTE Data Service + - path: "/data/" + pathType: Prefix + backend: + service: + name: srte-data-service + port: + number: 8084 + + # Data Extraction Service + - path: "/data-extraction/" + pathType: Prefix + backend: + service: + name: data-extraction-service + port: + number: 8090 + + # Case Notification Service + - path: "/case-notification/" + pathType: Prefix + backend: + service: + name: case-notification-service + port: + number: 8089 + + # XML HL7 Parser Service + - path: "/hl7-parser/" + pathType: Prefix + backend: + service: + name: xml-hl7-parser-service + port: + number: 8088 + + # Data Compare API Service + - path: "/comparison/" + pathType: Prefix + backend: + service: + name: data-compare-api-service + port: + number: 8097 \ No newline at end of file diff --git a/k8-manifests/traefik-ingress-main.yaml b/k8-manifests/traefik-ingress-main.yaml new file mode 100644 index 000000000..60a456a46 --- /dev/null +++ b/k8-manifests/traefik-ingress-main.yaml @@ -0,0 +1,64 @@ +# This is a DUPLICATE of the Helm-managed main-ingress-resource, configured +# for Traefik instead of NGINX. It allows testing Traefik routing without +# modifying any existing Helm charts. + +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: traefik-main-ingress + namespace: default + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-production" + traefik.ingress.kubernetes.io/router.middlewares: default-nbs-custom-headers@kubernetescrd,default-body-size-limit@kubernetescrd +spec: + ingressClassName: traefik + tls: + - secretName: app.EXAMPLE_DOMAIN + hosts: + - app.EXAMPLE_DOMAIN + rules: + - host: app.EXAMPLE_DOMAIN + http: + paths: + - path: "/auth/realms/nbs-users/" + pathType: Prefix + backend: + service: + name: keycloak + port: + name: http + - path: "/auth/robots.txt" + pathType: Exact + backend: + service: + name: keycloak + port: + name: http + - path: "/auth/js/" + pathType: Prefix + backend: + service: + name: keycloak + port: + name: http + - path: "/auth/resources/" + pathType: Prefix + backend: + service: + name: keycloak + port: + name: http + - path: /favicon.ico + pathType: Prefix + backend: + service: + name: nbs-gateway-svc + port: + number: 8000 + - path: "/" + pathType: Prefix + backend: + service: + name: nbs-gateway-svc + port: + number: 8000 \ No newline at end of file diff --git a/k8-manifests/traefik-ingressroute-cached.yaml b/k8-manifests/traefik-ingressroute-cached.yaml new file mode 100644 index 000000000..2563f2968 --- /dev/null +++ b/k8-manifests/traefik-ingressroute-cached.yaml @@ -0,0 +1,23 @@ +# This is the Traefik equivalent of the Helm-managed main-ingress-resource-cached. +# Uses IngressRoute CRD because the regex path pattern cannot be expressed +# with standard Kubernetes Ingress pathType (Prefix/Exact). + +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: traefik-cached-ingress + namespace: default +spec: + entryPoints: + - websecure + routes: + - match: "Host(`app.EXAMPLE_DOMAIN`) && PathRegexp(`^/(?!auth|ecr-viewer|orchestration).+\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$`)" + kind: Rule + services: + - name: nbs-gateway-svc + port: 8000 + middlewares: + - name: nbs-cached-headers + namespace: default + tls: + secretName: app.EXAMPLE_DOMAIN \ No newline at end of file diff --git a/k8-manifests/traefik-middleware-body-limit.yaml b/k8-manifests/traefik-middleware-body-limit.yaml new file mode 100644 index 000000000..70cd3ab50 --- /dev/null +++ b/k8-manifests/traefik-middleware-body-limit.yaml @@ -0,0 +1,11 @@ +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: body-size-limit + namespace: default +spec: + buffering: + maxRequestBodyBytes: 104857600 + memRequestBodyBytes: 10485760 + maxResponseBodyBytes: 0 + memResponseBodyBytes: 1048576 \ No newline at end of file diff --git a/k8-manifests/traefik-middleware-cached-headers.yaml b/k8-manifests/traefik-middleware-cached-headers.yaml new file mode 100644 index 000000000..bdfeced95 --- /dev/null +++ b/k8-manifests/traefik-middleware-cached-headers.yaml @@ -0,0 +1,11 @@ +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: nbs-cached-headers + namespace: default +spec: + headers: + customResponseHeaders: + X-Frame-Options: "Allow" + Cross-Origin-Opener-Policy: "same-origin" + Cache-Control: "max-age=1209600, immutable" \ No newline at end of file diff --git a/k8-manifests/traefik-middleware-headers.yaml b/k8-manifests/traefik-middleware-headers.yaml new file mode 100644 index 000000000..a2f671f3a --- /dev/null +++ b/k8-manifests/traefik-middleware-headers.yaml @@ -0,0 +1,10 @@ +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: nbs-custom-headers + namespace: default +spec: + headers: + customResponseHeaders: + X-Frame-Options: "Allow" + Cross-Origin-Opener-Policy: "same-origin" \ No newline at end of file From 8c134db530f916d003a80e8d25523a90eea2ce57 Mon Sep 17 00:00:00 2001 From: EmmanuelNwa247 Date: Mon, 9 Mar 2026 19:47:21 -0400 Subject: [PATCH 2/6] Add Traefik ingress controller chart and ingress --- .../templates/traefik-ingress.yaml | 85 +++++++++++-------- charts/dataingestion-service/values.yaml | 5 +- .../templates/traefik-ingress.yaml | 29 ++++--- .../traefik-ingressroute-cached.yaml | 29 +++++++ .../templates/traefik-middlewares.yaml | 63 ++++++++++++++ charts/modernization-api/values.yaml | 9 +- charts/traefik/values-azure.yaml | 6 -- charts/traefik/values.yaml | 6 -- k8-manifests/traefik-ingressroute-cached.yaml | 23 ----- .../traefik-middleware-body-limit.yaml | 11 --- .../traefik-middleware-cached-headers.yaml | 11 --- k8-manifests/traefik-middleware-headers.yaml | 10 --- 12 files changed, 170 insertions(+), 117 deletions(-) rename k8-manifests/traefik-ingress-dataingestion.yaml => charts/dataingestion-service/templates/traefik-ingress.yaml (53%) rename k8-manifests/traefik-ingress-main.yaml => charts/modernization-api/templates/traefik-ingress.yaml (60%) create mode 100644 charts/modernization-api/templates/traefik-ingressroute-cached.yaml create mode 100644 charts/modernization-api/templates/traefik-middlewares.yaml delete mode 100644 k8-manifests/traefik-ingressroute-cached.yaml delete mode 100644 k8-manifests/traefik-middleware-body-limit.yaml delete mode 100644 k8-manifests/traefik-middleware-cached-headers.yaml delete mode 100644 k8-manifests/traefik-middleware-headers.yaml diff --git a/k8-manifests/traefik-ingress-dataingestion.yaml b/charts/dataingestion-service/templates/traefik-ingress.yaml similarity index 53% rename from k8-manifests/traefik-ingress-dataingestion.yaml rename to charts/dataingestion-service/templates/traefik-ingress.yaml index 5cea675ad..1738e6cf1 100644 --- a/k8-manifests/traefik-ingress-dataingestion.yaml +++ b/charts/dataingestion-service/templates/traefik-ingress.yaml @@ -1,132 +1,143 @@ +{{/* +Traefik Ingress - Data Ingestion and Reporting Service routes +Replaces: k8s-manifests/traefik-ingress-dataingestion.yaml +Only rendered when traefikIngress.enabled is true. +Includes body-size-limit middleware. +*/}} +{{- if .Values.traefikIngress.enabled }} +{{- $fullName := include "dataingestion-service.fullname" . -}} +{{- $svcPort := .Values.service.port -}} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: traefik-dataingestion-ingress - namespace: default + name: {{ $fullName }}-traefik-ingress + labels: + {{- include "dataingestion-service.labels" . | nindent 4 }} annotations: cert-manager.io/cluster-issuer: "letsencrypt-production" + traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-body-size-limit@kubernetescrd spec: ingressClassName: traefik tls: - - secretName: EXAMPLE_DOMAIN_DATA_HOSTNAME + - secretName: {{ .Values.ingressHost }} hosts: - - EXAMPLE_DOMAINDATA_HOSTNAME + - {{ .Values.ingressHost }} rules: - - host: EXAMPLE_DOMAIN_DATA_HOSTNAME + - host: {{ .Values.ingressHost }} http: paths: - # Data Ingestion Service - path: "/ingestion/" pathType: Prefix backend: service: - name: dataingestion-service + name: {{ $fullName }} port: - number: 8081 - - # Reporting Services + number: {{ $svcPort }} + {{- if eq .Values.reportingService.enabled "true" }} - path: "/reporting/person-svc/" pathType: Prefix backend: service: name: person-reporting-service port: - number: 8091 + number: {{ .Values.reportingService.personReportingServicePort }} - path: "/reporting/organization-svc/" pathType: Prefix backend: service: name: organization-reporting-service port: - number: 8092 + number: {{ .Values.reportingService.organizationReportingServicePort }} - path: "/reporting/investigation-svc/" pathType: Prefix backend: service: name: investigation-reporting-service port: - number: 8093 + number: {{ .Values.reportingService.investigationReportingServicePort }} - path: "/reporting/observation-svc/" pathType: Prefix backend: service: name: observation-reporting-service port: - number: 8094 + number: {{ .Values.reportingService.observationReportingServicePort }} - path: "/reporting/post-processing-svc/" pathType: Prefix backend: service: name: post-processing-reporting-service port: - number: 8095 + number: {{ .Values.reportingService.postProcessingReportingServicePort }} - path: "/reporting/ldfdata-svc/" pathType: Prefix backend: service: name: ldfdata-reporting-service port: - number: 8096 - - # Data Processing Service + number: {{ .Values.reportingService.ldfdataReportingServicePort }} + {{- end }} + {{- if eq .Values.dataprocessingService.enabled "true" }} - path: "/rti/" pathType: Prefix backend: service: name: data-processing-service port: - number: 8082 - - # NND Service + number: {{ .Values.dataprocessingService.port }} + {{- end }} + {{- if eq .Values.nndService.enabled "true" }} - path: "/extraction/" pathType: Prefix backend: service: name: nnd-service port: - number: 8083 - - # SRTE Data Service + number: {{ .Values.nndService.port }} + {{- end }} + {{- if eq .Values.srtedataService.enabled "true" }} - path: "/data/" pathType: Prefix backend: service: name: srte-data-service port: - number: 8084 - - # Data Extraction Service + number: {{ .Values.srtedataService.port }} + {{- end }} + {{- if eq .Values.dataExtraction.enabled "true" }} - path: "/data-extraction/" pathType: Prefix backend: service: name: data-extraction-service port: - number: 8090 - - # Case Notification Service + number: {{ .Values.dataExtraction.port }} + {{- end }} + {{- if eq .Values.caseNotification.enabled "true" }} - path: "/case-notification/" pathType: Prefix backend: service: name: case-notification-service port: - number: 8089 - - # XML HL7 Parser Service + number: {{ .Values.caseNotification.port }} + {{- end }} + {{- if eq .Values.xmlHl7Parser.enabled "true" }} - path: "/hl7-parser/" pathType: Prefix backend: service: name: xml-hl7-parser-service port: - number: 8088 - - # Data Compare API Service + number: {{ .Values.xmlHl7Parser.port }} + {{- end }} + {{- if eq .Values.compare.enabled "true" }} - path: "/comparison/" pathType: Prefix backend: service: name: data-compare-api-service port: - number: 8097 \ No newline at end of file + number: {{ .Values.compare.port }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/dataingestion-service/values.yaml b/charts/dataingestion-service/values.yaml index 02ecf5fa3..2d0154f3e 100644 --- a/charts/dataingestion-service/values.yaml +++ b/charts/dataingestion-service/values.yaml @@ -69,13 +69,16 @@ compare: port: 8085 ingress: - enabled: true + enabled: false className: "nginx" tls: - secretName: "data.EXAMPLE_DOMAIN" hosts: - "data.EXAMPLE_DOMAIN" +traefikIngress: + enabled: true + resources: {} autoscaling: diff --git a/k8-manifests/traefik-ingress-main.yaml b/charts/modernization-api/templates/traefik-ingress.yaml similarity index 60% rename from k8-manifests/traefik-ingress-main.yaml rename to charts/modernization-api/templates/traefik-ingress.yaml index 60a456a46..ed02055eb 100644 --- a/k8-manifests/traefik-ingress-main.yaml +++ b/charts/modernization-api/templates/traefik-ingress.yaml @@ -1,25 +1,30 @@ -# This is a DUPLICATE of the Helm-managed main-ingress-resource, configured -# for Traefik instead of NGINX. It allows testing Traefik routing without -# modifying any existing Helm charts. - +{{/* +Traefik Ingress - Main application routes (KeyCloak + NBS Gateway) +Replaces: k8s-manifests/traefik-ingress-main.yaml +Only rendered when traefikIngress.enabled is true. +Only one ingress type should be enabled: nginx (ingress), istio (istioGatewayIngress), or traefik (traefikIngress). +*/}} +{{- if .Values.traefikIngress.enabled }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: traefik-main-ingress - namespace: default + name: {{ include "modernization-api.fullname" . }}-traefik-ingress + labels: + {{- include "modernization-api.labels" . | nindent 4 }} annotations: cert-manager.io/cluster-issuer: "letsencrypt-production" - traefik.ingress.kubernetes.io/router.middlewares: default-nbs-custom-headers@kubernetescrd,default-body-size-limit@kubernetescrd + traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-nbs-custom-headers@kubernetescrd,{{ .Release.Namespace }}-body-size-limit@kubernetescrd spec: ingressClassName: traefik tls: - - secretName: app.EXAMPLE_DOMAIN + - secretName: {{ .Values.ingressHost }} hosts: - - app.EXAMPLE_DOMAIN + - {{ .Values.ingressHost }} rules: - - host: app.EXAMPLE_DOMAIN + - host: {{ .Values.ingressHost }} http: paths: + # KeyCloak auth routes - path: "/auth/realms/nbs-users/" pathType: Prefix backend: @@ -48,6 +53,7 @@ spec: name: keycloak port: name: http + # NBS Gateway routes - path: /favicon.ico pathType: Prefix backend: @@ -61,4 +67,5 @@ spec: service: name: nbs-gateway-svc port: - number: 8000 \ No newline at end of file + number: 8000 +{{- end }} \ No newline at end of file diff --git a/charts/modernization-api/templates/traefik-ingressroute-cached.yaml b/charts/modernization-api/templates/traefik-ingressroute-cached.yaml new file mode 100644 index 000000000..c2757d601 --- /dev/null +++ b/charts/modernization-api/templates/traefik-ingressroute-cached.yaml @@ -0,0 +1,29 @@ +{{/* +Traefik IngressRoute - Cached static assets with regex path matching +Replaces: k8s-manifests/traefik-ingressroute-cached.yaml +Uses IngressRoute CRD because regex path patterns cannot be expressed +with standard Kubernetes Ingress pathType (Prefix/Exact). +Only rendered when traefikIngress.enabled is true. +*/}} +{{- if .Values.traefikIngress.enabled }} +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: {{ include "modernization-api.fullname" . }}-traefik-cached + labels: + {{- include "modernization-api.labels" . | nindent 4 }} +spec: + entryPoints: + - websecure + routes: + - match: "Host(`{{ .Values.ingressHost }}`) && PathRegexp(`^/(?!auth|ecr-viewer|orchestration).+\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$`)" + kind: Rule + services: + - name: nbs-gateway-svc + port: 8000 + middlewares: + - name: nbs-cached-headers + namespace: {{ .Release.Namespace }} + tls: + secretName: {{ .Values.ingressHost }} +{{- end }} \ No newline at end of file diff --git a/charts/modernization-api/templates/traefik-middlewares.yaml b/charts/modernization-api/templates/traefik-middlewares.yaml new file mode 100644 index 000000000..f55a2a50d --- /dev/null +++ b/charts/modernization-api/templates/traefik-middlewares.yaml @@ -0,0 +1,63 @@ +{{/* +Traefik Middleware CRDs - Response headers, body size limits, cached headers +Replaces: + - k8s-manifests/traefik-middleware-headers.yaml + - k8s-manifests/traefik-middleware-body-limit.yaml + - k8s-manifests/traefik-middleware-cached-headers.yaml +Only rendered when traefikIngress.enabled is true. +*/}} +{{- if .Values.traefikIngress.enabled }} +# ============================================================================= +# Custom Response Headers (replaces NGINX configuration-snippet) +# Replaces: nginx.ingress.kubernetes.io/configuration-snippet: +# more_set_headers "X-Frame-Options: Allow"; +# more_set_headers "Cross-Origin-Opener-Policy: same-origin"; +# ============================================================================= +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: nbs-custom-headers + labels: + {{- include "modernization-api.labels" . | nindent 4 }} + app.kubernetes.io/component: ingress +spec: + headers: + customResponseHeaders: + X-Frame-Options: "Allow" + Cross-Origin-Opener-Policy: "same-origin" +--- +# ============================================================================= +# Body Size Limit (replaces NGINX proxy-body-size: "100m") +# ============================================================================= +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: body-size-limit + labels: + {{- include "modernization-api.labels" . | nindent 4 }} + app.kubernetes.io/component: ingress +spec: + buffering: + maxRequestBodyBytes: {{ int64 (.Values.traefikIngress.bodySizeLimit.maxRequestBodyBytes | default 104857600) }} + memRequestBodyBytes: 10485760 + maxResponseBodyBytes: 0 + memResponseBodyBytes: 1048576 +--- +# ============================================================================= +# Cached Asset Headers (adds Cache-Control for static assets) +# Replaces: NGINX configuration-snippet on main-ingress-resource-cached +# ============================================================================= +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: nbs-cached-headers + labels: + {{- include "modernization-api.labels" . | nindent 4 }} + app.kubernetes.io/component: ingress +spec: + headers: + customResponseHeaders: + X-Frame-Options: "Allow" + Cross-Origin-Opener-Policy: "same-origin" + Cache-Control: "max-age=1209600, immutable" +{{- end }} \ No newline at end of file diff --git a/charts/modernization-api/values.yaml b/charts/modernization-api/values.yaml index 3618d89e9..c6bf73710 100644 --- a/charts/modernization-api/values.yaml +++ b/charts/modernization-api/values.yaml @@ -41,7 +41,7 @@ pageBuilder: enabled: "false" ingress: - enabled: true + enabled: false className: "nginx" tls: - secretName: app.EXAMPLE_DOMAIN @@ -56,6 +56,13 @@ istioGatewayIngress: certificateName: "" certificateIssuerName: "letsencrypt-production" +traefikIngress: + enabled: true + bodySizeLimit: + # Max request body size in bytes (100MB — matches NGINX proxy-body-size: 100m) + maxRequestBodyBytes: 104857600 + + mTLS: enabled: true diff --git a/charts/traefik/values-azure.yaml b/charts/traefik/values-azure.yaml index 2a7d650f4..30e2014f7 100644 --- a/charts/traefik/values-azure.yaml +++ b/charts/traefik/values-azure.yaml @@ -2,12 +2,6 @@ # Replaces: charts/nginx-ingress/values-azure.yaml # Chart: traefik/traefik (v3.6.x) -image: - registry: docker.io - repository: traefik - tag: "v3.6.2" - pullPolicy: IfNotPresent - deployment: enabled: true kind: Deployment diff --git a/charts/traefik/values.yaml b/charts/traefik/values.yaml index 9f56dd698..25019e921 100644 --- a/charts/traefik/values.yaml +++ b/charts/traefik/values.yaml @@ -2,12 +2,6 @@ # Replaces: charts/nginx-ingress/values.yaml # Chart: traefik/traefik (v3.6.x) -image: - registry: docker.io - repository: traefik - tag: "v3.6.2" - pullPolicy: IfNotPresent - deployment: enabled: true kind: Deployment diff --git a/k8-manifests/traefik-ingressroute-cached.yaml b/k8-manifests/traefik-ingressroute-cached.yaml deleted file mode 100644 index 2563f2968..000000000 --- a/k8-manifests/traefik-ingressroute-cached.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# This is the Traefik equivalent of the Helm-managed main-ingress-resource-cached. -# Uses IngressRoute CRD because the regex path pattern cannot be expressed -# with standard Kubernetes Ingress pathType (Prefix/Exact). - -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: traefik-cached-ingress - namespace: default -spec: - entryPoints: - - websecure - routes: - - match: "Host(`app.EXAMPLE_DOMAIN`) && PathRegexp(`^/(?!auth|ecr-viewer|orchestration).+\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$`)" - kind: Rule - services: - - name: nbs-gateway-svc - port: 8000 - middlewares: - - name: nbs-cached-headers - namespace: default - tls: - secretName: app.EXAMPLE_DOMAIN \ No newline at end of file diff --git a/k8-manifests/traefik-middleware-body-limit.yaml b/k8-manifests/traefik-middleware-body-limit.yaml deleted file mode 100644 index 70cd3ab50..000000000 --- a/k8-manifests/traefik-middleware-body-limit.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: body-size-limit - namespace: default -spec: - buffering: - maxRequestBodyBytes: 104857600 - memRequestBodyBytes: 10485760 - maxResponseBodyBytes: 0 - memResponseBodyBytes: 1048576 \ No newline at end of file diff --git a/k8-manifests/traefik-middleware-cached-headers.yaml b/k8-manifests/traefik-middleware-cached-headers.yaml deleted file mode 100644 index bdfeced95..000000000 --- a/k8-manifests/traefik-middleware-cached-headers.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: nbs-cached-headers - namespace: default -spec: - headers: - customResponseHeaders: - X-Frame-Options: "Allow" - Cross-Origin-Opener-Policy: "same-origin" - Cache-Control: "max-age=1209600, immutable" \ No newline at end of file diff --git a/k8-manifests/traefik-middleware-headers.yaml b/k8-manifests/traefik-middleware-headers.yaml deleted file mode 100644 index a2f671f3a..000000000 --- a/k8-manifests/traefik-middleware-headers.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: nbs-custom-headers - namespace: default -spec: - headers: - customResponseHeaders: - X-Frame-Options: "Allow" - Cross-Origin-Opener-Policy: "same-origin" \ No newline at end of file From 5d7f9894cf3124b5833773381c8f9634887b9ba0 Mon Sep 17 00:00:00 2001 From: EmmanuelNwa247 Date: Tue, 10 Mar 2026 10:19:56 -0400 Subject: [PATCH 3/6] set static IP for AWS --- charts/traefik/values.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/charts/traefik/values.yaml b/charts/traefik/values.yaml index 25019e921..d1b77a944 100644 --- a/charts/traefik/values.yaml +++ b/charts/traefik/values.yaml @@ -78,6 +78,12 @@ service: prometheus.io/scrape: "true" prometheus.io/port: "9100" prometheus.io/path: /metrics + # Optional: Assign Elastic IPs to the NLB for static IP addresses + # Allocate EIPs in AWS first, then reference their allocation IDs: + # service.beta.kubernetes.io/aws-load-balancer-eip-allocations: eipalloc-xxxxxxxxx,eipalloc-yyyyyyyyy + # + # Optional: Restrict inbound traffic to specific CIDRs + # service.beta.kubernetes.io/aws-load-balancer-source-ranges: "XX.XX.XX.XX/24" additionalArguments: - "--serversTransport.forwardingTimeouts.dialTimeout=300s" From 1c87cc0f8d24853ba9383d75bc91b2129959346e Mon Sep 17 00:00:00 2001 From: EmmanuelNwa247 Date: Tue, 10 Mar 2026 15:55:45 -0400 Subject: [PATCH 4/6] Add nbs-ingress chart and Traefik controller values --- .../templates/traefik-ingress.yaml | 143 ----------- charts/dataingestion-service/values.yaml | 2 +- .../traefik-ingressroute-cached.yaml | 29 --- charts/modernization-api/values.yaml | 2 +- charts/nbs-ingress/Chart.yaml | 6 + charts/nbs-ingress/README.md | 47 ++++ charts/nbs-ingress/templates/_helpers.tpl | 45 ++++ .../nbs-ingress/templates/nginx-ingress.yaml | 241 ++++++++++++++++++ .../nbs-ingress/templates/nifi-ingress.yaml | 95 +++++++ .../traefik-ingress-dataingestion.yaml | 142 +++++++++++ .../templates/traefik-ingress-main.yaml} | 42 ++- .../traefik-ingressroute-cached.yaml | 27 ++ .../templates/traefik-middlewares.yaml | 29 +-- charts/nbs-ingress/values.yaml | 131 ++++++++++ 14 files changed, 765 insertions(+), 216 deletions(-) delete mode 100644 charts/dataingestion-service/templates/traefik-ingress.yaml delete mode 100644 charts/modernization-api/templates/traefik-ingressroute-cached.yaml create mode 100644 charts/nbs-ingress/Chart.yaml create mode 100644 charts/nbs-ingress/README.md create mode 100644 charts/nbs-ingress/templates/_helpers.tpl create mode 100644 charts/nbs-ingress/templates/nginx-ingress.yaml create mode 100644 charts/nbs-ingress/templates/nifi-ingress.yaml create mode 100644 charts/nbs-ingress/templates/traefik-ingress-dataingestion.yaml rename charts/{modernization-api/templates/traefik-ingress.yaml => nbs-ingress/templates/traefik-ingress-main.yaml} (53%) create mode 100644 charts/nbs-ingress/templates/traefik-ingressroute-cached.yaml rename charts/{modernization-api => nbs-ingress}/templates/traefik-middlewares.yaml (54%) create mode 100644 charts/nbs-ingress/values.yaml diff --git a/charts/dataingestion-service/templates/traefik-ingress.yaml b/charts/dataingestion-service/templates/traefik-ingress.yaml deleted file mode 100644 index 1738e6cf1..000000000 --- a/charts/dataingestion-service/templates/traefik-ingress.yaml +++ /dev/null @@ -1,143 +0,0 @@ -{{/* -Traefik Ingress - Data Ingestion and Reporting Service routes -Replaces: k8s-manifests/traefik-ingress-dataingestion.yaml -Only rendered when traefikIngress.enabled is true. -Includes body-size-limit middleware. -*/}} -{{- if .Values.traefikIngress.enabled }} -{{- $fullName := include "dataingestion-service.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ $fullName }}-traefik-ingress - labels: - {{- include "dataingestion-service.labels" . | nindent 4 }} - annotations: - cert-manager.io/cluster-issuer: "letsencrypt-production" - traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-body-size-limit@kubernetescrd -spec: - ingressClassName: traefik - tls: - - secretName: {{ .Values.ingressHost }} - hosts: - - {{ .Values.ingressHost }} - rules: - - host: {{ .Values.ingressHost }} - http: - paths: - - path: "/ingestion/" - pathType: Prefix - backend: - service: - name: {{ $fullName }} - port: - number: {{ $svcPort }} - {{- if eq .Values.reportingService.enabled "true" }} - - path: "/reporting/person-svc/" - pathType: Prefix - backend: - service: - name: person-reporting-service - port: - number: {{ .Values.reportingService.personReportingServicePort }} - - path: "/reporting/organization-svc/" - pathType: Prefix - backend: - service: - name: organization-reporting-service - port: - number: {{ .Values.reportingService.organizationReportingServicePort }} - - path: "/reporting/investigation-svc/" - pathType: Prefix - backend: - service: - name: investigation-reporting-service - port: - number: {{ .Values.reportingService.investigationReportingServicePort }} - - path: "/reporting/observation-svc/" - pathType: Prefix - backend: - service: - name: observation-reporting-service - port: - number: {{ .Values.reportingService.observationReportingServicePort }} - - path: "/reporting/post-processing-svc/" - pathType: Prefix - backend: - service: - name: post-processing-reporting-service - port: - number: {{ .Values.reportingService.postProcessingReportingServicePort }} - - path: "/reporting/ldfdata-svc/" - pathType: Prefix - backend: - service: - name: ldfdata-reporting-service - port: - number: {{ .Values.reportingService.ldfdataReportingServicePort }} - {{- end }} - {{- if eq .Values.dataprocessingService.enabled "true" }} - - path: "/rti/" - pathType: Prefix - backend: - service: - name: data-processing-service - port: - number: {{ .Values.dataprocessingService.port }} - {{- end }} - {{- if eq .Values.nndService.enabled "true" }} - - path: "/extraction/" - pathType: Prefix - backend: - service: - name: nnd-service - port: - number: {{ .Values.nndService.port }} - {{- end }} - {{- if eq .Values.srtedataService.enabled "true" }} - - path: "/data/" - pathType: Prefix - backend: - service: - name: srte-data-service - port: - number: {{ .Values.srtedataService.port }} - {{- end }} - {{- if eq .Values.dataExtraction.enabled "true" }} - - path: "/data-extraction/" - pathType: Prefix - backend: - service: - name: data-extraction-service - port: - number: {{ .Values.dataExtraction.port }} - {{- end }} - {{- if eq .Values.caseNotification.enabled "true" }} - - path: "/case-notification/" - pathType: Prefix - backend: - service: - name: case-notification-service - port: - number: {{ .Values.caseNotification.port }} - {{- end }} - {{- if eq .Values.xmlHl7Parser.enabled "true" }} - - path: "/hl7-parser/" - pathType: Prefix - backend: - service: - name: xml-hl7-parser-service - port: - number: {{ .Values.xmlHl7Parser.port }} - {{- end }} - {{- if eq .Values.compare.enabled "true" }} - - path: "/comparison/" - pathType: Prefix - backend: - service: - name: data-compare-api-service - port: - number: {{ .Values.compare.port }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/charts/dataingestion-service/values.yaml b/charts/dataingestion-service/values.yaml index 2d0154f3e..4d29b04c6 100644 --- a/charts/dataingestion-service/values.yaml +++ b/charts/dataingestion-service/values.yaml @@ -77,7 +77,7 @@ ingress: - "data.EXAMPLE_DOMAIN" traefikIngress: - enabled: true + enabled: false resources: {} diff --git a/charts/modernization-api/templates/traefik-ingressroute-cached.yaml b/charts/modernization-api/templates/traefik-ingressroute-cached.yaml deleted file mode 100644 index c2757d601..000000000 --- a/charts/modernization-api/templates/traefik-ingressroute-cached.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{/* -Traefik IngressRoute - Cached static assets with regex path matching -Replaces: k8s-manifests/traefik-ingressroute-cached.yaml -Uses IngressRoute CRD because regex path patterns cannot be expressed -with standard Kubernetes Ingress pathType (Prefix/Exact). -Only rendered when traefikIngress.enabled is true. -*/}} -{{- if .Values.traefikIngress.enabled }} -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: {{ include "modernization-api.fullname" . }}-traefik-cached - labels: - {{- include "modernization-api.labels" . | nindent 4 }} -spec: - entryPoints: - - websecure - routes: - - match: "Host(`{{ .Values.ingressHost }}`) && PathRegexp(`^/(?!auth|ecr-viewer|orchestration).+\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$`)" - kind: Rule - services: - - name: nbs-gateway-svc - port: 8000 - middlewares: - - name: nbs-cached-headers - namespace: {{ .Release.Namespace }} - tls: - secretName: {{ .Values.ingressHost }} -{{- end }} \ No newline at end of file diff --git a/charts/modernization-api/values.yaml b/charts/modernization-api/values.yaml index c6bf73710..d982cb41e 100644 --- a/charts/modernization-api/values.yaml +++ b/charts/modernization-api/values.yaml @@ -57,7 +57,7 @@ istioGatewayIngress: certificateIssuerName: "letsencrypt-production" traefikIngress: - enabled: true + enabled: false bodySizeLimit: # Max request body size in bytes (100MB — matches NGINX proxy-body-size: 100m) maxRequestBodyBytes: 104857600 diff --git a/charts/nbs-ingress/Chart.yaml b/charts/nbs-ingress/Chart.yaml new file mode 100644 index 000000000..887dda2be --- /dev/null +++ b/charts/nbs-ingress/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: nbs-ingress +description: NBS7 Ingress routing resources — decoupled from application charts +type: application +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/charts/nbs-ingress/README.md b/charts/nbs-ingress/README.md new file mode 100644 index 000000000..523355243 --- /dev/null +++ b/charts/nbs-ingress/README.md @@ -0,0 +1,47 @@ +# NBS7 Ingress Chart + +Standalone Helm chart that manages all NBS7 ingress routing, decoupled from application charts. + +## Why a Separate Chart? + +The ingress resources were previously embedded in `modernization-api` and `dataingestion-service` Helm charts. This created a coupling problem: upgrading the ingress controller (e.g., NGINX → Traefik) required upgrading the application charts, which could pull in unwanted application changes for STLTs on older NBS7 versions. + +This chart allows: +- Deploying Traefik ingress independently of NBS7 application version +- STLTs to choose their ingress provider (NGINX or Traefik) without changing application charts +- Centralized management of all routing rules in one place + +## Usage + +### Deploy with Traefik (default) + +```bash +helm install nbs-ingress ./charts/nbs-ingress \ + --set appHost=app.example.com \ + --set dataHost=data.example.com +``` + +### Deploy with NGINX + +```bash +helm install nbs-ingress ./charts/nbs-ingress \ + --set traefik.enabled=false \ + --set nginx.enabled=true \ + --set appHost=app.example.com \ + --set dataHost=data.example.com +``` + +### Switch from NGINX to Traefik + +```bash +helm upgrade nbs-ingress ./charts/nbs-ingress \ + --set traefik.enabled=true \ + --set nginx.enabled=false +``` + +## Important Notes + +- **Disable ingress in application charts** when using this chart. Set `ingress.enabled: false` in both `modernization-api` and `dataingestion-service` values. +- **Deploy this chart after application charts** so the backend services exist. +- **Only enable one provider** at a time (`nginx` or `traefik`). +- The Traefik controller itself is deployed separately via `charts/traefik/values.yaml`. \ No newline at end of file diff --git a/charts/nbs-ingress/templates/_helpers.tpl b/charts/nbs-ingress/templates/_helpers.tpl new file mode 100644 index 000000000..bbc95195a --- /dev/null +++ b/charts/nbs-ingress/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "nbs-ingress.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "nbs-ingress.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "nbs-ingress.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "nbs-ingress.labels" -}} +app: NBS +type: Ingress +helm.sh/chart: {{ include "nbs-ingress.chart" . }} +app.kubernetes.io/name: {{ include "nbs-ingress.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: ingress +{{- end }} diff --git a/charts/nbs-ingress/templates/nginx-ingress.yaml b/charts/nbs-ingress/templates/nginx-ingress.yaml new file mode 100644 index 000000000..a9c54f770 --- /dev/null +++ b/charts/nbs-ingress/templates/nginx-ingress.yaml @@ -0,0 +1,241 @@ +{{/* +NGINX Ingress - Main application routes +Only rendered when nginx.enabled is true. +Preserves the existing NGINX routing for STLTs that haven't migrated to Traefik. +*/}} +{{- if .Values.nginx.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs-ingress.fullname" . }}-main + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Frame-Options: Allow"; + more_set_headers "Cross-Origin-Opener-Policy: same-origin"; + nginx.ingress.kubernetes.io/service-upstream: "true" + nginx.ingress.kubernetes.io/use-regex: "true" +spec: + ingressClassName: nginx + tls: + - secretName: {{ .Values.appHost }} + hosts: + - {{ .Values.appHost }} + rules: + - host: {{ .Values.appHost }} + http: + paths: + - path: "/auth/realms/nbs-users/" + pathType: Prefix + backend: + service: + name: {{ .Values.app.keycloak.serviceName }} + port: + name: {{ .Values.app.keycloak.portName }} + - path: "/auth/robots.txt" + pathType: Exact + backend: + service: + name: {{ .Values.app.keycloak.serviceName }} + port: + name: {{ .Values.app.keycloak.portName }} + - path: "/auth/js/" + pathType: Prefix + backend: + service: + name: {{ .Values.app.keycloak.serviceName }} + port: + name: {{ .Values.app.keycloak.portName }} + - path: "/auth/resources/" + pathType: Prefix + backend: + service: + name: {{ .Values.app.keycloak.serviceName }} + port: + name: {{ .Values.app.keycloak.portName }} + - path: /favicon.ico + pathType: Prefix + backend: + service: + name: {{ .Values.app.gateway.serviceName }} + port: + number: {{ .Values.app.gateway.port }} + - path: "/" + pathType: Prefix + backend: + service: + name: {{ .Values.app.gateway.serviceName }} + port: + number: {{ .Values.app.gateway.port }} +--- +# NGINX Ingress - Cached static assets +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs-ingress.fullname" . }}-cached + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Frame-Options: Allow"; + more_set_headers "Cross-Origin-Opener-Policy: same-origin"; + more_set_headers "Cache-Control: max-age=1209600, immutable"; + nginx.ingress.kubernetes.io/service-upstream: "true" + nginx.ingress.kubernetes.io/use-regex: "true" +spec: + ingressClassName: nginx + tls: + - secretName: {{ .Values.appHost }} + hosts: + - {{ .Values.appHost }} + rules: + - host: {{ .Values.appHost }} + http: + paths: + - path: "/(.+)\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$" + pathType: ImplementationSpecific + backend: + service: + name: {{ .Values.app.gateway.serviceName }} + port: + number: {{ .Values.app.gateway.port }} +--- +# NGINX Ingress - Data Ingestion +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs-ingress.fullname" . }}-dataingestion + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} +spec: + ingressClassName: nginx + tls: + - secretName: {{ .Values.dataHost }} + hosts: + - {{ .Values.dataHost }} + rules: + - host: {{ .Values.dataHost }} + http: + paths: + {{- if .Values.data.ingestion.enabled }} + - path: "/ingestion/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.ingestion.serviceName }} + port: + number: {{ .Values.data.ingestion.port }} + {{- end }} + {{- if .Values.data.dataProcessing.enabled }} + - path: "/rti/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.dataProcessing.serviceName }} + port: + number: {{ .Values.data.dataProcessing.port }} + {{- end }} + {{- if .Values.data.nnd.enabled }} + - path: "/extraction/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.nnd.serviceName }} + port: + number: {{ .Values.data.nnd.port }} + {{- end }} + {{- if .Values.data.srteData.enabled }} + - path: "/data/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.srteData.serviceName }} + port: + number: {{ .Values.data.srteData.port }} + {{- end }} + {{- if .Values.data.dataExtraction.enabled }} + - path: "/data-extraction/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.dataExtraction.serviceName }} + port: + number: {{ .Values.data.dataExtraction.port }} + {{- end }} + {{- if .Values.data.caseNotification.enabled }} + - path: "/case-notification/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.caseNotification.serviceName }} + port: + number: {{ .Values.data.caseNotification.port }} + {{- end }} + {{- if .Values.data.xmlHl7Parser.enabled }} + - path: "/hl7-parser/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.xmlHl7Parser.serviceName }} + port: + number: {{ .Values.data.xmlHl7Parser.port }} + {{- end }} + {{- if .Values.data.reporting.enabled }} + - path: "/reporting/person-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.person.serviceName }} + port: + number: {{ .Values.data.reporting.person.port }} + - path: "/reporting/organization-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.organization.serviceName }} + port: + number: {{ .Values.data.reporting.organization.port }} + - path: "/reporting/investigation-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.investigation.serviceName }} + port: + number: {{ .Values.data.reporting.investigation.port }} + - path: "/reporting/observation-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.observation.serviceName }} + port: + number: {{ .Values.data.reporting.observation.port }} + - path: "/reporting/post-processing-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.postProcessing.serviceName }} + port: + number: {{ .Values.data.reporting.postProcessing.port }} + - path: "/reporting/ldfdata-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.ldfdata.serviceName }} + port: + number: {{ .Values.data.reporting.ldfdata.port }} + {{- end }} + {{- if .Values.data.compare.enabled }} + - path: "/comparison/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.compare.serviceName }} + port: + number: {{ .Values.data.compare.port }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/nbs-ingress/templates/nifi-ingress.yaml b/charts/nbs-ingress/templates/nifi-ingress.yaml new file mode 100644 index 000000000..be52c9100 --- /dev/null +++ b/charts/nbs-ingress/templates/nifi-ingress.yaml @@ -0,0 +1,95 @@ +{{/* +NiFi Ingress — only rendered when nifi.enabled is true. +NiFi serves HTTPS on port 8443 internally, requiring special backend handling. + +NGINX: Uses backend-protocol, upstream-vhost, and proxy-redirect annotations. +Traefik: Uses ServersTransport CRD for HTTPS backend + headers middleware for upstream-vhost. +*/}} + +{{- if .Values.nifi.enabled }} + +{{/* ========== TRAEFIK PATH ========== */}} +{{- if .Values.traefik.enabled }} +# ServersTransport — HTTPS backend connection to NiFi +apiVersion: traefik.io/v1alpha1 +kind: ServersTransport +metadata: + name: {{ include "nbs-ingress.fullname" . }}-nifi-transport + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} +spec: + insecureSkipVerify: true +--- +# Middleware — Set Host header to localhost:8443 (NiFi validates Host) +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: {{ include "nbs-ingress.fullname" . }}-nifi-headers + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} +spec: + headers: + customRequestHeaders: + Host: "localhost:8443" +--- +# IngressRoute — NiFi routing with HTTPS backend via ServersTransport +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: {{ include "nbs-ingress.fullname" . }}-nifi + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} +spec: + entryPoints: + - websecure + routes: + - match: "Host(`{{ .Values.nifi.host }}`)" + kind: Rule + services: + - name: {{ .Values.nifi.serviceName }} + port: {{ .Values.nifi.port }} + serversTransport: {{ include "nbs-ingress.fullname" . }}-nifi-transport + scheme: https + middlewares: + - name: {{ include "nbs-ingress.fullname" . }}-nifi-headers + namespace: {{ .Release.Namespace }} + tls: + secretName: {{ .Values.nifi.host }} +{{- end }} + +{{/* ========== NGINX PATH ========== */}} +{{- if .Values.nginx.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs-ingress.fullname" . }}-nifi + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + nginx.ingress.kubernetes.io/upstream-vhost: "localhost:8443" + nginx.ingress.kubernetes.io/proxy-redirect-from: "https://localhost:8443" + nginx.ingress.kubernetes.io/proxy-redirect-to: "https://{{ .Values.nifi.host }}" +spec: + ingressClassName: nginx + tls: + - secretName: {{ .Values.nifi.host }} + hosts: + - {{ .Values.nifi.host }} + rules: + - host: {{ .Values.nifi.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ .Values.nifi.serviceName }} + port: + number: {{ .Values.nifi.port }} +{{- end }} + +{{- end }} \ No newline at end of file diff --git a/charts/nbs-ingress/templates/traefik-ingress-dataingestion.yaml b/charts/nbs-ingress/templates/traefik-ingress-dataingestion.yaml new file mode 100644 index 000000000..c1d2dfd41 --- /dev/null +++ b/charts/nbs-ingress/templates/traefik-ingress-dataingestion.yaml @@ -0,0 +1,142 @@ +{{/* +Traefik Ingress - Data Ingestion and Reporting Service routes +Only rendered when traefik.enabled is true. +Includes body-size-limit middleware for large ECR uploads. +*/}} +{{- if .Values.traefik.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs-ingress.fullname" . }}-dataingestion + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} + traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-body-size-limit@kubernetescrd +spec: + ingressClassName: traefik + tls: + - secretName: {{ .Values.dataHost }} + hosts: + - {{ .Values.dataHost }} + rules: + - host: {{ .Values.dataHost }} + http: + paths: + {{- if .Values.data.ingestion.enabled }} + - path: "/ingestion/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.ingestion.serviceName }} + port: + number: {{ .Values.data.ingestion.port }} + {{- end }} + {{- if .Values.data.reporting.enabled }} + - path: "/reporting/person-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.person.serviceName }} + port: + number: {{ .Values.data.reporting.person.port }} + - path: "/reporting/organization-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.organization.serviceName }} + port: + number: {{ .Values.data.reporting.organization.port }} + - path: "/reporting/investigation-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.investigation.serviceName }} + port: + number: {{ .Values.data.reporting.investigation.port }} + - path: "/reporting/observation-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.observation.serviceName }} + port: + number: {{ .Values.data.reporting.observation.port }} + - path: "/reporting/post-processing-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.postProcessing.serviceName }} + port: + number: {{ .Values.data.reporting.postProcessing.port }} + - path: "/reporting/ldfdata-svc/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.reporting.ldfdata.serviceName }} + port: + number: {{ .Values.data.reporting.ldfdata.port }} + {{- end }} + {{- if .Values.data.dataProcessing.enabled }} + - path: "/rti/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.dataProcessing.serviceName }} + port: + number: {{ .Values.data.dataProcessing.port }} + {{- end }} + {{- if .Values.data.nnd.enabled }} + - path: "/extraction/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.nnd.serviceName }} + port: + number: {{ .Values.data.nnd.port }} + {{- end }} + {{- if .Values.data.srteData.enabled }} + - path: "/data/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.srteData.serviceName }} + port: + number: {{ .Values.data.srteData.port }} + {{- end }} + {{- if .Values.data.dataExtraction.enabled }} + - path: "/data-extraction/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.dataExtraction.serviceName }} + port: + number: {{ .Values.data.dataExtraction.port }} + {{- end }} + {{- if .Values.data.caseNotification.enabled }} + - path: "/case-notification/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.caseNotification.serviceName }} + port: + number: {{ .Values.data.caseNotification.port }} + {{- end }} + {{- if .Values.data.xmlHl7Parser.enabled }} + - path: "/hl7-parser/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.xmlHl7Parser.serviceName }} + port: + number: {{ .Values.data.xmlHl7Parser.port }} + {{- end }} + {{- if .Values.data.compare.enabled }} + - path: "/comparison/" + pathType: Prefix + backend: + service: + name: {{ .Values.data.compare.serviceName }} + port: + number: {{ .Values.data.compare.port }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/modernization-api/templates/traefik-ingress.yaml b/charts/nbs-ingress/templates/traefik-ingress-main.yaml similarity index 53% rename from charts/modernization-api/templates/traefik-ingress.yaml rename to charts/nbs-ingress/templates/traefik-ingress-main.yaml index ed02055eb..56edbb0dc 100644 --- a/charts/modernization-api/templates/traefik-ingress.yaml +++ b/charts/nbs-ingress/templates/traefik-ingress-main.yaml @@ -1,27 +1,25 @@ {{/* Traefik Ingress - Main application routes (KeyCloak + NBS Gateway) -Replaces: k8s-manifests/traefik-ingress-main.yaml -Only rendered when traefikIngress.enabled is true. -Only one ingress type should be enabled: nginx (ingress), istio (istioGatewayIngress), or traefik (traefikIngress). +Only rendered when traefik.enabled is true. */}} -{{- if .Values.traefikIngress.enabled }} +{{- if .Values.traefik.enabled }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: {{ include "modernization-api.fullname" . }}-traefik-ingress + name: {{ include "nbs-ingress.fullname" . }}-main labels: - {{- include "modernization-api.labels" . | nindent 4 }} + {{- include "nbs-ingress.labels" . | nindent 4 }} annotations: - cert-manager.io/cluster-issuer: "letsencrypt-production" + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-nbs-custom-headers@kubernetescrd,{{ .Release.Namespace }}-body-size-limit@kubernetescrd spec: ingressClassName: traefik tls: - - secretName: {{ .Values.ingressHost }} + - secretName: {{ .Values.appHost }} hosts: - - {{ .Values.ingressHost }} + - {{ .Values.appHost }} rules: - - host: {{ .Values.ingressHost }} + - host: {{ .Values.appHost }} http: paths: # KeyCloak auth routes @@ -29,43 +27,43 @@ spec: pathType: Prefix backend: service: - name: keycloak + name: {{ .Values.app.keycloak.serviceName }} port: - name: http + name: {{ .Values.app.keycloak.portName }} - path: "/auth/robots.txt" pathType: Exact backend: service: - name: keycloak + name: {{ .Values.app.keycloak.serviceName }} port: - name: http + name: {{ .Values.app.keycloak.portName }} - path: "/auth/js/" pathType: Prefix backend: service: - name: keycloak + name: {{ .Values.app.keycloak.serviceName }} port: - name: http + name: {{ .Values.app.keycloak.portName }} - path: "/auth/resources/" pathType: Prefix backend: service: - name: keycloak + name: {{ .Values.app.keycloak.serviceName }} port: - name: http + name: {{ .Values.app.keycloak.portName }} # NBS Gateway routes - path: /favicon.ico pathType: Prefix backend: service: - name: nbs-gateway-svc + name: {{ .Values.app.gateway.serviceName }} port: - number: 8000 + number: {{ .Values.app.gateway.port }} - path: "/" pathType: Prefix backend: service: - name: nbs-gateway-svc + name: {{ .Values.app.gateway.serviceName }} port: - number: 8000 + number: {{ .Values.app.gateway.port }} {{- end }} \ No newline at end of file diff --git a/charts/nbs-ingress/templates/traefik-ingressroute-cached.yaml b/charts/nbs-ingress/templates/traefik-ingressroute-cached.yaml new file mode 100644 index 000000000..97e2a8cf3 --- /dev/null +++ b/charts/nbs-ingress/templates/traefik-ingressroute-cached.yaml @@ -0,0 +1,27 @@ +{{/* +Traefik IngressRoute - Cached static assets with regex path matching +Uses IngressRoute CRD because regex paths cannot be expressed with standard Ingress pathType. +Only rendered when traefik.enabled is true. +*/}} +{{- if .Values.traefik.enabled }} +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: {{ include "nbs-ingress.fullname" . }}-cached + labels: + {{- include "nbs-ingress.labels" . | nindent 4 }} +spec: + entryPoints: + - websecure + routes: + - match: "Host(`{{ .Values.appHost }}`) && PathRegexp(`^/(?!auth|ecr-viewer|orchestration).+\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$`)" + kind: Rule + services: + - name: {{ .Values.app.gateway.serviceName }} + port: {{ .Values.app.gateway.port }} + middlewares: + - name: nbs-cached-headers + namespace: {{ .Release.Namespace }} + tls: + secretName: {{ .Values.appHost }} +{{- end }} \ No newline at end of file diff --git a/charts/modernization-api/templates/traefik-middlewares.yaml b/charts/nbs-ingress/templates/traefik-middlewares.yaml similarity index 54% rename from charts/modernization-api/templates/traefik-middlewares.yaml rename to charts/nbs-ingress/templates/traefik-middlewares.yaml index f55a2a50d..21f690948 100644 --- a/charts/modernization-api/templates/traefik-middlewares.yaml +++ b/charts/nbs-ingress/templates/traefik-middlewares.yaml @@ -1,25 +1,17 @@ {{/* Traefik Middleware CRDs - Response headers, body size limits, cached headers -Replaces: - - k8s-manifests/traefik-middleware-headers.yaml - - k8s-manifests/traefik-middleware-body-limit.yaml - - k8s-manifests/traefik-middleware-cached-headers.yaml -Only rendered when traefikIngress.enabled is true. +Only rendered when traefik.enabled is true. */}} -{{- if .Values.traefikIngress.enabled }} +{{- if .Values.traefik.enabled }} # ============================================================================= -# Custom Response Headers (replaces NGINX configuration-snippet) -# Replaces: nginx.ingress.kubernetes.io/configuration-snippet: -# more_set_headers "X-Frame-Options: Allow"; -# more_set_headers "Cross-Origin-Opener-Policy: same-origin"; +# Custom Response Headers # ============================================================================= apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: nbs-custom-headers labels: - {{- include "modernization-api.labels" . | nindent 4 }} - app.kubernetes.io/component: ingress + {{- include "nbs-ingress.labels" . | nindent 4 }} spec: headers: customResponseHeaders: @@ -27,33 +19,30 @@ spec: Cross-Origin-Opener-Policy: "same-origin" --- # ============================================================================= -# Body Size Limit (replaces NGINX proxy-body-size: "100m") +# Body Size Limit (100MB — matches NGINX proxy-body-size: 100m) # ============================================================================= apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: body-size-limit labels: - {{- include "modernization-api.labels" . | nindent 4 }} - app.kubernetes.io/component: ingress + {{- include "nbs-ingress.labels" . | nindent 4 }} spec: buffering: - maxRequestBodyBytes: {{ int64 (.Values.traefikIngress.bodySizeLimit.maxRequestBodyBytes | default 104857600) }} - memRequestBodyBytes: 10485760 + maxRequestBodyBytes: {{ int64 (.Values.middlewares.bodySizeLimit.maxRequestBodyBytes | default 104857600) }} + memRequestBodyBytes: {{ int64 (.Values.middlewares.bodySizeLimit.memRequestBodyBytes | default 10485760) }} maxResponseBodyBytes: 0 memResponseBodyBytes: 1048576 --- # ============================================================================= # Cached Asset Headers (adds Cache-Control for static assets) -# Replaces: NGINX configuration-snippet on main-ingress-resource-cached # ============================================================================= apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: nbs-cached-headers labels: - {{- include "modernization-api.labels" . | nindent 4 }} - app.kubernetes.io/component: ingress + {{- include "nbs-ingress.labels" . | nindent 4 }} spec: headers: customResponseHeaders: diff --git a/charts/nbs-ingress/values.yaml b/charts/nbs-ingress/values.yaml new file mode 100644 index 000000000..5677f3db1 --- /dev/null +++ b/charts/nbs-ingress/values.yaml @@ -0,0 +1,131 @@ +# ============================================================================= +# NBS7 Ingress Chart - values.yaml +# ============================================================================= +# This chart manages all ingress routing for NBS7, decoupled from +# application charts (modernization-api, dataingestion-service). +# +# Only one ingress provider should be enabled at a time. +# ============================================================================= + +# ----------------------------------------------------------------------------- +# INGRESS PROVIDER SELECTION +# ----------------------------------------------------------------------------- +# Enable exactly one provider: +nginx: + enabled: false + +traefik: + enabled: true + +# ----------------------------------------------------------------------------- +# HOSTNAMES +# ----------------------------------------------------------------------------- +# Replace these with your environment-specific hostnames +appHost: "app.EXAMPLE_DOMAIN" +dataHost: "data.EXAMPLE_DOMAIN" + +# ----------------------------------------------------------------------------- +# TLS +# ----------------------------------------------------------------------------- +tls: + clusterIssuer: "letsencrypt-production" + +# ----------------------------------------------------------------------------- +# TRAEFIK MIDDLEWARE CONFIGURATION +# ----------------------------------------------------------------------------- +middlewares: + # Body size limit (matches NGINX proxy-body-size: 100m) + bodySizeLimit: + maxRequestBodyBytes: 104857600 + memRequestBodyBytes: 10485760 + +# ----------------------------------------------------------------------------- +# NIFI +# ----------------------------------------------------------------------------- +# NiFi is optional — most deployments don't expose it externally. +# Enable only if you need external access to the NiFi UI. +# NiFi serves HTTPS on port 8443 internally. +nifi: + enabled: false + host: "nifi.EXAMPLE_DOMAIN" + serviceName: "nifi-efs" + port: 8443 + +# ----------------------------------------------------------------------------- +# BACKEND SERVICES +# ----------------------------------------------------------------------------- +# These match the service names and ports deployed by the application charts. +# Only change these if your application charts use non-default names/ports. + +app: + # NBS Gateway + gateway: + serviceName: "nbs-gateway-svc" + port: 8000 + # KeyCloak + keycloak: + serviceName: "keycloak" + portName: "http" + +data: + # Data Ingestion Service + ingestion: + enabled: true + serviceName: "dataingestion-service" + port: 8081 + # Reporting Services + reporting: + enabled: false + person: + serviceName: "person-reporting-service" + port: 8091 + organization: + serviceName: "organization-reporting-service" + port: 8092 + investigation: + serviceName: "investigation-reporting-service" + port: 8093 + observation: + serviceName: "observation-reporting-service" + port: 8094 + postProcessing: + serviceName: "post-processing-reporting-service" + port: 8095 + ldfdata: + serviceName: "ldfdata-reporting-service" + port: 8096 + # Data Processing + dataProcessing: + enabled: true + serviceName: "data-processing-service" + port: 8082 + # NND Service + nnd: + enabled: false + serviceName: "nnd-service" + port: 8083 + # SRTE Data Service + srteData: + enabled: true + serviceName: "srte-data-service" + port: 8084 + # Data Extraction + dataExtraction: + enabled: true + serviceName: "data-extraction-service" + port: 8090 + # Case Notification + caseNotification: + enabled: false + serviceName: "case-notification-service" + port: 8089 + # XML HL7 Parser + xmlHl7Parser: + enabled: true + serviceName: "xml-hl7-parser-service" + port: 8088 + # Data Compare API + compare: + enabled: false + serviceName: "data-compare-api-service" + port: 8097 \ No newline at end of file From 523a3d63bc9c3072a8653aa575a3d0fe445b687d Mon Sep 17 00:00:00 2001 From: Emmanuel Nwakire <100969358+nuel247@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:43:31 -0400 Subject: [PATCH 5/6] Add nbs6-ingress chart for EXT NBS6 ingress routing --- charts/nbs6-ingress/Chart.yaml | 6 ++ charts/nbs6-ingress/README.md | 34 ++++++++++ charts/nbs6-ingress/templates/_helpers.tpl | 45 +++++++++++++ .../templates/ingress-cached.yaml | 62 +++++++++++++++++ charts/nbs6-ingress/templates/ingress.yaml | 66 +++++++++++++++++++ .../nbs6-ingress/templates/middlewares.yaml | 32 +++++++++ charts/nbs6-ingress/values.yaml | 33 ++++++++++ 7 files changed, 278 insertions(+) create mode 100644 charts/nbs6-ingress/Chart.yaml create mode 100644 charts/nbs6-ingress/README.md create mode 100644 charts/nbs6-ingress/templates/_helpers.tpl create mode 100644 charts/nbs6-ingress/templates/ingress-cached.yaml create mode 100644 charts/nbs6-ingress/templates/ingress.yaml create mode 100644 charts/nbs6-ingress/templates/middlewares.yaml create mode 100644 charts/nbs6-ingress/values.yaml diff --git a/charts/nbs6-ingress/Chart.yaml b/charts/nbs6-ingress/Chart.yaml new file mode 100644 index 000000000..e6155900d --- /dev/null +++ b/charts/nbs6-ingress/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: nbs6-ingress +description: NBS6 (Classic/WildFly) Ingress routing — decoupled from the nbs6 application chart +type: application +version: 1.0.0 +appVersion: "1.0.0" \ No newline at end of file diff --git a/charts/nbs6-ingress/README.md b/charts/nbs6-ingress/README.md new file mode 100644 index 000000000..b0ab8714e --- /dev/null +++ b/charts/nbs6-ingress/README.md @@ -0,0 +1,34 @@ +# NBS6 Ingress Chart + +Standalone Helm chart for NBS6 (Classic/WildFly) ingress routing, decoupled from the `nbs6` application chart. + +## Overview + +This chart is for CDC and Montana environments that run NBS6 in a container alongside NBS7. It manages the ingress routing for the `app-classic` hostname independently of the NBS6 application chart version. + +## Usage + +### Deploy with Traefik (default) + +```bash +helm install nbs6-ingress ./charts/nbs6-ingress \ + --set host=app-classic.example.com \ + --set serviceName=nbs6-service +``` + +### Deploy with NGINX + +```bash +helm install nbs6-ingress ./charts/nbs6-ingress \ + --set traefik.enabled=false \ + --set nginx.enabled=true \ + --set host=app-classic.example.com \ + --set serviceName=nbs6-service +``` + +## Important Notes + +- The `serviceName` must match the NBS6 Helm release service name (`-service`) +- The NBS6 service exposes port 443 (HTTPS) which maps to WildFly on targetPort 7001 +- Disable `ingress.enabled` in the NBS6 application chart when using this chart +- NBS6 has its own middleware CRDs (`nbs6-custom-headers`, `nbs6-cached-headers`) separate from the NBS7 `nbs-ingress` chart middlewares \ No newline at end of file diff --git a/charts/nbs6-ingress/templates/_helpers.tpl b/charts/nbs6-ingress/templates/_helpers.tpl new file mode 100644 index 000000000..1a91799cd --- /dev/null +++ b/charts/nbs6-ingress/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "nbs6-ingress.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "nbs6-ingress.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "nbs6-ingress.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "nbs6-ingress.labels" -}} +app: NBS +type: Ingress +helm.sh/chart: {{ include "nbs6-ingress.chart" . }} +app.kubernetes.io/name: {{ include "nbs6-ingress.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: ingress +{{- end }} diff --git a/charts/nbs6-ingress/templates/ingress-cached.yaml b/charts/nbs6-ingress/templates/ingress-cached.yaml new file mode 100644 index 000000000..bf1761897 --- /dev/null +++ b/charts/nbs6-ingress/templates/ingress-cached.yaml @@ -0,0 +1,62 @@ +{{/* +NBS6 (Classic/WildFly) Ingress — Cached static assets +Regex path excludes /auth and matches common static file extensions. +*/}} + +{{/* ========== TRAEFIK PATH ========== */}} +{{- if .Values.traefik.enabled }} +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: {{ include "nbs6-ingress.fullname" . }}-cached + labels: + {{- include "nbs6-ingress.labels" . | nindent 4 }} +spec: + entryPoints: + - websecure + routes: + - match: "Host(`{{ .Values.host }}`) && PathRegexp(`^/(?!auth).+\\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$`)" + kind: Rule + services: + - name: {{ .Values.serviceName }} + port: {{ .Values.servicePort }} + middlewares: + - name: nbs6-cached-headers + namespace: {{ .Release.Namespace }} + tls: + secretName: {{ .Values.host }} +{{- end }} + +{{/* ========== NGINX PATH ========== */}} +{{- if .Values.nginx.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs6-ingress.fullname" . }}-cached + labels: + {{- include "nbs6-ingress.labels" . | nindent 4 }} + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/service-upstream: "true" + nginx.ingress.kubernetes.io/use-regex: "true" + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Frame-Options: Allow"; + more_set_headers "Cross-Origin-Opener-Policy: same-origin"; + more_set_headers "Cache-Control: max-age=1209600, immutable"; +spec: + tls: + - secretName: {{ .Values.host }} + hosts: + - {{ .Values.host }} + rules: + - host: {{ .Values.host }} + http: + paths: + - path: '/(?!auth).+\.(jpg|svg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|ttf|woff|woff2)$' + pathType: ImplementationSpecific + backend: + service: + name: {{ .Values.serviceName }} + port: + number: {{ .Values.servicePort }} +{{- end }} \ No newline at end of file diff --git a/charts/nbs6-ingress/templates/ingress.yaml b/charts/nbs6-ingress/templates/ingress.yaml new file mode 100644 index 000000000..2b9b60c72 --- /dev/null +++ b/charts/nbs6-ingress/templates/ingress.yaml @@ -0,0 +1,66 @@ +{{/* +NBS6 (Classic/WildFly) Ingress — Main routes +Service: {{ .Release.Name }}-service (port 443 → targetPort 7001) +*/}} + +{{/* ========== TRAEFIK PATH ========== */}} +{{- if .Values.traefik.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs6-ingress.fullname" . }}-main + labels: + {{- include "nbs6-ingress.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.tls.clusterIssuer | quote }} + traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-nbs6-custom-headers@kubernetescrd +spec: + ingressClassName: traefik + tls: + - secretName: {{ .Values.host }} + hosts: + - {{ .Values.host }} + rules: + - host: {{ .Values.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ .Values.serviceName }} + port: + number: {{ .Values.servicePort }} +{{- end }} + +{{/* ========== NGINX PATH ========== */}} +{{- if .Values.nginx.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "nbs6-ingress.fullname" . }}-main + labels: + {{- include "nbs6-ingress.labels" . | nindent 4 }} + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/service-upstream: "true" + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Frame-Options: Allow"; + more_set_headers "Cross-Origin-Opener-Policy: same-origin"; +spec: + tls: + - secretName: {{ .Values.host }} + hosts: + - {{ .Values.host }} + rules: + - host: {{ .Values.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ .Values.serviceName }} + port: + number: {{ .Values.servicePort }} +{{- end }} \ No newline at end of file diff --git a/charts/nbs6-ingress/templates/middlewares.yaml b/charts/nbs6-ingress/templates/middlewares.yaml new file mode 100644 index 000000000..650acdb97 --- /dev/null +++ b/charts/nbs6-ingress/templates/middlewares.yaml @@ -0,0 +1,32 @@ +{{/* +NBS6 Traefik Middleware CRDs +Only rendered when traefik.enabled is true. +*/}} +{{- if .Values.traefik.enabled }} +# Custom Response Headers for NBS6 +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: nbs6-custom-headers + labels: + {{- include "nbs6-ingress.labels" . | nindent 4 }} +spec: + headers: + customResponseHeaders: + X-Frame-Options: "Allow" + Cross-Origin-Opener-Policy: "same-origin" +--- +# Cached Asset Headers for NBS6 +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: nbs6-cached-headers + labels: + {{- include "nbs6-ingress.labels" . | nindent 4 }} +spec: + headers: + customResponseHeaders: + X-Frame-Options: "Allow" + Cross-Origin-Opener-Policy: "same-origin" + Cache-Control: "max-age=1209600, immutable" +{{- end }} \ No newline at end of file diff --git a/charts/nbs6-ingress/values.yaml b/charts/nbs6-ingress/values.yaml new file mode 100644 index 000000000..860e3672d --- /dev/null +++ b/charts/nbs6-ingress/values.yaml @@ -0,0 +1,33 @@ +# ============================================================================= +# NBS6 Ingress Chart - values.yaml +# ============================================================================= +# Manages ingress routing for the NBS6 (Classic/WildFly) application, +# decoupled from the nbs6 application chart. +# +# Only one ingress provider should be enabled at a time. +# ============================================================================= + +# ----------------------------------------------------------------------------- +# INGRESS PROVIDER SELECTION +# ----------------------------------------------------------------------------- +nginx: + enabled: false + +traefik: + enabled: true + +# ----------------------------------------------------------------------------- +# NBS6 SERVICE CONFIGURATION +# ----------------------------------------------------------------------------- +# The nbs6 chart creates a service named -service +# (e.g., if helm release is "nbs6", service is "nbs6-service") +# Port 443 maps to targetPort 7001 (WildFly) +host: "app-classic.EXAMPLE_DOMAIN" +serviceName: "nbs6-service" +servicePort: 443 + +# ----------------------------------------------------------------------------- +# TLS +# ----------------------------------------------------------------------------- +tls: + clusterIssuer: "letsencrypt-production" \ No newline at end of file From 18bffd7dd952df84f8f50acdc1d3506a83f97363 Mon Sep 17 00:00:00 2001 From: Emmanuel Nwakire <100969358+nuel247@users.noreply.github.com> Date: Thu, 12 Mar 2026 12:11:15 -0400 Subject: [PATCH 6/6] Add nodeSelector and port 80 --- charts/nbs6-ingress/values.yaml | 2 +- charts/traefik/values-azure.yaml | 3 +++ charts/traefik/values.yaml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/charts/nbs6-ingress/values.yaml b/charts/nbs6-ingress/values.yaml index 860e3672d..e0de3fa00 100644 --- a/charts/nbs6-ingress/values.yaml +++ b/charts/nbs6-ingress/values.yaml @@ -24,7 +24,7 @@ traefik: # Port 443 maps to targetPort 7001 (WildFly) host: "app-classic.EXAMPLE_DOMAIN" serviceName: "nbs6-service" -servicePort: 443 +servicePort: 80 # ----------------------------------------------------------------------------- # TLS diff --git a/charts/traefik/values-azure.yaml b/charts/traefik/values-azure.yaml index 30e2014f7..5dd24a8af 100644 --- a/charts/traefik/values-azure.yaml +++ b/charts/traefik/values-azure.yaml @@ -2,6 +2,9 @@ # Replaces: charts/nginx-ingress/values-azure.yaml # Chart: traefik/traefik (v3.6.x) +nodeSelector: + kubernetes.io/os: linux + deployment: enabled: true kind: Deployment diff --git a/charts/traefik/values.yaml b/charts/traefik/values.yaml index d1b77a944..e98d25b4b 100644 --- a/charts/traefik/values.yaml +++ b/charts/traefik/values.yaml @@ -2,6 +2,9 @@ # Replaces: charts/nginx-ingress/values.yaml # Chart: traefik/traefik (v3.6.x) +nodeSelector: + kubernetes.io/os: linux + deployment: enabled: true kind: Deployment