From e82d2d136667a878f0d061f0296d50f7b0e99c39 Mon Sep 17 00:00:00 2001 From: EmmanuelNwa247 Date: Fri, 6 Mar 2026 16:43:48 -0500 Subject: [PATCH 1/3] 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/3] 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/3] 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"