Can NixOS Set Keyboard for Grub/LUKS Password?

I’ve used DVORAK keyboard my entire career and have successfully set up NixOS 23.05 to use DVORAK keyboard via following lines in my configuration.nix :

services.xserver.xkbVariant = "dvorak’;
console.keyMap = “dvorak”;

So far, so good.

However I’ve also set up my NixOS 23.05 to use LUKS disk encryption which prompts me for my LUKS decryption password during boot via Grub and only responds/decrypts when I enter the password via QWERTY keyboard layout.

I’ve searched all manner of NixOS options for keymap, keyboard, LUKS, Grub, etc. but haven’t located any option that would permit me to override QWERTY and use DVORAK layout for my LUKS password.

1 Like

Just a hunch, try with earlySetup option

console = {
    earlySetup = true;
    keyMap = "dvorak";
  };

earlySetup configures the console in NixOS stage 1 (initrd): it may be in time for inserting the passphrase for boot.initrd.luks.devices, but I’m not 100% sure.
For grub, I don’t think there is such an option, but it should be possible to add one.

Thanks for the suggestion.

I tried this but unfortunately no luck.

It appears console options only apply to those consoles that are available to NixOS after it has booted.

As the LUKS password prompt precedes availability of any NixOS console it must somehow be activated/configured via LUKS or GRUB.

I’ve found the following links that may provide clues.

It looks like alternative/custom keyboards can be compiled and linked to GRUB but it seems rather complicated. Still this approach might be the way to go.

This solution looks more straightforward and promising but not sure how I’d use Nix to implement it.

Also found the following work around hack if all else fails:

LUKS/DVORAK Hack

Hah, I had this idea half-formed in my head as a possible suggestion. I like it (FSVO like).

A more general answer is to reconsider your boot and encryption layout, and what your current setup actually protects against. I’m assuming you don’t currently have secure boot enabled; it’s close and works but still needs some polish. Once you do, you have integrity validation of your bootloader, kernel, and initrd. This content likely has little confidentiality requirement, but what you need is to be sure you trust it to enter secrets that enable decryption of the content that does. So maybe you don’t need LUKS until after the kernel is started.

I tryied to simplement this a while ago Add an option to set GRUB keyboard layout · Issue #41247 · NixOS/nixpkgs · GitHub.

My conclusion at the time was that it probably is technically possible but the required options were not exposed in the high level grub commands nixos builds upon. And even then not every grub input module supported custom layout (only at_keyboard did). I don’t know if the situation changed since then.

In the end I used the dual passphrase hack you mentionned.

I think that I have solved just the same problem. The solution seems to be this:

boot.initrd.systemd.enable = true;
console.earlySetup = true;
console.keyMap = “YOUR_KEYMAP”;

Then you can change your LUKS password following this post: How to change LUKS disk encryption passphrase in Linux. You may have to do it twice if you enabled a swap partition, because Nixos’ installation process seems to do it by default.

It seems that the reason why the first boot config line is needed is because the boot is done in two stages, and the first one does not activate console configuration options (systemd is responsible of this, I suppose). This is also useful when configuring Plymouth for a graphical boot (in this case you will have to disable text messages also, with boot.kernelParams = [ “quiet” “udev.log_level=3” ]; ).

It does still occur with 24.05
Solutions mentioned above didn’t work or didn’t fit to me, as willing to declare as much as possible in configs

Following did the trick on my side, removing console.keymap and use console.useXdbConfig instead:

{
  ...
  # `services.xserver.xkb` is needed for `24.05`, instead of e.g `services.xserver.xdbVariant`
  services.xserver.xkb = {
    layout = "us";
    variant = "alt-intl"; # or else
  };

  # `keymap` won't apply when prompted to enter the passphrase to decrypt on boot
  console = {
    earlySetup = true;
    useXkbConfig = true;
  };