Files
zeekay 4c6439ecd8 the host is encrypted at rest without asking for a TPM
A TPM bought two things and cost a machine requirement. What is actually needed
is that the disk is ciphertext, that no provider API key is a way in, and that no
credential is ever plaintext — and none of those needs a TPM.

  at rest   LUKS2 on the root, all of it: the credential files, systemd's own
            host key, the journal. A disk that leaves the rack says nothing.
  identity  systemd-creds --with-key=host instead of --with-key=tpm2. The key it
            binds to lives under /var/lib/systemd on that LUKS root, so the
            credential is ciphertext twice over and a disk read without the
            passphrase yields neither half. It still decrypts only into %d,
            memory-backed and readable by this unit alone, and still never
            appears in the environment.
  not a way in
            The box is not a resource of any cloud we hold an API key for, so
            there is no console to open, no root password to reset, no snapshot
            to take. That property was always the point; the TPM was never what
            provided it.

Two things are genuinely given up and both are stated where a reader will meet
them rather than left to be discovered:

  - The passphrase now exists, so a reboot is attended. A host that needs a
    human to come back is a host somebody keeps a passphrase for, and that is
    the trade.
  - Nothing measures the code. With no PCR policy the disk does not refuse to
    unlock for a changed binary or an attached debugger, so what protects the
    build is the appliance model — signed image, no shell, replaced rather than
    repaired — which rests on trusting whoever holds the machine.

The prose is corrected everywhere it claimed a key "never leaves the TPM",
because after this change that sentence is false in eight places and a comment
that is false is worse than one that is absent.
2026-08-22 11:37:35 -07:00

57 lines
2.8 KiB
Plaintext

# Install to /etc/egress/env, root:root 0400, on the LUKS root.
#
# This file is the whole configuration. There is no orchestrator to ask, which
# is the point: this process runs where a cloud API token does not reach.
# NO MNEMONIC HERE. The identity KMS authorizes is the innermost secret on this
# box — it derives the key that unlocks every provider credential — so it is
# encrypted to this host and loaded as a unit credential, never as an environment
# variable this file could carry:
#
# systemd-creds encrypt --with-key=host --name=mnemonic - /etc/egress/mnemonic.cred
#
# Everything below is configuration, not secret. This file holds no credential.
# Who may spend. A token must name this issuer and carry this audience.
# Audience has no default on purpose: a service accepting any audience accepts
# a token minted for a different app.
# The key set is published under the IAM prefix, not at the host root: the root
# spelling answers 404, and a JWKS is fetched on the first call rather than at
# boot — so the wrong URL here starts cleanly and then refuses every caller as
# unidentifiable, which reads like a token problem rather than a config one.
EGRESS_ISSUER=https://hanzo.id
EGRESS_JWKS=https://hanzo.id/v1/iam/.well-known/jwks
EGRESS_AUDIENCE=hanzo-egress
# Where the credentials live. KMSPath is this service's own identity path.
# HTTPS, because this process runs OFF the cluster and that is the whole design.
# The ZAP endpoint is a direct dial to a port the public edge does not carry —
# kms.hanzo.ai resolves to the CDN, which proxies 443 and nothing else — so a
# zap:// endpoint here is one that cannot be reached from where egress lives. Use
# zap:// only from inside the cluster, where the port is real.
EGRESS_KMS=https://kms.hanzo.ai
EGRESS_KMS_ORG=hanzo
EGRESS_KMS_PATH=hanzo/egress
# The http transport authenticates as a machine identity rather than by envelope
# signature, so these two go with an https endpoint and are ignored with zap://.
# The matching secret is sealed, never written here:
# systemd-creds encrypt --with-key=host --name=client-secret - /etc/egress/client-secret.cred
EGRESS_IAM=https://hanzo.id
EGRESS_CLIENT_ID=
# Inbound ZAP. Bind to the interface callers reach, never 0.0.0.0 on a host
# with a public address.
EGRESS_LISTEN=:9653
EGRESS_RPM=600
EGRESS_DEADLINE=5m
# OPTIONAL. Egress already knows where each cloud it can pay for answers —
# that is a fact about the cloud, not a choice this host makes — so nothing here
# is needed to serve DigitalOcean or Hetzner. Set an entry only to MOVE one: a
# regional or sovereign endpoint. It cannot admit a cloud egress cannot pay for,
# because an address is not what makes a cloud payable. https only, and a
# malformed entry refuses to start.
# EGRESS_URLS=digitalocean=https://api.digitalocean.com