Installing a fresh Krill server via the documented one-liner
(curl -fsSL …/install_krill.sh | sudo bash) failed at the cluster-PIN step.
First it looked like the prompt rejected every PIN in a tight loop and then aborted the install:
1
2
3
4
Enter a 4-digit PIN for this Krill cluster: ❌ PIN must be exactly 4 digits (0-9). Try again.
…
dpkg: error processing package krill (--configure):
old krill package postinst maintainer script subprocess failed with exit status 1
After a first fix it changed to a different failure: the prompt accepted the PIN,
but pressing Enter never returned — the install “succeeded” (the krill service
was running) yet apt hung forever and never gave the terminal back.
The PIN was being collected inside the deb’s postinst maintainer script.
read -r KRILL_PIN read from stdin, which under
curl … | sudo bash is the installer pipe, not the terminal — so it consumed
leftover script bytes, failed validation each time, hit EOF, and set -e
aborted configure. (Only fresh installs were affected; postinst skips the
prompt when /etc/krill/credentials/pin_hash already exists, which is why
previously-installed hosts — including the Ghost runner — never hit it.)/dev/tty removed the abort but exposed the real
problem: a dpkg maintainer script must not read the terminal. During
apt/dpkg configure, postinst shares the controlling terminal with dpkg’s
own machinery and the needrestart hook (visible in the process tree as
/usr/lib/needrestart/dpkg-status alongside the running …/krill.postinst).
The /dev/tty read could never reliably get the typed line, so postinst slept
forever on the read while dpkg waited on postinst — the server started, but the
apt invocation hung. A pseudo-terminal repro that lacked the competing
dpkg/needrestart processes did not reproduce it, which masked the cause at
first.Make postinst strictly non-interactive and move the interactive prompt into the
installer, run at the end where it cleanly owns the terminal:
distro/server/install_krill.sh drops a /run/krill-install-managed flag
before apt runs, then — after apt finishes and has released the
terminal — prompts for the PIN by invoking krill-reset-pin < /dev/tty (reusing
the shipped tool so the PinDerivation HMAC lives in one place). If there is no
terminal (fully unattended run) it prints a loud “ACTION REQUIRED” banner.server/package/DEBIAN/postinst no longer touches any terminal. It applies an
optional preseed PIN from /run/krill-install-pin (for unattended installs),
then removes it. When no PIN is configured it prints a gentle “PIN will be set
at the end of the installer” note if the managed flag is present, or the loud
“ACTION REQUIRED: run sudo krill-reset-pin” banner for a standalone
apt-get install krill. The HMAC derivation (krill-api-pbkdf2-v1) is
unchanged, so the PinDerivation wire contract is preserved./dev/tty or stdin. dpkg/apt/needrestart own the terminal during
configure; any read there can hang the whole install. Collect input in the
installer wrapper that owns the terminal before apt is invoked, or use debconf,
and hand the value to the package out-of-band. The exception is a
directly-invoked CLI like krill-reset-pin, which owns its own stdin.PostinstPinPromptTest (server jvmTest) statically asserts postinst contains
no /dev/tty and no read, behaviourally runs the seed/messaging block under
setsid (preseed applied; unmanaged→loud banner; managed→quiet note; never
blocks), and asserts install_krill.sh runs krill-reset-pin < /dev/tty at the
end and shares the /run/krill-install-managed flag postinst honours — so the
two halves can’t drift.