Skip to content

Network and hardening

This page is for the platform and security teams who run Olympusx AI: what it exposes, what it reaches, how its secrets are kept, and how to check that the images you run are the ones Olympusx built.

Address Who reaches it Needed
https://<console-host> People’s browsers: the console and its API under /api Yes, from wherever people work
https://<gateway-host>/v1 Applications, editors and agents calling models with API keys Yes, from wherever those run
The identity provider’s issuer People’s browsers, to sign in Yes. With the built-in identity service it is under /auth on the console host.
https://<console-host>/api/v1/hooks/code-sources/<id> Your code host (GitLab, GitHub, Bitbucket Cloud), for merge request reviews Only for code sources that review merge requests. See Merge request review.
https://<console-host>/api/v1/hooks/log-sources/<id> Your alerting system, sending alerts for investigation Only when alerts are sent in. See Alert integration.

A code host or alerting system on the public internet must reach the hook addresses. Everything else can stay on a private network. Each hook is authenticated by its source’s own secret.

The platform’s internal ports, its metrics endpoints and the database are never exposed through the console or gateway hosts.

Network policies in the platform’s namespace

Section titled “Network policies in the platform’s namespace”

Network policies are on by default. They make sure:

  • the control plane’s internal listeners, which the gateway calls on every request, are reachable from the gateway’s pods only. Anyone who could reach them could mint authorization decisions and billing events.
  • the metrics ports are reachable only by your monitoring. See Metrics scrapers.
  • the database instances admit the database operator on their management port and nothing else beyond the platform’s own pods.

Leave them on. If your cluster’s network plugin does not enforce network policies, the objects are inert: record that in your risk register rather than relying on them. OVN-Kubernetes and Calico enforce them; a managed cluster with policy enforcement disabled does not.

By default any source may reach the gateway’s port: it is the authenticated inference API, reached through the ingress or route and directly by in-cluster applications. To narrow it, list the allowed peers in the chart’s networkPolicy.gatewayFrom: your ingress controller’s namespace (on OpenShift, the router) and the namespaces of in-cluster clients. The control plane is always admitted, because agent runs call the gateway.

spec.networkPolicy.metricsScrapers lists who may scrape the control plane’s port 8086, the metering worker’s 8082 and the database’s 9187. Each entry is a network policy peer, as in a policy’s from:. The list replaces the default:

Cluster Default
Kubernetes The namespace named monitoring
OpenShift Namespaces labelled network.openshift.io/policy-group: monitoring, which admits user-workload monitoring
spec:
networkPolicy:
metricsScrapers:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: observability

An empty list is refused. A wrong list breaks nothing visibly: pods stay ready, and Prometheus shows the targets down.

A second field names the namespace the database operator runs in, when it is not that operator’s default. Wrong, the database still serves queries but stops failing over. See Configuration.

Each project gets a namespace on every cluster where it holds quota. Olympusx AI applies to it:

  • network policies that deny all traffic in both directions by default, then allow DNS, traffic within the namespace, and traffic to and from the platform’s namespace. There is no internet egress. A model server there loads its weights from your registry, not from the internet;
  • a resource quota and default limits from the project’s quota;
  • an edit role and a view role, neither of which can change the quota, the limits, the network policies or roles. People cannot weaken their own boundary.

Olympusx AI never adopts a namespace labelled for another tenant, or an unlabelled one that already exists, and never deletes a namespace it did not create for a project.

The roles are bound to people only when the installation sets a group template, a pattern containing {tenant} that names the group your cluster’s authentication gives a tenant’s people. Without it, no binding is created.

What the platform itself reaches, and how to control it:

Destination From Control
The identity provider’s discovery and keys The control plane Must be reachable.
Cloud model providers, over HTTPS The control plane An egress proxy through the chart’s control-plane environment (HTTPS_PROXY, NO_PROXY).
Hugging Face, for imports An import job on a connected cluster, or the bastion agent Declare air-gapped clusters; fetch through a bastion. See Remote access.
Tenants’ tool servers (MCP) The control plane, during agent runs Public addresses over https:// only, by default. In-cluster hosts must be listed in spec.agents.mcpInternalAllowList. See below.
Registered clusters’ API servers The control plane Must be reachable from the platform.

By default a tenant’s tool server is reached only on a public address over https://. Private ranges (10/8, 172.16/12, 192.168/16, fc00::/7, 100.64/10) are reached only when listed:

