GRUB keeps the firmware's text console; phone-home back to HTTP
Lab, Secure Boot VM: the deployed Debian booted under Secure Boot through the chainload, but its console was garbled after the network GRUB had switched the display mode; GRUB menus now use the firmware's text console (terminal_output console), which also suits serial/SOL. phone-home over HTTPS failed once on that first boot (TLS: bad record MAC on the region's side; the same request works from the machine since), and cloud-init spends its 10 tries within milliseconds. Its content is not secret and its token only works from the machine's address, so it goes over HTTP again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c494c7b226
commit
b2ad0210bf
3 files changed
+15
-7
No files matched your search
+6
-2
@@ -91,8 +91,12 @@ region and `deploy/install-rack.sh` on rack hosts (new dnsmasq layout, signed ra
|
||||
the agents' endpoints and images on 443. Agents accept the CA by the fingerprint on the PXE
|
||||
command line and do not fall back to HTTP. Old agents keep working over HTTP. The commissioning
|
||||
image has to be rebuilt to get the new agents.
|
||||
- The stateless overlay client works the same way (rebuild stateless images), and a deployed OS
|
||||
calls home over HTTPS.
|
||||
- The stateless overlay client works the same way (rebuild stateless images).
|
||||
- **UEFI and Secure Boot.** UEFI machines PXE-boot through Debian's signed shim and GRUB, so machines
|
||||
with Secure Boot on can boot at all; before, the firmware refused the unsigned `syslinux.efi`.
|
||||
- GRUB menus are made from the pxelinux ones.
|
||||
- The local disk is booted by chainloading the installed OS's signed loader.
|
||||
- Secure Boot verifies the kernel; the initrd and squashfs are not covered.
|
||||
- **BMC certificates.** HTTPS BMCs (Redfish, Proxmox) are pinned on first use. The certificate
|
||||
is read in a handshake that carries no credentials, and a changed certificate gets none
|
||||
(`tls_fingerprint`; cleared on an address change or a BMC firmware update by Rollcall).
|
||||
|
||||
@@ -297,11 +297,10 @@ func (a *App) renderSeed(j *Job, sp DeploySpec, token string) []seedFile {
|
||||
if len(sp.Packages) > 0 {
|
||||
fmt.Fprintf(&b, "packages: %s\n", yamlList(sp.Packages))
|
||||
}
|
||||
home := base
|
||||
if t := a.agentTLS(base); t != "" && a.ca != nil {
|
||||
home = t // the deployed OS trusts the Rollcall CA (bootcmd below), so it calls home over HTTPS
|
||||
}
|
||||
fmt.Fprintf(&b, "phone_home:\n url: %s/api/v1/phone-home/%s\n post: [instance_id, hostname, fqdn, pub_key_ed25519]\n tries: 10\n", home, token)
|
||||
// plain HTTP on purpose: nothing in it is secret (the token only works from this
|
||||
// machine's address), and cloud-init spends its 10 tries within milliseconds, so a
|
||||
// TLS hiccup on first boot (seen once on Debian: bad record MAC) loses "booted"
|
||||
fmt.Fprintf(&b, "phone_home:\n url: %s/api/v1/phone-home/%s\n post: [instance_id, hostname, fqdn, pub_key_ed25519]\n tries: 10\n", base, token)
|
||||
b.WriteString("final_message: \"rollcall: deployed, up after $UPTIME s\"\n") // only $UPTIME/$TIMESTAMP/$DATASOURCE/$VERSION are expanded
|
||||
ud = b.String()
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
)
|
||||
|
||||
const grubDispatch = `# generated by rollcall: the machine's own menu, else the one for unknown machines
|
||||
terminal_output console
|
||||
set timeout=8
|
||||
configfile $prefix/grub.cfg-$net_default_mac
|
||||
configfile $prefix/grub.cfg-default
|
||||
@@ -90,6 +91,10 @@ func pxelinuxToGrub(body string) string {
|
||||
}
|
||||
var b strings.Builder
|
||||
b.WriteString("# generated by rollcall from the pxelinux menu\n")
|
||||
// the firmware's text console: GRUB does not switch the display mode, so the OS
|
||||
// it starts gets the firmware's own (OVMF showed a garbled console after a switch),
|
||||
// and serial/SOL consoles see the menu
|
||||
b.WriteString("terminal_output console\n")
|
||||
fmt.Fprintf(&b, "set default=%d\nset timeout=%d\n", def, timeout)
|
||||
for _, e := range entries {
|
||||
fmt.Fprintf(&b, "menuentry %s {\n", grubQuote(e.label))
|
||||
|
||||
Reference in new issue
Block a user