Skip to main content

Threat intelligence and the data relay

The relay is one in-cluster service, download-api. It is the only component with a route out, and it is how your fleet gets threat intelligence.

This is not a choice you make. It is a requirement. See Known limitations.

What it relays

Read-only, upstream-produced content only.

ClassRoutesWhy it is not shipped
CTI indicators/v1/indicators/version, /v1/indicators/downloadBuilt by the upstream intelligence pipeline
ML models/v1/models/* and the per-model aliasesTrained and published by Gen0Sec
GeoIP/v1/geoip/manifest, /v1/geoip/{file}/downloadLicensed by MaxMind and IPInfo. The IPInfo Lite bundle is the default source
IDS rules/v1/ids-rules/*Licensed as part of the Emerging Threats ruleset

It is a relay, not a cache. Nothing is stored on the way through. There is no local artifact store to size, no synchronization job to supervise, and no staleness window. An agent that polls gets whatever upstream has at that moment.

The relayed URLs are identical to the direct ones, so your agents need no configuration change.

What it never relays

ClassRoutesWhy
Workload identity/v1/identity/*Produced in your cluster, describes your workloads
Policy edges/v1/policy-edges/*Pod IPs, namespaces, NetworkPolicy edges
Fleet bans/v1/fleet-bans/*Your own agents' ban decisions

These three are tenant-scoped: they describe your infrastructure or your decisions. Relaying them would push that to a service you do not run. They keep the local object store path behind the local authorization check, in relay mode exactly as without it.

Uploads are never relayed. The relay is read-only, so PUT and POST on the download surface are served locally or not at all.

How authorization works

Two hops, two credentials, checked in two places.

HopCredentialChecked by
Agent to relayThe agent's own key, issued by your dashboardYour cluster. Relayed routes sit behind the local auth middleware and each carries the same permission it has in direct mode
Relay to Gen0SecYour Gen0Sec API keyGen0Sec

A caller's key is never forwarded upstream on a self-hosted deployment. A locally-issued key cannot authenticate to gen0sec. Forwarding it would leak a local credential to a third party without making the request succeed. With no Gen0Sec API key configured, the relay sends no credential at all.

The setting that must be right

downloadProxy:
enabled: true
upstream: "https://api.gen0sec.com"
apiKeySecret:
name: gen0sec-download-proxy # named by default
key: DOWNLOAD_PROXY_API_KEY

Why the key is required

Your agents' keys are issued by your dashboard and exist only in your database, so they cannot authenticate to gen0sec. The relay presents your own Gen0Sec API key instead, and that is the only credential the upstream will accept from your installation.

Without it, the relay sends no credential, Gen0Sec answers 401, and no relayed artifact reaches your fleet.

The chart names the secret by default, so this fails loudly now

apiKeySecret.name defaults to gen0sec-download-proxy. If that secret does not exist, the relay pod never starts: CreateContainerConfigError, visible immediately.

That is deliberate. An empty name renders no environment variable at all, the relay starts, and the only symptom is every relayed class answering 401 while agents report empty rulesets rather than errors. A failed rollout at install time is the cheaper failure.

Blank the name only if you relay through a gateway that supplies its own credential.

Getting the key right

printf '%s' '<your Gen0Sec API key>' > ~/.gen0sec/relay-key
kubectl -n gen0sec create secret generic gen0sec-download-proxy \
--from-file=DOWNLOAD_PROXY_API_KEY=$HOME/.gen0sec/relay-key

The value renders as a secretKeyRef, so it never appears in a manifest or in a values file.

All settings

KeyDefaultMeaning
downloadProxy.enabledtrueTurning it off is not supported
downloadProxy.upstreamhttps://api.gen0sec.comThe upstream base URL. A malformed value fails startup rather than degrading
downloadProxy.externalgeoip,ids-rulesWhich external classes to relay. An unknown name fails startup
downloadProxy.timeout60sUpstream request timeout, matching the router's own
downloadProxy.apiKeySecret.name""Set this. See above
downloadProxy.apiKeySecret.keyDOWNLOAD_PROXY_API_KEYThe key within the secret
Failing startup is deliberate

A malformed upstream is not treated as "fall back to reading from the local object store". That would leave every agent poll erroring against a store this deployment does not populate. Failing fast is the safer wrong answer.

Verifying

kubectl -n gen0sec get --raw \
'/api/v1/namespaces/gen0sec/services/g0s-download-api:http/proxy/status/healthz'

The output is similar to this:

{ "status": "ready", "mode": "proxy", "upstream": "https://api.gen0sec.com",
"external_relays": ["geoip", "ids-rules"] }

That tells you the relay started, not that it is authorized. For that, read the log:

kubectl -n gen0sec logs deploy/g0s-download-api | grep -i 'relayed from upstream' | tail -5

Any status=401 means your Gen0Sec API key is missing or wrong.

Response codes worth knowing

CodeMeansWhat an agent does
200Relayed successfullyUses the artifact
401The upstream rejected the credentialReports an empty ruleset, not an error. This is the silent failure
502The upstream is unreachableReads it as "ask again later" and keeps what it holds. Correct degradation
404The artifact does not exist upstreamTreats it as withdrawn

The 401 and 502 rows are the reason this page exists.

Preview a change before applying it

helm template g0s $B/charts/gen0sec-platform-*.tgz -n gen0sec \
-f $B/values/gen0sec-platform-values-onprem.yaml \
--set downloadProxy.apiKeySecret.name=gen0sec-download-proxy \
| grep -A3 DOWNLOAD_PROXY