spec:
agents:
mcpInternalAllowList:
- '*.tenant-tools.svc.cluster.local'
- 10.20.0.0/16

Entries are host names, *. wildcards, addresses and CIDRs. A listed host may also be reached over plain http://. Loopback, link-local and cloud metadata addresses are never reached, whatever the list says, and the control plane refuses to start on such an entry, or on *.

Keep the list narrow. The cluster’s service and pod ranges contain the platform’s own services, and listing them gives a tenant administrator the reach the policy exists to take away. Prefer a namespace wildcard or a range set aside for tool servers. See Tools.

  • Console and gateway are served over HTTPS through your ingress, or OpenShift routes with edge termination that redirect plain HTTP. One TLS secret can serve both hosts (spec.ingress.tlsSecret).
  • The console sends Strict-Transport-Security: max-age=31536000; includeSubDomains and a content security policy that allows scripts only from itself and connections only to itself and the identity provider.
  • Registered clusters are reached with their certificate verified against the CA you give, or the system’s roots. Skip TLS verification (dev only) exists for development and must stay off.
  • Registries a cluster pulls from are verified the same way; Plain HTTP sends credentials unencrypted and suits only an isolated internal mirror.
  • The bastion agent is reached over mutual TLS only.

The platform’s master key, a Secret named by spec.secrets.masterKey with a SECRETS_MASTER_KEY entry, seals every credential Olympusx AI stores: cluster tokens, registry passwords, model provider keys, bastion client keys and backup keys. Create it once:

kubectl -n <namespace> create secret generic olympus-master-key \
--from-literal=SECRETS_MASTER_KEY="$(openssl rand -base64 32)"
  • No API response ever contains a sealed credential. Pages show only whether one is set, or its last four characters.
  • Without the master key, Olympusx AI refuses to store a credential rather than store it in the clear.
  • Changing the key makes every sealed credential unreadable, and each must be entered again. Treat it as long-lived, and keep a copy outside the cluster: a restore needs the original. See Backup and restore.

API keys are shown once, when issued, and stored only as a hash. Sign-in passwords are never seen by Olympusx AI: they live in the identity provider.

Every tenant-scoped table in the platform database carries a row-level security policy that is enforced even for the table’s owner: a request scoped to one tenant cannot read another tenant’s rows. On an installation with the bundled database, the platform’s database account holds no superuser rights, so the policies apply from the first query.

Turning on tenant isolation at installation goes further: the platform then connects with a restricted role that does not own the tables and cannot drop the policies that constrain it. It needs a separate database role Secret. The operator refuses the resource when tenant isolation is on and that Secret is not given. See Configuration.

Tenant knowledge lives in separate vector databases, one per instance, with its own credentials.

Every published Olympusx AI image and the Helm chart are signed, and every image except the operator catalog carries a software bill of materials (SBOM) and build provenance.

  • cosign v2 or later.

  • The Olympusx AI public signing key, supplied with your release. Check its fingerprint against the one your Olympusx contact gives you through a separate channel: that comparison is what makes the rest meaningful.

    sha256sum olympus-cosign.pub
cosign verify \
--key olympus-cosign.pub \
--insecure-ignore-tlog=true \
<registry>/olympus-control-plane:<version>

Output naming the key and the digest means the image is exactly what Olympusx built. An error means it is not: do not deploy it, and tell your Olympusx contact.

Verify each image you run, starting with the operator catalog, which a cluster installing through the operator pulls first: the operator catalog, operator and operator bundle, the control plane, the console, the code parser, the guardrails service, the reranker, the model importer, the optional GPU agent, and the chart. The guardrails and reranker images do not change with every release; verify the digest your installation pins, not a tag.

--insecure-ignore-tlog=true turns off only the public transparency-log check. The signature is still verified against the key.

A tag can be moved; a digest cannot. Deploy by the digest you verified, by setting each image’s tag to <version>@sha256:<digest>.

They are attestations inside the image index, read with the tool that wrote them, from the verified digest:

D=$(crane digest <registry>/olympus-control-plane:<version>)
cosign verify --key olympus-cosign.pub --insecure-ignore-tlog=true \
"<registry>/olympus-control-plane@$D"
docker buildx imagetools inspect "<registry>/olympus-control-plane@$D" \
--format '{{ json .SBOM }}' > sbom.json
docker buildx imagetools inspect "<registry>/olympus-control-plane@$D" \
--format '{{ json .Provenance }}'

Reading them from a tag proves nothing on its own: pin first, then inspect. The registry address and pull credential come with your subscription.