Skip to content

Custom Domains and TLS

Frank Yglesias Bertheau edited this page Jul 7, 2026 · 1 revision
<h1>ᚾ&nbsp;NornGate — Custom Domains & TLS</h1>

Map a public domain to a realm and terminate TLS at the edge. The one thing to get right first: a custom domain adds a public name and certificate, terminating at the edge — it does not change identity inside the mesh, and a valid certificate is transport, not authorization. The domain still routes through the spine and traverses G0–G4 like any other host.

Hostnames are illustrative; Realm field names are the derived config model; the Istio and cert-manager resources are real APIs.


ᚨ Before you start

Two TLS layers exist — do not conflate them:

  • External TLS — client ↔ edge, a public-CA certificate (ACME / Let's Encrypt) for the custom domain. This is what a browser validates.
  • Internal mTLS — workload ↔ workload inside the mesh, SPIFFE SVIDs, trust domain norngate.com. The custom domain never touches this.

And one rule: the custom domain must route through the spine to a realm. A public host that reaches a runtime without traversing the gates is a hole, not a feature — total mediation applies to every host, named or not.


ᛚ Point DNS at the edge

CNAME the custom domain to the edge endpoint. The edge (Alfheim) terminates TLS and serves cacheable reads close to clients; dynamic requests continue through the spine.

app.acme.com.   CNAME   edge.norngate.com.

Why the edge: terminating and caching at Alfheim keeps latency low for clients far from the core, while every request that changes state still flows to a realm and its gates.


ᛖ Terminate TLS at the gateway

Issue the certificate with cert-manager (ACME), or bring your own as a Secret.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata: { name: acme-app-cert, namespace: asgard }
spec:
  secretName: acme-app-tls
  dnsNames: ["app.acme.com"]
  issuerRef: { name: letsencrypt, kind: ClusterIssuer }

Terminate and redirect at the Istio Gateway — TLS 1.3 minimum, HTTP forced to HTTPS.

apiVersion: networking.istio.io/v1
kind: Gateway
metadata: { name: acme-gateway, namespace: asgard }
spec:
  selector: { istio: ingressgateway }
  servers:
    - port: { number: 443, name: https, protocol: HTTPS }
      hosts: ["app.acme.com"]
      tls: { mode: SIMPLE, credentialName: acme-app-tls, minProtocolVersion: TLSV1_3 }
    - port: { number: 80, name: http, protocol: HTTP }
      hosts: ["app.acme.com"]
      tls: { httpsRedirect: true }

Route the host to the realm's runtime.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata: { name: acme-route, namespace: midgard }
spec:
  hosts: ["app.acme.com"]
  gateways: ["asgard/acme-gateway"]
  http:
    - route:
        - destination: { host: midgard-runtime.midgard.svc.cluster.local }

Why cert-manager: it automates issuance and renewal, so short-lived certs rotate without a human — the failure mode of custom domains is almost always an expired cert nobody renewed. Why TLS 1.3 + redirect: the minimum version defeats downgrade attacks and the redirect closes the plaintext door on port 80.


ᚦ Keep it gated

The custom host traverses G0–G4 exactly like an internal one. External clients authenticate at G0 with an OIDC token or API key (admitted through Vanaheim) — the public certificate proves the server's identity to the client and says nothing about the client's authorization.

Why this is the whole point: the common mistake is treating "it is HTTPS behind our domain" as security. TLS gets you an encrypted channel, not a permitted action — authorization is still G1, approval still G2. The gates are the control; the certificate is just the envelope.


ᛒ Verify

The domain is not done when the padlock appears — it is done when the padlock appears and the request is gated.

  • Certificate — valid chain, matches the host, not expired; confirm cert-manager auto-renews ahead of expiry.
    openssl s_client -connect app.acme.com:443 -servername app.acme.com </dev/null 2>/dev/null | openssl x509 -noout -dates
    
  • Posture — TLS 1.3 negotiated; HTTP→HTTPS redirect works.
  • Gated (the critical check) — a request to the custom domain must produce gate records:
    norngate-cli audit query --realm midgard --from now-5m
    
    If a request to app.acme.com produced no gate records, it bypassed the spine — stop and fix the routing before going live.

Why the gated check is non-negotiable: a green padlock on an ungated path is a false sense of security — encrypted, and completely unmediated. Encryption without mediation is the exact failure this platform exists to prevent.


ᚱ Next steps


Iconography

Section glyphs are Elder Futhark runes (Unicode Runic block, U+16A0–U+16FF) — semantic, not emoji. Full set on Home:

Rune Name Gloss Marks
Nauðiz need, constraint the platform mark
Ansuz the word, instruction before you start
Laguz water, the flow point DNS at the edge
Ehwaz the horse, conveyance terminate TLS at the gateway
Thurisaz thorn, the gates keep it gated
Berkanan growth, the change verified verify
Raidō the ride, the road next steps

References. RFC 8555 (ACME) via cert-manager; RFC 8446 (TLS 1.3); RFC 6797 (HSTS); Istio Gateway / VirtualService (per The Spine); SPIFFE (internal mTLS, distinct from edge TLS). Naming doctrine: Prose Edda / Poetic Edda, per Norse Cosmology & Platform Design.

ᚾ NornGate — Custom Domains & TLS

Map a public domain to a realm and terminate TLS at the edge. The one thing to get right first: a custom domain adds a public name and certificate, terminating at the edge — it does not change identity inside the mesh, and a valid certificate is transport, not authorization. The domain still routes through the spine and traverses G0–G4 like any other host.

Hostnames are illustrative; Realm field names are the derived config model; the Istio and cert-manager resources are real APIs.


ᚨ Before you start

Two TLS layers exist — do not conflate them:

  • External TLS — client ↔ edge, a public-CA certificate (ACME / Let's Encrypt) for the custom domain. This is what a browser validates.
  • Internal mTLS — workload ↔ workload inside the mesh, SPIFFE SVIDs, trust domain norngate.com. The custom domain never touches this.

And one rule: the custom domain must route through the spine to a realm. A public host that reaches a runtime without traversing the gates is a hole, not a feature — total mediation applies to every host, named or not.


ᛚ Point DNS at the edge

CNAME the custom domain to the edge endpoint. The edge (Alfheim) terminates TLS and serves cacheable reads close to clients; dynamic requests continue through the spine.

app.acme.com.   CNAME   edge.norngate.com.

Why the edge: terminating and caching at Alfheim keeps latency low for clients far from the core, while every request that changes state still flows to a realm and its gates.


ᛖ Terminate TLS at the gateway

Issue the certificate with cert-manager (ACME), or bring your own as a Secret.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata: { name: acme-app-cert, namespace: asgard }
spec:
  secretName: acme-app-tls
  dnsNames: ["app.acme.com"]
  issuerRef: { name: letsencrypt, kind: ClusterIssuer }

Terminate and redirect at the Istio Gateway — TLS 1.3 minimum, HTTP forced to HTTPS.

apiVersion: networking.istio.io/v1
kind: Gateway
metadata: { name: acme-gateway, namespace: asgard }
spec:
  selector: { istio: ingressgateway }
  servers:
    - port: { number: 443, name: https, protocol: HTTPS }
      hosts: ["app.acme.com"]
      tls: { mode: SIMPLE, credentialName: acme-app-tls, minProtocolVersion: TLSV1_3 }
    - port: { number: 80, name: http, protocol: HTTP }
      hosts: ["app.acme.com"]
      tls: { httpsRedirect: true }

Route the host to the realm's runtime.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata: { name: acme-route, namespace: midgard }
spec:
  hosts: ["app.acme.com"]
  gateways: ["asgard/acme-gateway"]
  http:
    - route:
        - destination: { host: midgard-runtime.midgard.svc.cluster.local }

Why cert-manager: it automates issuance and renewal, so short-lived certs rotate without a human — the failure mode of custom domains is almost always an expired cert nobody renewed. Why TLS 1.3 + redirect: the minimum version defeats downgrade attacks and the redirect closes the plaintext door on port 80.


ᚦ Keep it gated

The custom host traverses G0–G4 exactly like an internal one. External clients authenticate at G0 with an OIDC token or API key (admitted through Vanaheim) — the public certificate proves the server's identity to the client and says nothing about the client's authorization.

Why this is the whole point: the common mistake is treating "it is HTTPS behind our domain" as security. TLS gets you an encrypted channel, not a permitted action — authorization is still G1, approval still G2. The gates are the control; the certificate is just the envelope.


ᛒ Verify

The domain is not done when the padlock appears — it is done when the padlock appears and the request is gated.

  • Certificate — valid chain, matches the host, not expired; confirm cert-manager auto-renews ahead of expiry.
    openssl s_client -connect app.acme.com:443 -servername app.acme.com </dev/null 2>/dev/null | openssl x509 -noout -dates
  • Posture — TLS 1.3 negotiated; HTTP→HTTPS redirect works.
  • Gated (the critical check) — a request to the custom domain must produce gate records:
    norngate-cli audit query --realm midgard --from now-5m
    If a request to app.acme.com produced no gate records, it bypassed the spine — stop and fix the routing before going live.

Why the gated check is non-negotiable: a green padlock on an ungated path is a false sense of security — encrypted, and completely unmediated. Encryption without mediation is the exact failure this platform exists to prevent.


ᚱ Next steps


Iconography

Section glyphs are Elder Futhark runes (Unicode Runic block, U+16A0–U+16FF) — semantic, not emoji. Full set on [Home](Home#iconography):

Rune Name Gloss Marks
Nauðiz need, constraint the platform mark
Ansuz the word, instruction before you start
Laguz water, the flow point DNS at the edge
Ehwaz the horse, conveyance terminate TLS at the gateway
Thurisaz thorn, the gates keep it gated
Berkanan growth, the change verified verify
Raidō the ride, the road next steps

References. [RFC 8555](https://www.rfc-editor.org/rfc/rfc8555) (ACME) via [cert-manager](https://cert-manager.io/); [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446) (TLS 1.3); [RFC 6797](https://www.rfc-editor.org/rfc/rfc6797) (HSTS); Istio Gateway / VirtualService (per [The Spine](The-Spine)); [SPIFFE](https://spiffe.io/) (internal mTLS, distinct from edge TLS). Naming doctrine: Prose Edda / Poetic Edda, per [Norse Cosmology & Platform Design](Norse-Cosmology-and-Platform-Design).

Clone this wiki locally