Govern (Keystone) is designed to need no internet access at runtime. Everything it needs after installation, from container images to identity providers, mail and model servers, can live inside your network.
Complete offline operation is a property of each release and each installation, not something a bundle proves by existing. Before you rely on it, run the release on a host with no route out, as described in the last section of this page.
What must be inside the boundary
| Class | Items |
|---|---|
| Images | The Govern images, PostgreSQL, the migration tool, and Mailpit if you use it. The release's deploy/airgap/images.txt lists them. |
| Database | PostgreSQL 15 or later and the release's migrations |
| Identity | Your SAML or OIDC identity provider, if you use single sign-on |
| An SMTP relay inside the network | |
| Models | Self-hosted model servers, if people use models |
| Platform services | DNS, NTP, your TLS certificate authority, backup, monitoring and a log sink |
Optional integrations (SMTP, LDAP, identity providers, webhooks, vendor audit connectors) create outbound traffic when they are turned on. Point them at services inside your network or leave them off.
Build the bundle on a connected host
scripts/airgap/build-bundle.sh --platform linux/amd64 --output dist/ni-auth-airgap
The script builds the Govern images, pulls the pinned dependency images listed in deploy/airgap/images.txt, saves every image into one archive, and packages the loader scripts, the Docker Compose files and the Helm charts with a SHA256SUMS file. For a formal release, replace the image tags in images.txt with immutable registry digests.
Move the bundle through your approved media process, then verify SHA256SUMS inside the air gap before you load anything.
Load the images
On each Docker host:
cd ni-auth-airgap
./install-offline.sh
install-offline.sh loads the images from the archive without network access. For Kubernetes, either import the images into the container runtime of every schedulable node, or retag and push them to a registry inside your network.
Run with Docker Compose
Use the air-gap override, which pins every service to a local image and turns pulls off:
docker compose -f deploy/docker-compose.yml \
-f deploy/docker-compose.airgap.yml up -d --pull never
Run it from the release's source tree, so the migrations and the database role script are present. Set NI_AUTH_IMAGE, NI_AUTH_DASHBOARD_IMAGE, POSTGRES_IMAGE, MIGRATE_IMAGE and MAILPIT_IMAGE if your imported tags differ from the defaults. Configure the stack as in Docker Compose.
Run on Kubernetes
Install the keystone chart as in Kubernetes, with these choices for an isolated network:
image.registryset to your internal registry, with a pull secret if it needs one.- Object storage on a shared ReadWriteMany directory (
objectStorage.local), or an S3-compatible store inside your network (objectStorage.s3.endpoint). - For the optional telemetry pipeline, a directory cold store (
telemetryPipeline.cold.local); for Streams tiered storage,streams.tiering.store=dir.
Render the chart and check that every image comes from your registry before you install:
helm template keystone deploy/helm/keystone -f values.yaml \
| grep -E 'image:|imagePullPolicy:'
Reaching services inside your network
Govern refuses outbound connections to private, loopback, link-local and metadata addresses unless the operator opens them. In an isolated network that is usually exactly where your services are, so list their networks, as narrowly as possible:
| Variable | Opens |
|---|---|
NI_AUTH_OUTBOUND_ALLOW_PRIVATE_CIDRS | Webhooks, approval channels, SIEM collectors, LDAP and Active Directory, inference servers and other tenant-configured destinations |
NI_AUTH_MODELS_PRIVATE_NETWORKS | Model provider connections. Models on openai_compatible or ollama connections inside these networks count as self-hosted, which is what the self_hosted routing rule for restricted data requires. |
KEYSTONE_MCP_ALLOW_PRIVATE_NETWORKS | MCP servers |
Other features that work without reaching outside:
- Workload identity for the model gateway accepts an uploaded key set for OIDC issuers Govern cannot reach, such as an air-gapped cluster.
- Audit tiering works with an on-premises S3-compatible store that supports Object Lock (for example MinIO), because requests are signed without a cloud SDK.
- Offline audit verification with
keystone-audit-verifyneeds no network access. See Verify offline.
Offline licence
Offline licences are signed by Neural Inverse with an Ed25519 key. Only the public key is deployed, in one of:
NI_AIRGAP_LICENSE_PUBLIC_KEY: a PEMPUBLIC KEYblock, or base64 of the 32 raw key bytes;NI_AIRGAP_LICENSE_PUBLIC_KEY_FILE: a path to a file holding it.
The check fails closed. With neither set, licence registration and reads answer 503 license_verification_unconfigured. A value that is not a valid Ed25519 public key stops the server. A licence whose signature does not verify answers 400 license_invalid, and one past its 30-day grace period 422 license_expired; each refusal is audited as airgap.license.refused.
Changes to the air-gap configuration (POST /api/v1/airgap/license and the other write routes under /api/v1/airgap/) are for the platform operator only; organisation owners and admins get 403. Every change is audited.
The air-gap administration API (/api/v1/airgap/*) is partial as a whole: the FIPS mode setting (PUT /api/v1/airgap/fips) is stored but nothing else reads it yet, so it does not change how Govern runs. Licence and bundle verification work as described above.
Verify a release offline
A release is ready for your enclave only when it has run from the transferred bundle alone:
- Use a disposable host or namespace with no default route and a DNS resolver that refuses every query. Mount no build caches, credential stores or home directories.
- Verify the bundle's checksums, import the images without registry access, and deploy with pulls disabled.
- Run the migrations and the startup checks. Exercise sign-in, token issue and refresh, user, organisation and role changes, audit export, restart, and backup and restore, plus each optional integration you plan to use against services inside the network.
- Capture DNS queries, connection attempts and firewall counters throughout. Any undeclared destination, or any attempt to download a package or image, fails the check. Include a browser, because web assets can reach out on their own.
A strict air gap is enforced by your network controls. These tests are defence in depth, not proof that no network path exists.