Files
bluejay-infra/apps/fc-distribution/README.md
2026-04-23 17:03:22 -05:00

4.3 KiB

fc-distribution — staged deployment (Phase 1, USB provisioning)

Status: manifests staged, NOT YET APPLIED. Image must be built + imported and signing 1Password items confirmed before git push.

FlowerCore.Distribution publishes signed edition manifests (ECDSA P-256 over canonical JSON) and serves the SHA-256 content-addressed blob store that USB builders pull from. The verifier embeds the IAmWorkin ACME CA Root CA as the trust anchor; per-edition leaf signing material lives in 1Password and is mounted into the pod read-only.

Deployment order (do NOT skip / reorder)

1. FlowerCore.DNS preflight — VERIFIED 2026-04-23

dist.iamworkin.lan already resolves to 10.0.56.200, but keep the FlowerCore.DNS preflight green before push:

curl -sk "https://dns.iamworkin.lan/api/v1/zones/iamworkin.lan/resolve-preflight?hostname=dist.iamworkin.lan"
# Expect: "resolvable": true

python bluejay-infra/scripts/check-pfsense-dns.py
# Historical filename retained; implementation now calls FlowerCore.DNS
# resolve-preflight instead of raw resolver lookups.

If the record ever disappears, recreate it through FlowerCore.DNS before push/apply:

curl -sk https://dns.iamworkin.lan/api/v1/servers
curl -sk -X POST https://dns.iamworkin.lan/api/v1/servers/<serverId>/zones/iamworkin.lan/records \
  -H "Content-Type: application/json" \
  -d '{"name":"dist","type":"A","data":"10.0.56.200","ttl":300}'

If this is missing, cert-manager HTTP-01 will silently back off ~2h. See memory feedback_pfsense_dns_required_for_acme.md.

2. 1Password items required in vault IAmWorkin

Item title Item id Used as
FlowerCore Code Signing CA (existing) Informational handle only — root CA is baked into the image at build time, not mounted
FlowerCore Edition Signing Key - edition:kiosk-standard 3hf33egdvnni6jyuws3r737mqe Mounted at /signing/kiosk-standard/
FlowerCore Edition Signing Key - edition:aistation-field ccxrtsan5samfq4pfuczymacrq Mounted at /signing/aistation-field/

Each edition item must publish three field labels (the operator turns field labels into Secret keys verbatim):

  • certificate.pem — leaf certificate
  • private-key.pem — ECDSA P-256 private key
  • chain.pem — leaf + intermediate (referenced by the env var as the cert-path; the verifier uses this for signature path validation)

3. Build + import the image to rke2-server

The Pod is pinned to rke2-server because the Synology NFS export /volume1/kubernetes only allows that node. Importing to the agents is optional until the ACL is widened.

# From BLUEJAY-WS, in D:\git\FlowerCore\FlowerCore.Distribution
TAG="v$(date +%Y%m%d%H%M)"
dotnet.exe publish -c Release -o deploy/app \
  src/FlowerCore.Distribution.Web/FlowerCore.Distribution.Web.csproj
podman build -t localhost/fc-distribution:$TAG -f deploy/Dockerfile.deploy deploy
podman save localhost/fc-distribution:$TAG -o /tmp/fc-distribution.tar
scp /tmp/fc-distribution.tar rke2-server:/tmp/
ssh rke2-server "sudo /var/lib/rancher/rke2/bin/ctr -a /run/k3s/containerd/containerd.sock -n k8s.io images import /tmp/fc-distribution.tar"

4. Bump the image tag + push

Edit fc-distribution.yaml, replace localhost/fc-distribution:v202604231530 with the tag from step 3, then:

cd D:/git/FlowerCore/bluejay-infra
python scripts/check-pfsense-dns.py
git add apps/fc-distribution/
git commit -m "feat(fc-distribution): deploy Phase 1 manifest publisher"
git push

ArgoCD picks up within ~3 minutes and creates infra-fc-distribution.

5. Verify

fcadmin_ssh noc1 '
  kubectl -n argocd get application infra-fc-distribution
  kubectl -n fc-distribution get certificate,pod,secret
  curl -sk -m 8 -o /dev/null -w "HTTP %{http_code}\n" https://dist.iamworkin.lan/healthz
'

Expect: Certificate Ready: True within ~60s, /healthz HTTP 200, both edition-kiosk-standard and edition-aistation-field Secrets present with certificate.pem, private-key.pem, chain.pem keys.