foundation/documentation/sessions/SESSION_2026-06-30_001.md

50 lines
3.8 KiB
Markdown
Raw Permalink Normal View History

# Session 2026-06-30 #001 — Foundation bootstrap: contracts → live VM + DNS + offsite backup
## What was done
- **T00** contracts CONTRACT_001004 (+ amendment for `hosts.git`, `vm.sshPort`, `cloudflare.zoneId`).
- **T01** `preflight/` + `VERSIONS` (images carry `:PIN_DIGEST` placeholders — see gotchas).
- **T02** Bun-workspace + typed `config.ts` + vendored `@olsitec/pulumi-{docker,vault}`.
- **ADR-006 precursor**: shared Docker-over-SSH provider + `foundation-net` (`lib/context.ts`,
`components/network.ts`, phase-slotted `index.ts`). Composition = per-component factories, gates via `dependsOn`.
- **Phase-0 VM**: vendored `@olsitec/pulumi-hetzner`; `provision/` stack. Live: **cx33 Helsinki,
`204.168.234.72`**, Docker 29.6.1, **SSH port 222**, key `~/.ssh/foundation-test_ed25519`, firewall 222/80/443/2222.
- **Offsite backup**: `offsite-backup/` stack — bucket **`olsitec-foundation`** + scoped service account
on `minio.wob.olsitec.de:19000` (home Synology). Verified scoped (cross-bucket denied).
- **Steps 1+2**: real `olsitec.net` config + **DNS** `forge/vault/s3/git.olsitec.net → 204.168.234.72`
(verified authoritative; explicit A shadows the `*.olsitec.net` wildcard). `foundation-net` live on VM.
## Current state
- Repo: `~/work/olsitec-foundation/foundation`. Latest commit `185be52`. Working tree clean.
- **Master passphrase** (the one external secret): `pass olsitec-foundation/PULUMI_CONFIG_PASSPHRASE`.
- Deploy the foundation: `cd bootstrap && ./run.sh up` (sets passphrase + `SSH_PRIVATE_KEY_PATH`).
- Stacks (all local file backends): `bootstrap` stack **foundation** (real passphrase); `provision`
stack **foundation-test** + `offsite-backup` stack **prod** (throwaway passphrase `dev-validation-throwaway`).
- Other creds: `pass olsicloud4/{HCLOUD_TOKEN,CLOUDFLARE_MASTER_TOKEN}`; MinIO admin via the
`wob-admin-external` mc alias (accessKey `admin`, NOT `pass MINIO_BACKUP_*` which is a different instance).
## Next steps (Wave 2 → the goal: `git clone git@git.olsitec.net`)
Validate each live on the VM via `bootstrap/run.sh up` (images still unpinned → `FOUNDATION_ALLOW_UNPINNED=1`
or pin digests per `VERSIONS` header). Each component is a factory `components/<svc>.ts`, wired into the
`index.ts` phase slots (ADR-006).
1. **T03 postgres** · **T04 rustfs** (+ buckets) — data plane.
2. **T05 vault** — sealed container + init-capture (reuse `olsitec-core/run.sh` pattern → unseal keys to
`vaultCredentials:*` encrypted config) + passphrase-gated unseal helper (ADR-004). The hard one.
3. **T06 credentials**`@pulumi/random` → Vault (CONTRACT_002 paths).
4. **T07 Caddy** — DNS-01 TLS; needs a **Cloudflare-enabled Caddy image** (build via xcaddy; standard
`caddy:2` lacks the DNS plugin). Token already in `foundation:cloudflareApiToken`.
5. **T08 Forgejo** — app.ini ← Postgres/RustFS/Vault; first admin headless; **org + repo** so
`git clone git@git.olsitec.net:olsitec/...` works (forgeSshPort 2222, published).
6. **T10 runner** · **T12 backup** (RustFS → replicate to the offsite `olsitec-foundation` bucket;
scoped creds already in `foundation:backup.offsite*`).
## Risks / watchouts
- `Pulumi.foundation.yaml` self-quotes scalars + `encryptionsalt` is now **load-bearing** (decrypts 3
committed secrets) — keep it committed; don't strip the salt anymore.
- VM SSH is **port 222**; the eventual real VM would be 22 (`vm.sshPort` handles it).
- `VERSIONS` images are `:PIN_DIGEST` + RustFS is `latest` — pin before treating as production.
- Don't run `pulumi up` against the production `olsicloud4-*` stacks. The home MinIO `.local` name is
LAN-only; the VM must use the public `minio.wob.olsitec.de:19000`.
- Everything is destroyable: `provision` (VM), `offsite-backup` (bucket+creds) via `pulumi destroy`.
## Operating mode for next session: HIGH-RISK / INFRA (remote VM, Docker, secrets).