deploy/MULLVAD-V2.md

Mullvad egress for v2

V2 requires one pre-provisioned Mullvad device whose ID is pinned in config/relay-v2.toml. The account number stays in /etc/attested-relay/mullvad-account, readable only by the host service user; it is never compiled into an enclave or included in published source.

Each enclave boot obtains fresh private-key material from NSM, authenticates to Mullvad over certificate-verified HTTPS and replaces that device's public key. Retries reuse the same key and check whether an earlier update already succeeded. V2 contains no account-device creation or deletion path. An operator provisions the device once; existing unrelated devices remain untouched. Simultaneous enclave boots using the same device can disrupt each other's connectivity.

WireGuard terminates inside the enclave. Client-selected upstream connections and their DoH lookups traverse the tunnel, including retries and redirects. Without a healthy handshake they fail closed. An accidental Direct mode cannot override the required-relay setting. Public bootstrap infrastructure (Mullvad's API, its DNS lookup and AWS hardware verification) may connect directly. The parent still sees the VPN peer and traffic sizes/timing; Mullvad and upstream resolvers can observe destination metadata. Upstream HTTPS still protects the request and response contents from Mullvad, subject to the existing WebPKI model.

The signed policy reports egress = mullvad-wireguard and mullvad_up. Readiness requires both a live epoch and a healthy tunnel. A handshake older than 180 seconds or a stopped tunnel is not healthy. Reconnection keeps the same account device. Development-only direct routing requires both --dev and RELAY_DEV_DIRECT=1; production cannot use that environment variable to disable the tunnel.

Host preparation: install the account file with owner tlproxy, mode 0400, before starting the updated graviton5-host-launch.sh. Preserve prior releases and artifacts. New source requires new EIF measurements and a new client PCR pin. An enclave replacement restarts in-memory RandomX generation.

Validation and live deployment evidence are recorded separately in measurements/; a configured device or an ordinary-host VPN test alone does not prove Nitro execution or production readiness.