carlos / platform Public

docs: the release pubkey belongs to the fleet env contract; module doc fixes

- fleet_byo.html: add CARLOS_RELEASE_PUBKEY to the primary (no-bucket) env
  block, with a note that release pointers are Ed25519-signed and the box
  refuses to adopt anything without it.
- infra/eleven-fleet.md: add CARLOS_RELEASE_PUBKEY to the Step-3 env block,
  with an explicit warning that the value must be Carloku's release
  pubkey, not tito's — carrying the old file's value forward silently
  ships the wrong key and adoption fails signature verification.
- infra/modules/region-remote-host/main.tf: fix a comment that attributed
  aws_iam_role_policy.host_route53 to this module; it lives in
  region-host.
- infra/modules/README.md: correct the region-remote-host description —
  the data bucket grant is always present, the deployment bucket grant is
  only present when deployment_bucket_arn is set (fleet-API consumers
  omit it).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 14b926376496c22cac8dc6e0c819b8b64fe801d4 parent c012216
4 files changed, +21 −9
  • infra/eleven-fleet.md +7 −2
  • infra/modules/README.md +9 −5
  • infra/modules/region-remote-host/main.tf +2 −2
  • internal/console/templates/fleet_byo.html +3 −0
diff --git a/infra/eleven-fleet.md b/infra/eleven-fleet.md
index 0495eaba8..e6dc9a414 100644
--- a/infra/eleven-fleet.md
+++ b/infra/eleven-fleet.md
@@ -87,12 +87,17 @@ contract — no `CARLOS_DEPLOYMENT_BUCKET`, no platform-bucket half of
CARLOS_FLEET_BOX=<box-1-label>
CARLOS_REGION=fleet/eleven
CARLOS_STATUS_PREFIX=fleets/eleven/
+ CARLOS_RELEASE_PUBKEY=<Carloku's release public key>
CARLOS_TUNNEL_URL=https://<Carloku's reserved tunnel hostname>
CARLOS_TUNNEL_NAME=eleven/<box-1-label>
CARLOS_TUNNEL_TOKEN=<from Step 2 — shown once>
-`CARLOS_FLEET_BOX` defaults from `CARLOS_TUNNEL_NAME`'s label half, but
-write it explicitly. `/etc/carlos/credentials` now holds ONLY the
+`CARLOS_RELEASE_PUBKEY` must be **Carloku's** release public key, not
+tito's — carrying the old `host.env`'s value forward silently ships the
+wrong key, and adoption then fails signature verification (the box will
+not adopt any release, with no other symptom). `CARLOS_FLEET_BOX` defaults
+from `CARLOS_TUNNEL_NAME`'s label half, but write it explicitly.
+`/etc/carlos/credentials` now holds ONLY the
hibernate-bucket key from the Eleven-owned tofu root — any platform-bucket
key pair the file carried for tito's own console is removed here, not just
unused. Restart the agent unit to pick up the new env.
diff --git a/infra/modules/README.md b/infra/modules/README.md
index 5687b9b81..857b58d23 100644
--- a/infra/modules/README.md
+++ b/infra/modules/README.md
@@ -82,11 +82,15 @@ wants one.
What an off-cloud CARLOS host (customer fleets and tito's hq)
needs from AWS when there is no EC2 instance profile to lean on: a region
-data bucket plus a scoped IAM user + access key, limited to exactly the
-deployment bucket and this region's data bucket — the same
-wrong-region-fails-at-IAM residency property `region-host` gives cloud
-hosts. Consumed by customer fleets (paulca/pi-fleet is the live example) and
-the platform's tito hq; the module is reusable as-is for both.
+data bucket plus a scoped IAM user + access key, limited to this region's
+data bucket always, plus the deployment bucket only when
+`deployment_bucket_arn` is set — the same wrong-region-fails-at-IAM
+residency property `region-host` gives cloud hosts. Fleet-API consumers
+(issue #73) omit `deployment_bucket_arn` entirely: the box reaches the
+platform's deployment bucket over the console's edge with its tunnel
+token, not a direct IAM grant. Consumed by customer fleets (paulca/pi-fleet
+is the live example) and the platform's tito hq; the module is reusable
+as-is for both.
| Variable | Description |
|---|---|
diff --git a/infra/modules/region-remote-host/main.tf b/infra/modules/region-remote-host/main.tf
index 64da92b08..ce7d0ecf5 100644
--- a/infra/modules/region-remote-host/main.tf
+++ b/infra/modules/region-remote-host/main.tf
@@ -96,8 +96,8 @@ resource "aws_iam_user_policy" "host" {
# bucket through the console's edge, over the same tunnel token it dials
# with, so var.deployment_bucket_arn is left "" and this whole statement
# (and the IAM policy resource carrying it) is omitted. count, not a dynamic
-# block, matches this module's own aws_iam_role_policy.host_route53 pattern
-# for an optional statement.
+# block, matches the same optional-statement pattern used by
+# aws_iam_role_policy.host_route53 in the region-host module.
resource "aws_iam_user_policy" "host_deployment_bucket" {
count = var.deployment_bucket_arn != "" ? 1 : 0
name = "carlos-remote-host-${var.region_code}-deployment-bucket"
diff --git a/internal/console/templates/fleet_byo.html b/internal/console/templates/fleet_byo.html
index b034e5230..ddd0339e1 100644
--- a/internal/console/templates/fleet_byo.html
+++ b/internal/console/templates/fleet_byo.html
@@ -31,9 +31,12 @@ CARLOS_HIBERNATE_BUCKET=&lt;your-bucket&gt;
CARLOS_FLEET=&lt;name&gt;
CARLOS_FLEET_BOX=&lt;label&gt;
CARLOS_REGION=fleet/&lt;name&gt;
+CARLOS_RELEASE_PUBKEY=&lt;this deployment's release public key&gt;
CARLOS_TUNNEL_URL=&lt;this deployment's tunnel address&gt;
CARLOS_TUNNEL_TOKEN=&lt;from carlos fleets add-box &lt;name&gt; &lt;label&gt; — shown once&gt;
CARLOS_TUNNEL_NAME=&lt;name&gt;/&lt;label&gt;</code></pre>
+<p class="small">Release pointers are Ed25519-signed; without <code>CARLOS_RELEASE_PUBKEY</code> the
+box has no key to verify against and refuses to adopt anything.</p>
<p class="small"><code>CARLOS_FLEET_BOX</code> is optional and defaults from
<code>CARLOS_TUNNEL_NAME</code>'s label half. <code>AWS_SHARED_CREDENTIALS_FILE</code> points at
an access key for the bucket above — <strong>your own bucket only</strong> — written root-owned