feat: CoreOS-compatible login hardening and core operator key provisioning - #80
feat: CoreOS-compatible login hardening and core operator key provisioning#80castrojo wants to merge 11 commits into
Conversation
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove build-time sed mutation of /layer/etc/shadow from bluefin-server-ddi.bst and verify systemd-sysusers root user declaration in test_core_login_contract.py. Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reflect implemented SSH public-key provisioning via tmpfiles.extra and retain static network configuration as the remaining credential gap. Assisted-by: Claude Sonnet 5 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Deleting os-sshd-preset.bst orphaned the whole files/os/systemd/system-preset directory, dropping the networkd, k0s first-boot, and var-mount presets from the OS DDI. Reintroduce packaging through a clearly named os-systemd-presets.bst import element and guard it with an anti-orphan packaging assertion over files/os. BuildStream strips setuid bits from artifacts, so the key-only core operator could not elevate through wheel. Restore mode 4755 on /usr/bin/sudo in the DDI and assert the contract at source level. Scope the roadmap's open credential item to static network configuration; core SSH keys already arrive via tmpfiles.extra. Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In commit c752c48, the kiosk proxy was updated to generate self-signed TLS certificates on the fly and serve over HTTPS. Update the install-vm recipe to probe https://127.0.0.1:8080/ (with --insecure) with fallback to HTTP, and output HTTPS access URLs. Assisted-by: Gemini 3.8 Flash via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
e639d51 to
863a6ec
Compare
hanthor
left a comment
There was a problem hiding this comment.
Mostly good hardening, but it turns SSH on by default without saying so
The core of this — key-only core operator, PermitRootLogin no, PasswordAuthentication no, persistent host keys in /var/lib/ssh, NOPASSWD wheel — is a coherent CoreOS-shaped design and the new test_core_login_contract.py is a genuinely good contract suite. test_no_os_payload_file_is_orphaned_from_the_os_stack in particular is the kind of guard this repo benefits from.
Three things need addressing before merge.
1. SSH flips from disabled-by-default to enabled-by-default, undisclosed
The PR deletes the preset that kept sshd off:
$ git diff main...pr80 -- files/os/systemd/system-preset/zz-enable-sshd.preset
-# SSH is present in the image for on-demand diagnostics, but off by default.
-disable sshd.service
-disable sshd.socket
os-sshd-preset.bst is renamed to os-systemd-presets.bst with the same source path and target, so the element survives — but the only file in it that mentioned sshd is gone, leaving zz-enable-networkd, zz-enable-k0s-first-boot, zz-enable-var-mount. With no explicit disable, sshd falls through to the default preset policy and comes up enabled.
This is not accidental — your own test asserts it:
assert "multi-user.target.wants/sshd.service" in ddi
assert not SSHD_PRESET.exists()So the behaviour is deliberate and tested. The problem is that the PR body does not mention it. The closest it gets is:
Package systemd presets in OS DDI to ensure networkd and k0s first-boot services run reliably.
A remote-access daemon changing from off to on is the single most consequential line in this diff, and it is described as a networkd packaging change. Please state it explicitly in the body, and ideally record the rationale in docs/ next to the deleted file's comment, which said the opposite.
For the record, the fail-closed gate you built is real and I'm not disputing the design — bluefin-core-access.service runs test -s /var/home/core/.ssh/authorized_keys and the sshd drop-in has Requires=+After= on it, so sshd genuinely refuses to start without a provisioned key. That mitigation is what makes this defensible. It just needs to be stated.
2. The drop-in clears sshd's config validation
[Service]
ExecStartPre=
ExecStartPre=/usr/bin/test -s /var/lib/ssh/ssh_host_ed25519_key
ExecStartPre=/usr/bin/test -s /var/lib/ssh/ssh_host_rsa_keyThe bare ExecStartPre= resets the list, which drops whatever the FSDK unit had — on most openssh-systemd builds that includes sshd -t, the config syntax check. Losing it means a malformed drop-in in sshd_config.d/ now fails at daemon start with a less useful error instead of being caught by the pre-check. Since the reason for the reset is presumably to drop upstream's host-key generation (now owned by bluefin-ssh-host-keys.service), consider re-adding /usr/sbin/sshd -t as a fourth ExecStartPre= rather than dropping it wholesale.
3. The verification numbers in the body don't match reality
pytest tests/unit(166 passed, 1 xfailed)
That is below what main alone produces. Measured just now:
main @ 7f376fa: 201 passed, 1 xfailed in 0.59s
main + pr80 (local merge): 210 passed, 1 xfailed in 0.83s
166 corresponds to neither. The suite does pass on this branch — that part is fine — but the number is stale enough to be misleading about what was actually run. Please re-run and update, since the same body is the only record of what was verified.
Also worth a look
--insecurein the health probe.curl --silent --insecure ... https://127.0.0.1:8080/ininstall-vmaccepts any certificate. Acceptable for a loopback dev probe, but note it presumes the kiosk already serves HTTPS — which is what #91 is implementing. If #91 doesn't land first, thehttps://branch just fails and falls through to thehttp://fallback, so the probe still works; the printed "Access URL" lines andxdg-openare unconditionallyhttps://though, and will be wrong until then.- Blast radius.
files/os/sysusers.d/,files/os/sudoers.d/andfiles/os/systemd/system-preset/are the kind ofsystem_files/-style payload that sibling Bluefin images tend to share. A%wheel ALL=(ALL) NOPASSWD: ALLpolicy and an enabled-by-default sshd are both worth checking against the other images before this pattern spreads.
Status
mergeable_state from the API is dirty, but that appears stale — merging this head into the recorded base succeeds with no conflicts:
$ git checkout -B testmerge 7f376fa && git merge --no-gpg-sign --no-edit pr80
CLEAN # git diff --name-only --diff-filter=U -> (empty)
CI is green on 863a6ec (build, unit, docs all success). The local gates on the merged tree are green too: 210 passed, 1 xfailed, 41/41 bats, all three .github/scripts checkers exit 0, against a fully-green main baseline — so nothing here is pre-existing breakage.
Blocking on item 1 primarily; items 2 and 3 are quick.
Generated by Claude Code
|
Addressed review feedback:
|
Summary
Implements CoreOS-compatible login hardening and key-only access for the
coreoperator account, locking the shared root account and wiring persistent SSH keys and systemd presets.Changes
sshdis enabled in the image for thecoreoperator account. To prevent unauthorized or headless exposure,sshd.serviceis strictly gated bybluefin-core-access.service(Requires=+After=), which executestest -s /var/home/core/.ssh/authorized_keys.sshdwill fail-closed and refuse to start unless an authorized SSH key has been provisioned viatmpfiles.extra. Root login and password authentication are completely disabled (PermitRootLogin no,PasswordAuthentication no).coreoperator user with passwordless wheel sudo privileges./var/lib/sshgenerated once viabluefin-ssh-host-keys.service.os-systemd-presets.bst) to ensure networkd, persistent/varmount, and k0s first-boot services run reliably.10-bluefin-access.confpreserving/usr/sbin/sshd -tconfig validation alongside persistent host key checks.tests/unit/test_core_login_contract.pyandtest_vm_dashboard_contract.py.install-vmhealth probe in Justfile to test HTTPS.Verification
pytest tests/unit(210 passed, 1 xfailed in 0.52s)bats tests/unit(41 passed, 0 failed)python3 .github/scripts/docs-checks.py(Passed)