Skip to content
Solutions

Pre-1.0 · Design-partner program

Identity without internet access: what it takes.

No telemetry or update checks: what an offline Nauthera installation needs, from mirrored signed images and chart to DNS, keys, PostgreSQL and Redis.

By Michael Beutler, FounderPublished

Nothing in nauthera-server phones home: it has no telemetry and no update check. What it dials is either infrastructure you run or a third party you choose to configure. That makes an installation without internet access a matter of mirroring two signed images and a chart, running the dependencies inside the network, and staying within the limits on external federation below.

Status: each item below is a requirement as the code and docs state it; What has not been checked at the end lists what no recorded installation has run yet. Nauthera is pre-1.0, in a design-partner program: its signed server and operator images and its Helm chart are public on the GitHub Container Registry, and teams can apply for one of five design-partner seats to pilot it with direct support. The source is private.

What the server connects to

ConnectionWhenSet byWithout internet
PostgreSQLAlwaysdatabase.host, database.dsnRun it inside the network. It is the only database the server supports.
RedisFor any issuer whose host is not loopbackcache.address, cache.addressesRun it inside the network, with maxmemory-policy noeviction.
SMTP relayOnly when one is configuredmail.smtp.hostAn internal relay works. Without one, password resets, verification links, invitations and sign-in alerts are not sent.
OpenTelemetry collectorOff by defaulttracing.endpointA collector you run, or leave tracing off.
Breached-password lookupOff by defaultauth.password.breach_lookup.urlLeave it off, or point it at a self-hosted mirror of the range API.
Hosted captchaOnly if chosen; the default is the built-in altchaauth.captcha.providerKeep altcha, which calls no third party.
Upstream OpenID Connect providersFor each IdentityProviderthe resource's providerIssuerPublic addresses only, see below.
GitHub sign-inFor an IdentityProvider of GitHubthe resource's providerIssuerNeeds github.com and api.github.com.
A client's key setFor private_key_jwt clients and signed requestsOIDCClient spec.jwksUriPublic addresses only, see below.
Back-channel logoutFor dynamically registered clients that ask for itthe client's registrationPublic addresses only, see below.
LDAP or Active DirectoryFor each LDAPDirectorythe resource's connection settingsInternal addresses work.

The IP geolocation database for sign-in alerts is a file you mount, not a connection.

Images and the chart, from your own registry

A release publishes two images, ghcr.io/nauthera/nauthera-server and ghcr.io/nauthera/nauthera-operator, each for linux/amd64 and linux/arm64, and one chart at oci://ghcr.io/nauthera/charts/nauthera-server. The chart's templates use no other image: its test pod and its database-maintenance jobs run the server image. A released chart pins both images by digest, and image.digest wins over image.tag.

  1. On a connected machine, verify the signatures. Each image and the chart are signed keyless with cosign, and verification checks Sigstore's public transparency log, so it needs internet access; verifying offline is not documented. See Installation.
  2. Copy both images into your registry with their multi-architecture index unchanged, so the pinned digests still resolve, and push the chart to your registry's OCI path.
  3. Point the release at the copies:
image:
  repository: registry.internal.example/nauthera/nauthera-server
  digest: sha256:…          # the digest the released chart pins
operator:
  enabled: true
  image:
    repository: registry.internal.example/nauthera/nauthera-operator
    digest: sha256:…
imagePullSecrets:
  - name: internal-registry  # also used by the operator and the maintenance pods

The resource definitions come with the chart (operator.crds.install), so helm upgrade also updates them. Mirror what the chart depends on as well: cert-manager, which the production profile turns on (certManager.enabled), and the Prometheus Operator or Gateway API definitions if you turn on metrics.serviceMonitor, metrics.prometheusRule or httpRoute.

DNS and the issuer URL

The issuer URL must be HTTPS, with a host and no path. Browsers open it to sign in, and every application fetches its discovery document and keys from it, so the same name has to resolve, to the same server, both on your users' machines and inside the cluster. Each further organization is served under that host, at /orgs/<slug>.

Keys and certificates

With certManager.enabled, as in the production profile, cert-manager issues every key the server needs: the JWT signing keys (EC P-256 for ES256 and RSA for RS256) and the key that signs the audit log's checkpoints, and with certManager.grpcTLS.enabled the mutual-TLS certificates of the operator's connection. The browser-facing certificate comes from certManager.issuerRef, or from the chart's own CA. Without internet access there is no public ACME issuer, so name one of your own and make every application trust it: Argo CD takes a rootCA in its OIDC settings (Argo CD), Grafana a tls_client_ca (Grafana). cert-manager never re-keys the signing keys (rotationPolicy: Never), because a new key would invalidate every token in flight. See Certificates and Keys & Secrets.

External federation: public addresses only

When the server fetches a URL on someone's behalf, an upstream provider's discovery document, token endpoint and keys, a client's jwks_uri, or a back-channel logout notification, it refuses loopback, private, link-local and shared address space. It checks the resolved address again when it dials and follows no redirects, and there is no setting to allow private targets. In a network where every address is private, that means:

  • An internal OpenID Connect provider, such as a Keycloak at a 10.x address, cannot be an IdentityProvider.
  • A private_key_jwt client cannot publish its key set on a private address.
  • Back-channel logout to applications on private addresses is refused.

An HTTPS_PROXY helps only when the proxy itself has a public address: upstream-provider and key-set fetches dial the proxy through the same check, so one on a private address is refused too. Back-channel logout reaches its proxy wherever it is, but resolves each application's address itself and still refuses a private one. LDAP and Active Directory are not held to the rule: an LDAPDirectory reaches your directory wherever it is, so in a closed network that is the way to sign in with existing accounts. See Hardening.

In the browser

The sign-in pages load from the server. A Branding can name a logo by any HTTPS URL and fonts from Google Fonts, which the sign-in pages' Content-Security-Policy admits; keep a branding's assets on hosts your users can reach.

Upgrades

An upgrade is the same mirroring for the new chart version, then the documented procedure: back up the database and the secrets, apply the migrations (the chart's pre-upgrade hook runs them with appendOnlyAudit, or the replicas do with database.migrate), and roll out. Check the upgrade notes first: one migration, which changes column types, needs every replica of the earlier release stopped. See Backups & Upgrades.

What has not been checked

  • A complete installation and upgrade with no route to the internet.
  • Verifying the cosign signatures offline.
  • Whether the default sign-in theme loads anything from outside the server.

If you run disconnected clusters and want this validated with you, apply for a design-partner seat below.

Release updates

Hear when the operator ships

One email when the operator ships. No newsletter.

By joining, you agree to our Privacy Policy and Terms.

Design partners

Apply for a design-partner seat

Five teams get calls with the founder, a say in the operator's design, and direct support when they pilot it.

Optional

We store your answers with your email address to select design partners. Privacy Policy