Connecting to the Traceable Platform¶
This guide explains the different ways to expose the Traceable Platform so that users, agents, and API clients can reach it. It covers the two routing modes shipped with the platform, the central traceable-router (Envoy) component, and detailed configuration for cloud load balancers, NGINX, Traefik, OpenShift Routes.
Overview¶
All external traffic to the platform — the UI, the GraphQL/REST APIs, the IAM/login flows, the OpenTelemetry trace ingestion (gRPC), and the agent control-plane — enters through a single logical edge. How that edge is exposed depends on your Kubernetes distribution and the ingress technology available in your environment.
The platform supports two routing modes, selected through the router value in the traceable-ingress Helm chart:
| Mode | router value |
Edge component | Best for |
|---|---|---|---|
| Legacy | legacy |
Multiple NGINX Ingress objects routing directly to backend services |
Clusters where ingress-nginx is installed and cluster-scoped permissions are available |
| Envoy | envoy |
A single traceable-router (Envoy) Service that you expose via any controller or load balancer |
Cloud Kubernetes, OpenShift, Traefik, and any cluster where ingress-nginx cannot be installed |
Rule of thumb: If you can install and run
ingress-nginxwith cluster scope, legacy mode works out of the box. In every other case — managed cloud clusters, OpenShift, namespace-scoped installs, or environments standardized on a non-NGINX ingress — use Envoy mode and pick one of the connectivity options below.
Architecture¶
Legacy mode (NGINX Ingress)¶
In legacy mode, the traceable-ingress chart renders a set of NGINX Ingress resources (ingress-http-auth, ingress-grpc-auth, ingress-http-noauth, and so on). Each one routes specific paths directly to the corresponding platform service (ui, graphql, iam/iam-v2, traceable-config-service, hypertrace-collector, scan-manager, etc.).
Authentication is delegated to NGINX's external-auth feature: protected ingresses carry nginx.ingress.kubernetes.io/auth-url and auth-signin annotations that call the jwt-auth service before forwarding the request.
Client ─► Cloud/Edge LB ─► ingress-nginx ─► [ui | graphql | iam | collector | ...]
│
└─ auth-url ─► jwt-auth
Requirements: a working ingress-nginx controller, cluster-scoped RBAC, and the NGINX external-auth annotations support.
Envoy mode (traceable-router)¶
In Envoy mode, all of that path routing, external authorization, login redirects, gRPC-web translation, and header rewriting is performed inside the traceable-router Envoy proxy. The ingress layer no longer needs to understand the platform's routing table — it only has to deliver traffic to one Service.
Client ─► [ Cloud LB | NGINX | Traefik | OpenShift Route ] ─► traceable-router (Envoy) ─► all platform services
This indirection is what makes Envoy mode portable: any controller that can forward HTTP/2 (h2c) or HTTPS to a single backend Service can front the platform. The traceable-ingress chart provides ready-made templates for several controllers, selected with the controller value:
router: envoy
controller: none # one of: ingress-nginx | nginx | traefik-ingress | openshift-route | none
Use controller: none when you expose the traceable-router Service directly (for example, with a cloud LoadBalancer Service) and do not want the chart to render any ingress object.
Applying the values in this guide: The
traceable-routerandtraceable-ingresssnippets below are chart values. At install time you supply them through the installer's per-chart override mechanism —cluster.helmValues.traceable-routerandcluster.helmValues.traceable-ingress. See Overriding Helm Chart Values for how to author and pass the override file.
The traceable-router component¶
The traceable-router chart (chart name: traceable-router) deploys a single Envoy proxy. Understanding its listeners and Service is key to configuring any of the Envoy-mode options.
Listeners and ports¶
| Listener | Container port | Protocol | Toggle | Notes |
|---|---|---|---|---|
| HTTP | 8000 |
HTTP/2 cleartext (h2c) | httpEnabled |
Use when TLS is terminated upstream (at the LB/ingress). |
| HTTPS | 8443 |
HTTPS (TLS terminated in Envoy) | httpsEnabled |
Uses the certificate from tlsSecretName. |
| Admin | 9901 |
HTTP | adminEnabled |
Stats (/stats/prometheus) and health (/ready). |
Service¶
By default the chart creates a ClusterIP Service:
service:
type: ClusterIP
primaryPortDef:
name: http
port: 8000
targetPort: http # -> container port 8000 (h2c)
secondaryPortDef:
name: https
port: 443
targetPort: https # -> container port 8443 (TLS)
To expose the platform you either:
- change
service.typetoLoadBalancer(cloud direct exposure), or - keep it as
ClusterIPand place an ingress controller (NGINX, Traefik, OpenShift Route) in front of it.
TLS strategy primer¶
There are two independent decisions:
- Where TLS is terminated — at the cloud load balancer / ingress, or inside
traceable-router. - Whether the backend hop is encrypted — i.e. does the controller talk to
traceable-routerover h2c (8000) or HTTPS (443/8443).
These two choices produce the configurations described per-option below.
Option 1: Cloud Kubernetes Service type LoadBalancer¶
On managed Kubernetes (EKS, GKE, AKS) the simplest and most common approach is to expose traceable-router directly with a LoadBalancer Service. The cloud provider provisions an external load balancer, and you do not deploy any ingress controller.
Set controller: none in traceable-ingress (so no ingress object is rendered) and configure the traceable-router Service.
Generic cloud LoadBalancer (TLS terminated in Envoy)¶
The load balancer passes TLS straight through to Envoy, which terminates it using tlsSecretName:
# traceable-router values
httpsEnabled: true
httpEnabled: false
tlsSecretName: traceable-router-certs
service:
type: LoadBalancer
primaryPortDef:
name: https
port: 443
targetPort: https # -> Envoy 8443
secondaryPortDef:
port: 0 # disables the second port
AWS EKS scenarios¶
AWS supports several patterns depending on where you want TLS terminated and whether you use an ACM certificate on the Network Load Balancer (NLB). Apply these annotations on the traceable-router Service.
1. TLS passthrough at the NLB¶
TLS is terminated by Envoy; the NLB forwards TCP only.
NLB:443 [tls-passthrough] ──► traceable-router:8443 (https)
httpsEnabled: true
httpEnabled: false
service:
type: LoadBalancer
primaryPortDef:
name: https
port: 443
targetPort: https
secondaryPortDef:
port: 0
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
2. TLS termination at the NLB (ACM certificate)¶
The NLB terminates TLS with an ACM certificate and forwards cleartext HTTP/2 to Envoy.
NLB:443 [ACM cert] ──► traceable-router:8000 (http/h2c)
httpEnabled: true
httpsEnabled: false
service:
type: LoadBalancer
primaryPortDef:
name: https
port: 443
targetPort: http
secondaryPortDef:
port: 0
annotations:
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-2:ACCT_ID:certificate/CERT_UUID"
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
3. TLS termination at the NLB and re-encryption to Envoy¶
The NLB terminates the client TLS (ACM), then opens a new TLS connection to Envoy (defense in depth).
NLB:443 [ACM cert] ──[ssl]──► traceable-router:8443 (https)
httpsEnabled: true
httpEnabled: false
service:
type: LoadBalancer
primaryPortDef:
name: https
port: 443
targetPort: https
secondaryPortDef:
port: 0
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: ssl
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-2:ACCT_ID:certificate/CERT_UUID"
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
4. TLS passthrough with a Classic Load Balancer¶
CLB:443 [tls-passthrough] ──► traceable-router:8443 (https)
httpsEnabled: true
httpEnabled: false
service:
type: LoadBalancer
primaryPortDef:
name: https
port: 443
targetPort: https
secondaryPortDef:
port: 0
GKE / AKS notes¶
- GKE: A
Serviceof typeLoadBalancerprovisions a regional TCP/UDP load balancer. For TLS passthrough, follow the generic example above (TLS terminated in Envoy). To terminate TLS at a Google load balancer instead, use a GKE Ingress/Gateway with a managed certificate pointing at thetraceable-routerService. - AKS: A
Serviceof typeLoadBalancerprovisions an Azure Load Balancer. Use the generic passthrough example, or addservice.beta.kubernetes.io/azure-load-balancer-internal: "true"for an internal-only endpoint.
DNS¶
After the load balancer is provisioned, create a DNS record for your platform host pointing at the load balancer's external address:
kubectl get svc traceable-router -n traceable \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}{.status.loadBalancer.ingress[0].ip}'
Create a CNAME (for a hostname) or an A record (for an IP) for traceable.yourcompany.com.
Option 2: NGINX Ingress¶
If your cluster runs the ingress-nginx controller, you can use legacy mode, where NGINX routes directly to the platform services.
# traceable-ingress values
router: legacy
host: traceable.yourcompany.com
tlsSecretName: star-yourcompany-com
ingressClassName: nginx
isIamV2Enabled: false # set true if IAM v2 is enabled
ingress:
authUrl: http://jwt-auth.traceable.svc.cluster.local
authSignin: https://traceable.yourcompany.com/login
proxyBodySize: "10m"
# configurationSnippet sets the in-cluster DNS resolver used by NGINX
configurationSnippet: |-
resolver 10.0.0.10 ipv6=off;
Notes:
- Set
configurationSnippet'sresolverto your cluster's DNS service IP (kubectl get svc -n kube-system kube-dns). - TLS is terminated by NGINX using the
tlsSecretNamesecret. Front NGINX with whatever external load balancer your environment provides. - gRPC ingestion paths (OpenTelemetry, config service) are served via dedicated
Ingressobjects annotated withbackend-protocol: GRPC.
Tip: You can also run NGINX in front of the Envoy router by setting
router: envoyandcontroller: nginx. In that mode NGINX forwards everything to the singletraceable-routerService instead of routing per-path. Use this when you want NGINX as the edge but prefer Envoy to own the platform routing table.
Option 3: Traefik (Envoy mode)¶
For clusters standardized on Traefik, use Envoy mode with the Traefik controller. The chart renders Traefik IngressRoute (and, when the backend hop is encrypted, ServersTransport) CRDs that point at traceable-router.
TLS terminated at Traefik, h2c to Envoy¶
This is the common case: Traefik terminates client TLS and forwards cleartext HTTP/2 to Envoy on port 8000.
router: envoy
controller: traefik-ingress
host: traceable.yourcompany.com
tlsSecretName: star-yourcompany-com
traceableRouter:
serviceName: traceable-router
servicePort: 8000
tlsEnabled: false # h2c backend hop
traefikIngress:
ingressClassName: traefik
entryPoints:
- websecure
passHostHeader: true
The chart additionally renders a dedicated route for /ti/ws (the installer WebSocket path) so it traverses over HTTP/1.1 cleanly.
Re-encrypt: TLS to Envoy as well¶
To encrypt the Traefik → Envoy hop, set traceableRouter.tlsEnabled: true. The chart then targets port 443 with scheme: https and generates a ServersTransport for backend verification.
router: envoy
controller: traefik-ingress
host: traceable.yourcompany.com
tlsSecretName: star-yourcompany-com
traceableRouter:
serviceName: traceable-router
servicePort: 443 # traceable-router Service must expose 443 (httpsEnabled)
tlsEnabled: true
traefikIngress:
ingressClassName: traefik
entryPoints:
- websecure
passHostHeader: true
serversTransport:
serverName: "" # defaults to .host
insecureSkipVerify: false
rootCAsSecrets: [] # Secrets holding CA certs (tls.ca / ca.crt) to trust
When
tlsEnabled: true, ensure thetraceable-routerService exposes port443(httpsEnabled: true). If you use a self-signed backend certificate, either provide the CA viaserversTransport.rootCAsSecrets/selfSignedCertificates, or setinsecureSkipVerify: true(not recommended for production).
Option 4: OpenShift Route (Envoy mode)¶
On OpenShift, ingress-nginx typically cannot be used. Use Envoy mode with the OpenShift Route controller; the chart renders a route.openshift.io/v1 Route pointing at traceable-router.
router: envoy
controller: openshift-route
host: traceable.yourcompany.com
traceableRouter:
serviceName: traceable-router
openshiftRoute:
weight: 100
tlsTermination: passthrough # passthrough | terminate | reencrypt
TLS termination modes¶
tlsTermination |
Behavior | Requirements |
|---|---|---|
passthrough |
The Route forwards encrypted traffic to Envoy, which terminates TLS. | traceable-router must serve HTTPS (httpsEnabled: true). |
terminate |
The OpenShift router terminates TLS (edge) and forwards cleartext to Envoy. insecureEdgeTerminationPolicy: Redirect is set. |
Provide edge certs via openshiftRoute.certificates, or rely on the default router cert. |
reencrypt |
The router terminates client TLS, then re-encrypts to Envoy. | traceableRouter.tlsEnabled: true is required (the chart fails the render otherwise). |
For terminate and reencrypt, supply certificates in PEM format:
openshiftRoute:
tlsTermination: reencrypt
certificates:
key: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
certificate: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
caCertificate: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
destinationCACertificate: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
traceableRouter:
tlsEnabled: true
DNS for OpenShift Routes¶
Create a CNAME for your platform host pointing at the Route's canonical hostname:
See the OpenShift Configuration guide for the full namespace-scoped install workflow.
Choosing the right option¶
| Your environment | Recommended option |
|---|---|
| EKS / GKE / AKS (managed cloud) | Cloud LoadBalancer (direct traceable-router Service) |
ingress-nginx already installed, cluster scope |
NGINX Ingress (legacy) |
| Red Hat OpenShift | OpenShift Route |
| Traefik-standardized cluster | Traefik |
| No ingress controller / want minimal moving parts | Cloud LoadBalancer, or Envoy mode with controller: none behind your own L4 LB |
Validation¶
After exposing the platform, validate connectivity:
# Service and (if LoadBalancer) external address
kubectl get svc traceable-router -n traceable
# Envoy readiness via the admin port
kubectl port-forward -n traceable svc/traceable-router-internal 9901:9901
curl -s http://localhost:9901/ready
# End-to-end: the login page should respond
curl -kI https://traceable.yourcompany.com/login
Expected: the /login request returns an HTTP 200 (or a 302 redirect to the login flow), confirming traffic reaches Envoy and the IAM service.
Troubleshooting¶
TLS handshake failures / certificate errors¶
Symptoms: Browser shows certificate warnings, or curl reports SSL certificate problem.
Causes & solutions:
- The certificate in
tlsSecretNamedoes not matchhost. Verify the SAN covers your DNS name. - For re-encrypt setups with a self-signed backend cert, the controller cannot verify Envoy's certificate. Provide the CA (
serversTransport.rootCAsSecretsfor Traefik,destinationCACertificatefor OpenShift), or temporarily setinsecureSkipVerify: trueto isolate the issue.
502 / 503 from the ingress¶
Symptoms: The edge responds but returns 502 Bad Gateway or 503.
Causes & solutions:
- Backend protocol mismatch. Envoy's HTTP listener is h2c (HTTP/2 cleartext). Ensure the controller forwards HTTP/2 (
scheme: h2cfor Traefik,backend-protocol: GRPC/HTTP2 for NGINX) when targeting port8000. traceable-routerpods are not ready. Checkkubectl get pods -n traceable -l app.kubernetes.io/name=traceable-routerand the/readyadmin endpoint.
Login redirect loops or wrong host¶
Symptoms: Repeated redirects to /login, or redirects to the wrong hostname.
Causes & solutions:
- The original
Hostheader is not preserved. Enable host pass-through (passHostHeader: truefor Traefik; preserveHoston NGINX). Envoy builds the login redirect from the inbound:authority.
WebSocket (/ti/ws) or installer UI fails¶
Symptoms: The installer (TI) WebSocket connection drops.
Causes & solutions:
- The
/ti/wspath must traverse over HTTP/1.1, not HTTP/2. The Traefik templates render a dedicated/ti/wsroute for this; ensure you did not override it. For custom edges, route/ti/wsover HTTP/1.1 withUpgradeheaders allowed.
LoadBalancer stuck in <pending>¶
Symptoms: kubectl get svc traceable-router shows EXTERNAL-IP: <pending>.
Causes & solutions:
- The cloud controller cannot provision the LB. On EKS, confirm the AWS Load Balancer Controller is installed and the subnet tags are correct. Check
kubectl describe svc traceable-router -n traceableevents.
Related guides¶
- Overriding Helm Chart Values
- OpenShift Configuration
- AWS EKS Configuration
- TLS Certificates
- Update Certificates
- Update DNS
Support¶
For connectivity and ingress assistance, contact support@harness.io.
When requesting support, provide:
- The routing mode (
legacyorenvoy) andcontrollervalue - The
traceable-routerService definition and annotations - Output of
kubectl get svc,ingress,route -n traceable - Relevant controller and
traceable-routerpod logs