Address PR review: PXE gate + callback, git-sync templates, distro catalog, k8s targets, http+https
Implements the six review comments on PR #1: - Per-host PXE-enable gate: read NetBox pxe_enabled custom field; a known host with it false gets the safe local-boot script (Cobbler netboot_enabled). Add a token-guarded POST /provisioned/{ident} callback that clears pxe_enabled in NetBox, plus a %post snippet in the default kickstarts that calls it. - Templates from a git repo: bootapi clones a templates repo and re-pulls every BOOTAPI_TEMPLATE_GIT_INTERVAL (default 3m), atomically swapping the template set (last-good kept on parse failure; embedded defaults are the startup fallback). Metrics for syncs/failures/generation. - Distro catalog (catalog/*.yaml): NetBox host -> boot images/kickstart, so adding an OS is a YAML + template change. Ships almalinux + fedora entries (artifactapi remotes); debian/talos path documented. - Boot images from the artifactapi almalinux/fedora remotes via the catalog. - Bind resolvers, puppet server/CA and PUPPETCA_URL env file now target the k8s services (198.18.200.7; puppet(ca).k8s.syd1.au.unkin.net). - Boot path served over plain HTTP (installers lack CA trust) with an optional parallel HTTPS listener; docs say do not 301 the boot endpoints. New packages: internal/catalog, internal/gitsync. NetBox client gains a pxe_enabled write (token needs that scope - noted in docs). `bootapi validate` subcommand validates a template/catalog set for the templates-repo CI. go build/vet clean, go test -race green, golangci-lint v2 clean, pre-commit clean. Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
This commit is contained in:
+47
-19
@@ -22,38 +22,66 @@ Create `apps/base/bootapi/` following the argocd-apps `AGENTS.md` pattern:
|
||||
`default`, SA `default` (copy netbox's `vaultauth.yaml`).
|
||||
3. **VaultStaticSecret** → k8s Secret `bootapi-secrets`, from Vault kv path
|
||||
`kubernetes/namespace/bootapi/default/bootapi-secrets` with keys:
|
||||
- `netbox_token` — a **dedicated, read-only** NetBox API token for bootapi
|
||||
(create a `bootapi` NetBox user/token via terraform-netbox rather than
|
||||
reusing the seeded superuser token at
|
||||
`kv/kubernetes/namespace/netbox/default/netbox-superuser`).
|
||||
- `netbox_token` — a **dedicated** NetBox API token for bootapi. It needs
|
||||
**read on devices/interfaces/ip-addresses AND write on the device
|
||||
`pxe_enabled` custom field** (the provisioned callback PATCHes it — see
|
||||
[security.md](security.md#netbox-write-scope)). Create a `bootapi` NetBox
|
||||
user/token via terraform-netbox rather than reusing the seeded superuser
|
||||
token at `kv/kubernetes/namespace/netbox/default/netbox-superuser`.
|
||||
- `provision_token` — the shared bearer token guarding `POST /provisioned`
|
||||
(also embedded in rendered kickstarts). Generate a random value.
|
||||
- `root_password_hash` — crypt(3) hash for the installed root account
|
||||
(the successor to Cobbler's eyaml `default_password_crypted`).
|
||||
- `ssh_authorized_keys` — optional, newline-separated.
|
||||
4. **ConfigMap** `bootapi-templates` (optional) — override `*.ks.tmpl` /
|
||||
`*.ipxe.tmpl`, mounted at `BOOTAPI_TEMPLATE_DIR=/etc/bootapi/templates`. Omit
|
||||
to use the embedded defaults. Annotate the Deployment with
|
||||
`reloader.stakater.com/auto: "true"` so template edits roll the pods.
|
||||
4. **Templates**: prefer git-sync — set `BOOTAPI_TEMPLATE_GIT_URL` to
|
||||
`https://git.unkin.net/unkin/bootapi-templates.git` (public; no token needed)
|
||||
and bootapi pulls it every `BOOTAPI_TEMPLATE_GIT_INTERVAL` (default 3m). No
|
||||
ConfigMap or pod restart is needed to change templates — merge to the repo's
|
||||
`main` and bootapi reloads within the interval (last-good kept on a bad push).
|
||||
The embedded defaults remain the fallback if the repo is unreachable. (A
|
||||
`BOOTAPI_TEMPLATE_DIR` ConfigMap is still supported for air-gapped installs.)
|
||||
5. **Deployment** — image above, env from `config.example.env`, secret keys wired
|
||||
as `BOOTAPI_NETBOX_TOKEN_FILE`/`BOOTAPI_ROOT_PASSWORD_HASH_FILE` (mount the
|
||||
Secret) or `...FROM secretKeyRef`. Least-privilege securityContext
|
||||
(`runAsNonRoot`, `drop: [all]`). Baseline resources: requests `512Mi`/`1`,
|
||||
limits `2Gi`/`2` cpu.
|
||||
6. **Service** `bootapi` (ClusterIP, port 80 → 8000) plus a **LoadBalancer** (or
|
||||
Gateway HTTPRoute) reachable by PXE clients at a stable address/hostname —
|
||||
this is what DHCP points at. Reuse the Vault-issued TLS the Cobbler vhost used
|
||||
if you terminate TLS at a gateway; note that iPXE fetches are plain HTTP, so a
|
||||
plain HTTP listener on the PXE VLAN is required either way.
|
||||
as `BOOTAPI_NETBOX_TOKEN_FILE` / `BOOTAPI_PROVISION_TOKEN_FILE` /
|
||||
`BOOTAPI_ROOT_PASSWORD_HASH_FILE` (mount the Secret). Least-privilege
|
||||
securityContext (`runAsNonRoot`, `drop: [all]`). Baseline resources: requests
|
||||
`512Mi`/`1`, limits `2Gi`/`2` cpu. The pod needs `git` on PATH for template
|
||||
sync (the distroless image includes only the static binary — either add a git
|
||||
layer, use an initContainer that seeds the checkout, or fall back to a
|
||||
ConfigMap; simplest is a small alpine+git base for this service).
|
||||
6. **Service + exposure**: see the Gateway section below.
|
||||
7. Register in `argocd/applicationsets/platform.yaml` (`apps/overlays/*/bootapi`)
|
||||
and the platform AppProject destinations.
|
||||
|
||||
### Gateway: HTTP and HTTPS
|
||||
|
||||
PXE installers do **not** trust the internal CA, so the boot path must be served
|
||||
over **plain HTTP**. Unlike the estate default, the bootapi HTTPRoute must **not
|
||||
blanket-301 HTTP→HTTPS**:
|
||||
|
||||
- A **plain-HTTP** listener/HTTPRoute (or a LoadBalancer Service on port 80→8000)
|
||||
reachable by PXE clients at a stable address/hostname on the PXE VLAN — this is
|
||||
the `BOOTAPI_BASE_URL` DHCP/iPXE points at. No redirect.
|
||||
- Optionally an **HTTPS** HTTPRoute for humans/tooling that do trust the CA
|
||||
(bootapi can serve TLS directly via `BOOTAPI_TLS_*`, or terminate at the
|
||||
gateway). This is additive; it must not replace or redirect the HTTP boot path.
|
||||
|
||||
The end-of-kickstart callback (`POST /provisioned`) runs over the same plain-HTTP
|
||||
base by default (the token authenticates it; the install has no CA trust yet). If
|
||||
you install the internal CA early in `%post`, you may set
|
||||
`BOOTAPI_CALLBACK_BASE_URL` to the HTTPS URL instead.
|
||||
|
||||
### Cross-repo dependencies (per estate conventions)
|
||||
|
||||
- **terraform-git**: `unkin/bootapi-templates` repo (this PR's sibling) holds the
|
||||
live template set + distro catalog + validation CI.
|
||||
- **argocd-apps**: add a `serviceaccount_*` under `apps/base/woodpecker/` if the
|
||||
bootapi pipelines need a dedicated SA (they use `default` today).
|
||||
- **terraform-vault**: add the k8s auth role + kv policy granting the `bootapi`
|
||||
namespace read on `kv/kubernetes/namespace/bootapi/default/*`.
|
||||
- **terraform-netbox**: create the read-only `bootapi` NetBox token and seed it
|
||||
(plus `root_password_hash`) into the Vault kv path above.
|
||||
- **terraform-netbox**: create the `bootapi` NetBox token (read + write on the
|
||||
`pxe_enabled` device custom field) and seed it, `provision_token` and
|
||||
`root_password_hash` into the Vault kv path above. Also define the `pxe_enabled`
|
||||
boolean custom field on the Device model.
|
||||
|
||||
## DHCP change (the cutover)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user