Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ docstring gives: it is a record, not a claim about now.

## 2026-11-09

- **[#421](https://github.com/Gerrrt/HomeLab/issues/421),
[#790](https://github.com/Gerrrt/HomeLab/issues/790): `gandalf` is ready
for `tpl-kali`'s build, `build-the-lab-templates.md` §5 step 2's `gandalf`
half.** `phoenix@pve` exists on `gandalf` with `PhoenixBuilder` on `/vms`,
`/storage/range`, `/storage/local` and `vmbr0`, and `PVEAuditor` on
`/nodes/gandalf`. Nothing is granted on `local-lvm` or `vmbr1`.
`PhoenixIsoCleanup` was granted on `local` and revoked the same day, from
review: Kali's build uploads no answer disc, so `Datastore.Allocate` there
bought nothing. The role omits `Saruman`'s `Pool.*`, which serve
OpenTofu there. The API certificate was already the node's own and names
`10.0.30.30`, so nothing was reissued. The Kali 2026.2 installer is on
`gandalf`'s `local`, checked against the hash in
`scripts/collect-iso-store-state.sh`, and `kali_iso_file` now defaults to
it. No token was made: it is made at the build so its secret goes straight
to `phoenix`. The build, the smoke test and the `-force` rebuild are
still #790's, from `phoenix`.

- **[#421](https://github.com/Gerrrt/HomeLab/issues/421): `gandalf`'s
management plane is closed, `build-the-playground.md` §4.** The firewall
had been off since the install, so ADR-0014's rules did not exist yet and
Expand Down
5 changes: 4 additions & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ Gated on the domain, on a household observation, or on something to publish.
`gandalf`.** Gated on #414 and the SOC: an attack VM pointed at an
uninstrumented estate teaches nothing. Both are met. The runbook's §1–§4
are behind it: the host, its bridges, `Saruman` at `.20` and the closed
management plane. Next is §5, the attack VM, then §6–§9, in order.
management plane. Next is §5, the attack VM, which clones `tpl-kali`:
[#790](https://github.com/Gerrrt/HomeLab/issues/790)'s build from
`phoenix`, whose `gandalf` half (user, grants, ISO) is done. Then §6–§9,
in order.
The name is
[ADR-0106](adr/0106-name-the-range-host-gandalf-and-leave-ifrit-to-its-disabled-amt.md)'s.
→ [runbook](runbooks/build-the-playground.md)
Expand Down
71 changes: 63 additions & 8 deletions docs/runbooks/build-the-lab-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,19 +492,74 @@ not from a second disc.
`ufw` is active, run `sudo ufw allow from 10.0.30.0/24 to any port 8800 proto tcp`,
and delete the rule afterwards. Debian's build (§4) needs this step and
no other here.
2. Grant `PhoenixBuilder` on `gandalf`'s storage and bridge, and trust
`gandalf`'s CA on `phoenix`, as §2 did for `Saruman`. Unless `gandalf` joins
`Saruman` in a cluster, it is its own API. Point `PROXMOX_URL` at it for
this build, and admit `phoenix` to its 8006 the way ADR-0043 did on
`Saruman`.
3. Build, naming the ISO actually on `gandalf` and **its** storage.
2. Give `phoenix` a user on `gandalf`, and trust `gandalf`'s CA on
`phoenix`, as §2 did for `Saruman`. Unless `gandalf` joins `Saruman` in a
cluster, it is its own API with its own users, so `phoenix@pve` there is a
second user with the same name, not the same one. `phoenix`'s 8006 rule is
already in `gandalf`'s `host.fw`
([`build-the-playground.md`](build-the-playground.md) §4).

**The `gandalf` half ran 2026-11-09**
([#421](https://github.com/Gerrrt/HomeLab/issues/421)). The certificate
was already the node's own: issuer `PVE Cluster Manager CA`, names
including `10.0.30.30`, and no custom `pveproxy-ssl.pem`. The roles are
[`build-the-jumpbox.md`](build-the-jumpbox.md) §4's list plus §2's
`VM.GuestAgent.Audit`. `Pool.Allocate` and `Pool.Audit` are left out,
because they are for OpenTofu's pools on `Saruman` and nothing on `gandalf`
is provisioned that way. The grants are narrower than `Saruman`'s:

| Role | Path | Why |
| --- | --- | --- |
| `PhoenixBuilder` | `/vms` | creating and templating 902 |
| `PhoenixBuilder` | `/storage/range` | the template's disks, on the range pool ([ADR-0096](../adr/0096-fit-ifrits-range-disk-as-a-sata-ssd-in-the-tinys-bay.md)) |
| `PhoenixBuilder` | `/storage/local` | the installer ISO |
| `PhoenixBuilder` | `/sdn/zones/localnetwork/vmbr0` | the build NIC |
| `PVEAuditor` | `/nodes/gandalf` | read-only. Lower case, as `pvesh get /nodes` prints it |

Nothing is granted on `local-lvm`, because the range's disks stay off the
M.2. Nothing is granted on `vmbr1` either: the range NIC belongs to the
clone ([`build-the-playground.md`](build-the-playground.md) §5), and a
token that can attach guests to the range bridge is a token that can put
one there. Nor is `PhoenixIsoCleanup`: Kali's build serves its preseed
over HTTP and uploads no answer disc, so there is nothing to delete, and
`Datastore.Allocate` would also delete any volume on `local` and edit its
configuration. It was granted on 2026-11-09 and revoked the same day, from
review. `pveum acl list | grep phoenix` is the check.

**The token is made at the build, by the person at the terminal**, so
its secret goes straight to `phoenix` and is never in a transcript. On
`gandalf`:

```bash
pveum user token add phoenix@pve builder --privsep 0
```

On `phoenix`, keep it in a file of its own,
`~/.config/proxmox/gandalf.env` (mode 0600), with `PROXMOX_URL`,
`PROXMOX_TOKEN_ID` and `PROXMOX_TOKEN_SECRET` pointing at
`https://10.0.30.30:8006/api2/json`. For this build, source
`phoenix.env` first and `gandalf.env` after it. `phoenix.env` exports
`PKR_VAR_build_password`, which every build validates (§3), even Kali's.
`gandalf.env` then overrides the three API variables. Rewriting
`phoenix.env` instead would point the next `Saruman` build at `gandalf`.

```bash
set -a; . ~/.config/proxmox/phoenix.env; . ~/.config/proxmox/gandalf.env; set +a
```

Then trust `gandalf`'s CA: relay
`/etc/pve/pve-root-ca.pem` as §2 does, under the name
`gandalf-pve-root-ca.crt`, and prove it with the same `curl`, without
`-k`.
3. Build, naming **`gandalf`'s** storage. The ISO is the 2026.2 installer
on `gandalf`'s `local`, put there 2026-11-09 and checked against the hash
in `scripts/collect-iso-store-state.sh`. It is `kali_iso_file`'s default.
`disk_storage` defaults to `large_data`, which is `Saruman`'s pool, and
the disk creation fails without the override:

```bash
packer build -only='kali.proxmox-iso.kali' \
-var kali_iso_file=local:iso/<the iso> \
-var disk_storage=<gandalf's guest storage> \
-var disk_storage=range \
packer/
```

Expand Down
10 changes: 5 additions & 5 deletions packer/variables.pkr.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ variable "arch_iso_file" {
default = "smaug-iso:iso/archlinux-2026.10.01-x86_64.iso"
}

# A placeholder name: Kali is written and not yet built (ADR-0074 part 2), and
# the first build on gandalf sets this to the ISO it actually has. It stays on
# local: the ISO store's export and pass admit Saruman alone (ADR-0072), so
# gandalf cannot mount it.
# The 2026.2 installer on gandalf's own local storage, the same file and hash
# as kali_saruman_iso_file's (scripts/collect-iso-store-state.sh). It sits on
# local because the ISO store's export and pass admit Saruman alone
# (ADR-0072), so gandalf cannot mount it.
variable "kali_iso_file" {
type = string
default = "local:iso/kali-linux-installer-amd64.iso"
default = "local:iso/kali-linux-2026.2-installer-amd64.iso"
}

# 910's ISO, for garuda (#921). Saruman mounts smaug-iso, so this one sits
Expand Down
Loading