Installing Hyvop with no internet access#
An air-gapped install has three parts: the images and the chart carried in on a bundle, a private registry inside, and values that close every way out. This page gives the bundle, the steps, and the inventory of every outbound call, with the switch that turns each one off.
The network policies enforce this list: a call not listed here is refused by the network, not by promise.
1. Make the bundle (where there is internet)#
Needs helm and skopeo.
scripts/airgap-bundle.sh --list # every image the chart can render, one per line
scripts/airgap-bundle.sh --version 0.9.0 # dist/hyvop-airgap-0.9.0.tar (+ .sha256)Images are copied with skopeo copy --all, which keeps the manifests as they are, so that a reference pinned by
@sha256 in the chart is still true in your registry. Do not move these images with docker save | docker load | docker push: that can change the digest, and the pod then fails to pull.
The bundle holds: the chart (hyvop-0.9.0.tgz), the images (images/), images.txt, images.lock, this page,
and load-and-install.sh. Verify the archive with its .sha256.
The bundle script copies; it does not check signatures. Where there is internet, check them before you build: the
cosign verify commands for the five images and the chart are in install.md. A signature stays valid
after skopeo copy --all because the manifests are not changed; check them there, not in the private registry, where
the certificate identity of the signer cannot be looked up without the internet.
During the 0.9.0 beta the packages are private: log in to ghcr.io with a GitHub token that can read the packages
(skopeo login ghcr.io, and docker login ghcr.io for cosign verify) before airgap-bundle.sh. In the air-gapped
cluster the images come from your own registry; if that registry needs a login, create the pull secret in the
namespace and set global.imagePullSecrets too (install.md, "Private packages"). When the Community
packages are public, the GitHub login is not needed.
2. Load and install (inside)#
tar xf hyvop-airgap-0.9.0.tar && cd hyvop-airgap-0.9.0
skopeo login registry.corp.example:5000
./load-and-install.sh registry.corp.example:5000/hyvop --load-only # copy the images in
./load-and-install.sh registry.corp.example:5000/hyvop -f my-values.yamlThe registry argument is the value of global.imageRegistry: ghcr.io/hyvop-inc/hyvop-core:0.9.0 becomes
registry.corp.example:5000/hyvop/hyvop-inc/hyvop-core:0.9.0, and postgres:18-alpine@sha256:... becomes
registry.corp.example:5000/hyvop/postgres:18-alpine@sha256:.... Pull secrets for the registry go in
global.imagePullSecrets.
load-and-install.sh installs with these values, which your own arguments may override:
| Value | Why |
|---|---|
global.imageRegistry=<registry> |
every image from the private registry |
networkPolicy.egress.core.internet=false |
core may not leave the cluster |
networkPolicy.egress.ingestors.internet=false |
the ingestors may not leave the cluster |
core.env.DETECTOR_CATALOGUE_REMOTE=false |
no call to the registry: no detector update is offered, and the detectors shipped with the release are installed and run as they are. Nothing is lost |
githubMcp.enabled=false |
that server exists to reach github.com (see below) |
networkPolicy.enabled (on by default) must stay on, and the cluster's network plugin must enforce
NetworkPolicy (Calico, Cilium, most managed clusters; kind's default plugin does not).
3. Every outbound call, and its switch#
| Component | Call | Needed for | Off switch, or the internal alternative |
|---|---|---|---|
| core | The model provider (AI_PROVIDER) |
AI features | core.env.AI_PROVIDER: "" (the default): AI is off. For a model of your own, AI_PROVIDER=openai-compatible with OPENAI_BASE_URL pointing to a service inside the cluster or network, and its address range in networkPolicy.egress.extraCidrs. Keep networkPolicy.egress.core.internet=false. |
| core | The detector catalogue (registry.hyvop.com by default) |
offering detector updates | core.env.DETECTOR_CATALOGUE_REMOTE=false: only the catalogue shipped in the image is used. An air-gapped install loses none of it. |
| core | A mail relay, when set | e-mail links (confirm an address, reset a password) | Leave it unset (no e-mail is sent), or name a relay inside the network with networkPolicy.egress.extraCidrs. |
| core | Git hosts and integrations a person adds (GitHub Enterprise, GitLab, webhooks) | integrations | Do not add them. A host inside the network is allowed to core by core.env.OUTBOUND_ALLOWED_HOSTS and networkPolicy.egress.extraCidrs; core refuses private addresses otherwise. |
| core | An OIDC identity provider | sign-in with your IdP | Use the e-mail and password sign-in (default; single sign-on is Enterprise). An IdP inside the network goes in networkPolicy.egress.extraCidrs. |
| ingestors (aws, azure, gcp) | The cloud's APIs (443) | collecting an account | networkPolicy.egress.ingestors.internet=false. With it closed, nothing is collected from a public cloud; an account reachable only through a private endpoint (a VPC endpoint, a private link) gets it with ingestors.<cloud>.extraCidrs. |
| ingestor-aws | The AWS price lists (public) | prices | Read them from a bundle on disk: ingestors.aws.env.PRICING_SOURCE_DIR=/path. |
| github-mcp | github.com, or the GitHub host (githubMcp.host) |
the ownership graph | githubMcp.enabled=false. A GitHub Enterprise Server inside the network is added to networkPolicy.egress.extraCidrs (443). |
| clickhouse-mcp | none | Off by default (clickhouseMcp.enabled=false). |
|
| ui, postgres, valkey, clickhouse, keycloak | none (DNS and the cluster only) | Their policies allow DNS and the pods that use them, nothing else. | |
| the nodes | Image pulls by the kubelet | starting | global.imageRegistry (the bundle). Not a call by the pods; the nodes pull. |
Whatever is on, kubectl -n hyvop get cm hyvop-network-egress -o jsonpath='{.data.egress\.md}' shows what
the policies of this install allow.