deploy/cloudflare-v2/README.md
On this page

Cloudflare HTTPS front door for relay v2

The public URL is https://relay.sparrowsystems.co. It is deployed using npx wrangler: a small Worker with a managed custom domain forwards through a VPC Service binding to the existing Cloudflare tunnel and parent loopback port 8080. The Worker disables caching and logging; clients still authenticate the inner enclave TLS connection with Nitro. The enclave was not restarted.

Current Worker source/configuration and public deployment evidence record successful public transport and fresh attestation while warming. The SDK source now sets an application user agent to avoid an observed edge rejection of generic Python urllib. This fix is not yet in the published 0.2.0a2 wheel.

The direct-tunnel DNS/cache-rule instructions below are the preserved alternative plan. They are not required for the deployed Worker custom domain; do not add the old proposed CNAME over its managed DNS entry. Existing unrelated services remain separate, and no inbound parent application port was opened.

The HTTP query carries the existing inner TLS byte stream. The Python client still verifies the enclave's attestation, PCRs, policy and TLS key before sending an upstream request. Cloudflare provides outer HTTPS and transport routing; it is not the attestation trust anchor. It can observe request timing, sizes, session identifiers and public artifacts. The application protocol has no origin-password query parameter.

Reviewable deployment plan

prepare.py makes no network calls and accepts no credentials. It prints API paths/bodies for review, including an exact-host cache bypass rule. Use the actual account and sparrowsystems.co zone IDs from the authenticated account:

python3 deploy/cloudflare-v2/prepare.py --account-id ACCOUNT_ID --zone-id ZONE_ID

Once the existing Cloudflare login is restored, check the account, exact-name DNS records, tunnel name, Worker routes, redirects, cache rules, and Access/WAF settings. A Wrangler login alone may not grant Tunnel/DNS/cache-rule write permissions. Use an already authorized dashboard/API session with the needed permissions; do not copy the account credential onto the EC2 parent.

  1. Create the new, remotely managed tunnel named attested-relay-v2, using the plan's create_tunnel body or npx wrangler tunnel create attested-relay-v2. If that name already exists, inspect it before reuse. Record its UUID.
  2. Rerun prepare.py with --tunnel-id TUNNEL_UUID. Apply its configure_tunnel body only to the inspected dedicated tunnel. The config permits /relay, the two indexes, and content-addressed artifacts, followed by a catch-all 404. Do not change the origin to another parent port.
  3. Add the exact-host cache bypass rule to the existing cache ruleset, after any matching rule that enables caching. Do not replace the zone ruleset. This conservatively bypasses caching for artifacts too. Preserve all query parameters and their values. Do not apply redirects, query transformations, browser challenges, or an interactive Access login to this machine API.
  4. Retrieve this tunnel's connector token privately from the dashboard or the plan's token API endpoint. A connector token can run this tunnel; keep it separate from account API/OAuth credentials. Do not put it in command arguments, shell history, logs, tracked files, or a URL.
  5. Install and start the dedicated connector on the new parent as below. Verify that the tunnel is healthy. Only then create the proxied CNAME from create_dns_after_preflight, after a complete exact-name DNS listing proves there is no conflicting record. An identical record is an idempotent no-op. A conflicting record must be investigated, never overwritten by this plan.
  6. Run the public smoke test and an actual attested client request with the independently recorded production PCR0. The transport smoke alone does not prove enclave readiness or attestation validity.

The named tunnel must have connectors for one parent host instance. The GET sessions are held in that host's memory. Adding a connector backed by a different host would distribute one session across unrelated stores and break sequencing. Multiple cloudflared connections to the same host are fine. Host restart loses sessions; clients must establish a new verified inner TLS connection.

Parent connector

Use a verified Linux ARM64 cloudflared release, version 2025.4.0 or later, installed at /usr/local/bin/cloudflared. Pin the version and verify its release checksum before installation. The version minimum is needed for --token-file. Do not use cloudflared service install: the dedicated unit below avoids replacing a pre-existing connector service.

Prepare root-owned /etc/attested-relay/cloudflare-v2 with mode 0700. Transfer the connector token through the existing authenticated SSH channel into a private file outside the repository, then stage it using stdin on the parent:

sudo python3 /opt/attested-relay/cloudflare-v2/stage-token.py \
  /etc/attested-relay/cloudflare-v2/token < /PRIVATE/PATH/connector-token

Staging creates a mode-0600 file and syncs it and its directory. It refuses an existing destination and never deletes files. For rotation, stage a new private filename, update LoadCredential in this dedicated unit, then restart it. Keep existing credential files protected; this workflow does not remove them.

Copy attested-relay-cloudflared.service to the same basename in /etc/systemd/system/, after confirming it is a new unit, and use:

sudo systemctl daemon-reload
sudo systemctl enable --now attested-relay-cloudflared.service
sudo systemctl is-active attested-relay-cloudflared.service

Systemd passes the connector token as a runtime credential file to an unprivileged dynamic user. Metrics bind only to 127.0.0.1:20246. Connector stdout/stderr are discarded because even error diagnostics can contain request URLs. Use systemd process health, loopback metrics, Cloudflare tunnel connection status, and the smoke checks for monitoring. Do not enable debug/access logging or export full query strings to Logpush or request traces for this hostname. Account-level Cloudflare log retention remains an operator-controlled setting.

The parent needs outbound DNS and Cloudflare Tunnel connectivity (QUIC/UDP or HTTP2/TCP port 7844); no inbound 8080/8444/7844 rule is required. The existing Graviton5 host unit already binds HTTP 8080 and raw TLS 8444 to loopback. This connector unit adds no listener for the raw TLS port.

To withdraw the new route without deleting files or changing legacy service, stop and disable only attested-relay-cloudflared.service. The new hostname will fail closed while the legacy hostname continues on its existing route.

Validation

Local checks create isolated temporary files and one optional isolated Rust host process. Files are retained; no existing service is interrupted:

python3 -m unittest discover -s deploy/cloudflare-v2/tests -v

After deployment:

python3 deploy/cloudflare-v2/smoke.py

The smoke script verifies outer HTTPS, fresh artifact discovery, no-store/cache headers, an identical empty-packet retry, and the following acknowledged packet. It sends no upstream request and never opens an inner enclave connection. Its empty host session expires normally. It prints neither query strings nor response bodies. --base-url http://127.0.0.1:8080 is available for parent-local checks; unencrypted remote URLs and embedded credentials are rejected.

Cloudflare's API reports the installed tunnel healthy with four connections. Parent-local and public transport smoke passed. Fresh Nitro verification through the public hostname passed with the client source user-agent fix. Application readiness remains warming. Deployment evidence and exact DNS record.

Official references

Selected public hostname

The public hostname selected on 2026-09-10 is relay.sparrowsystems.co. The current measured 92bd475 enclave retains its original certificate DNS name. The client authenticates the inner TLS key through its independently pinned Nitro attestation, rather than the self-signed certificate's DNS name; the outer HTTPS connection still uses ordinary hostname/certificate verification. Changing this outer route therefore does not require replacing the enclave or discarding production warm-up. Validate the fresh Nitro/TLS binding through the new public hostname as part of deployment.