Skip to main content

Publish the endpoints

The ingress controller is installed and running. However it's not configured to serve anything by default. That is deliberate, because creating those routes makes the APIs reachable from wherever the controller is reachable, so it is your decision, not ours.

The data plane's LoadBalancer Service already has an external address at this point. Until you complete this page it serves nothing, because no rule names a host.

Ingress and TLS are yours to configure

The platform ships the routing rules. Terminating TLS, issuing the certificate and exposing the LoadBalancer are your cluster's responsibility. For the configuration options, see the Kubernetes ingress reference.

Before you start

  • Install complete, all pods running
  • A DNS name you control, resolving to your ingress controller's address
  • A LoadBalancer address for the ingress data plane, or a Service type your cluster can expose
  • A TLS certificate for that name, or cert-manager configured

1. Choose the address

One address serves the dashboard and every agent-facing API. Requests are routed by path prefix.

export ENTRYPOINT_HOST=cerebellum.example.internal

The host is required. A rule with no host is silently ignored by the ingress controller: the Ingress object is created, no event is logged, and nothing serves traffic.

Use the address people will actually type. The dashboard derives its sign-in URL from this host, and sign-in fails if the two do not match.

2. Publish

The kit ships the overlay. Layer it on top of the values file you have been using.

helm upgrade g0s $B/charts/gen0sec-platform-*.tgz \
-n gen0sec \
-f $B/values/gen0sec-platform-values-onprem.yaml \
-f $KIT/examples/single-entrypoint/ingress-values.yaml \
--set entrypointHost=$ENTRYPOINT_HOST \
--set global.imageTag=$VERSION \
--timeout 20m
Re-pass every values file you installed with

helm upgrade applies only the files you pass it. Anything layered at install time and omitted here reverts to the chart default. On the Quickstart you also passed -f $KIT/examples/single-node/platform-values.yaml, so include it in this upgrade too (before the ingress overlay), or every service scales back to its production replica count:

helm upgrade g0s $B/charts/gen0sec-platform-*.tgz \
-n gen0sec \
-f $B/values/gen0sec-platform-values-onprem.yaml \
-f $KIT/examples/single-node/platform-values.yaml \
-f $KIT/examples/single-entrypoint/ingress-values.yaml \
--set entrypointHost=$ENTRYPOINT_HOST \
--set global.imageTag=$VERSION \
--timeout 20m
Quote any --set argument containing brackets

zsh treats [0] as a glob and fails before helm runs. Single-quote the whole argument: --set 'services.ui.ingress.hosts[0].host=...'.

3. Verify the routes exist

kubectl -n gen0sec get ingress

The output is similar to this:

NAME CLASS HOSTS ADDRESS PORTS AGE
g0s-platform synapse cerebellum.example.internal 10.0.0.42 80 30s

An empty HOSTS column means the host was not applied, and nothing will serve traffic.

Then check from outside the cluster. The dashboard is published at / and returns a redirect to its sign-in page, so follow it with -L:

curl -fsSL -o /dev/null -w '%{http_code}\n' https://$ENTRYPOINT_HOST/

The output is similar to this:

200
There is no health endpoint on the ingress

/status/healthz is served per pod inside the cluster and is deliberately not published through the ingress. A request to it from outside falls through to the dashboard catch-all and returns 404, so do not use it as an external check. The dashboard root above confirms reachability; the smoke test confirms the platform serves agents.

Find the address to point DNS at

The ingress data plane is a LoadBalancer Service.

kubectl -n gen0sec-system get svc g0s-infra-synapse -o wide

Point your DNS name at the external address. If EXTERNAL-IP stays <pending>, your cluster has no LoadBalancer implementation: change the Service type to something it can expose. It cannot stay cluster-internal.

The route table

You do not configure these. The overlay sets them, read off each service's own router. They are here because they are the answer to "a request landed on the wrong backend", and because a missing route fails quietly rather than loudly.

Path prefixServed by
/Dashboard (catch-all, shortest prefix, so it is last resort)
/v1/indicators, /v1/models, /v1/geoip, /v1/ids-rulesRelay
/v1/penalty-model, /v1/traffic-model, /v1/ja4-classifier, /v1/flow-classifier, /v1/jepa-embedderRelay, per-model aliases
/v1/identity, /v1/policy-edges, /v1/fleet-bansRelay, served locally
/v1/authcheck, /v1/authAuthentication
/v1/events, /v1/agents, /v1/logAgent ingest
/v1/agents/eventsConfiguration push (longer prefix than /v1/agents, so it wins)
/v1/configConfiguration
/v1/telemetry, /v1/logsTelemetry
/v1/signal, /v1/rulesSignal
/v1/ban-ledgerBan ledger
/v1/threatThreat feeds
/v1/service-graphService graph

Routing is by longest matching prefix, because one address serves every backend.

The configuration push stream on /v1/config is long-lived, so the chart sets read, write and idle timeouts of 3600 seconds on that route. Do not lower them: agents fall back to polling with no push, which looks like a slow platform rather than a timeout.

Why a missing route is worse than a broken one

The dashboard owns /, so any path absent from this table falls through to it and gets a redirect or HTML. HTTP has no way for the caller to tell that apart from a real answer, so the failures are silent:

Missing routeWhat the agent actually does
/v1/authcheckReceives HTML, cannot distinguish a bad key from a routing mistake, and continues unverified
/v1/agents/eventsLogs SSE connect returned HTTP 404, then falls back to polling. Looks like a slow platform, not a routing bug
/v1/ban-ledgerReads the redirect as success. The contribution is lost with no error anywhere

This is why the overlay exists rather than a list of prefixes for you to type.

/v1/ids-rules goes to the relay, not to the in-cluster rules service

IDS rules are relayed from gen0sec. The in-cluster rules service builds rules from a local ingest pipeline that this edition does not run. Route this prefix there and you reach a service with no rules, and the relay is never used.

If TLS terminates upstream

If a load balancer, CDN or tunnel terminates TLS in front of the ingress, the chart cannot infer the external scheme and guesses http while the browser is on https. The dashboard then builds its sign-in URL with the wrong scheme and rejects every sign-in with Invalid origin.

Set it explicitly:

--set externalScheme=https

Leave it unset when TLS terminates at the ingress, because then the chart reads it from the ingress TLS block.

The dashboard

The dashboard is enabled by default and is published at the root of your address. Sign-in is email and password, held in your own Postgres, so nothing outside the cluster is involved.

Its secret, g0s-db-ui, was created in Install step 6 with all the others. Re-running that script keeps the existing signing secret, so sessions and invite links stay valid.

To leave the dashboard out:

--set services.ui.enabled=false

If it fails

SymptomCause
kubectl get ingress shows an empty HOSTS columnentrypointHost was not set. The controller ignores host-less rules silently
curl times outDNS does not resolve to your ingress controller, or a firewall blocks the port
The dashboard loads but sign-in redirects to the wrong addressThe sign-in URL is derived from entrypointHost. It must be the address people type
A request reaches the wrong serviceLongest-prefix routing. Check the /v1/agents overlap above