Integrate with yubikey
This commit is contained in:
@@ -15,5 +15,6 @@
|
||||
./gitlab
|
||||
./jenkins
|
||||
./gaming
|
||||
./yubikey
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.dov.yubikey;
|
||||
in {
|
||||
options.dov.yubikey = {
|
||||
enable = mkEnableOption "YubiKey integration (PAM U2F + SSH agent)";
|
||||
|
||||
pamControl = mkOption {
|
||||
type = types.enum [ "sufficient" "required" ];
|
||||
default = "sufficient";
|
||||
description = ''
|
||||
PAM control flag for U2F authentication.
|
||||
- "sufficient": touch YubiKey OR type password (default).
|
||||
Can't lock yourself out — if the key is missing or not
|
||||
enrolled, the normal password prompt follows.
|
||||
- "required": touch YubiKey AND type password (true 2FA).
|
||||
'';
|
||||
};
|
||||
|
||||
pamServices = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "login" "sudo" ];
|
||||
description = ''
|
||||
PAM services to enable U2F for. Scoped per-service rather
|
||||
than globally so that e.g. sshd is not affected.
|
||||
'';
|
||||
};
|
||||
|
||||
authFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Central U2F authfile path. When null, uses the default
|
||||
per-user location (~/.config/Yubico/u2f_keys). Set to a
|
||||
nix-store path for a central, non-user-writable mapping.
|
||||
|
||||
Generate mappings with:
|
||||
pamu2fcfg -u <username>
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
# --- Shared infrastructure: smart card daemon + device access ---
|
||||
# hardware.gpgSmartcards installs the CCID udev rules that give
|
||||
# pcscd permission to open the YubiKey's smart-card USB interface.
|
||||
hardware.gpgSmartcards.enable = true;
|
||||
services.pcscd.enable = true;
|
||||
services.udev.packages = with pkgs; [
|
||||
yubikey-personalization
|
||||
libfido2
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
yubikey-manager # `ykman` CLI
|
||||
pam_u2f # `pamu2fcfg` for key enrollment
|
||||
libfido2 # `fido2-token` management
|
||||
];
|
||||
}
|
||||
|
||||
# --- PAM U2F: touch YubiKey for login / sudo ---
|
||||
{
|
||||
security.pam.u2f = {
|
||||
enable = true;
|
||||
control = cfg.pamControl;
|
||||
settings = {
|
||||
cue = true; # "Please touch the device."
|
||||
interactive = true; # "Insert your U2F device, then press ENTER."
|
||||
nouserok = true; # fall through to password if key not enrolled yet
|
||||
} // optionalAttrs (cfg.authFile != null) {
|
||||
inherit (cfg) authFile;
|
||||
};
|
||||
};
|
||||
|
||||
# Enable U2F per-service, not globally (avoids enabling for sshd).
|
||||
security.pam.services = genAttrs cfg.pamServices (_: {
|
||||
u2fAuth = true;
|
||||
});
|
||||
}
|
||||
|
||||
# --- SSH agent for FIDO2 (-sk) keys ---
|
||||
# yubikey-agent is incompatible with YubiKey firmware 5.7.x (PIV
|
||||
# management key auth changed). GPG agent's SSH emulation doesn't
|
||||
# reliably handle -sk keys. Use the standard OpenSSH agent instead,
|
||||
# which is the same software stack that created the key.
|
||||
{
|
||||
programs.gnupg.agent.enableSSHSupport = mkForce false;
|
||||
programs.ssh.startAgent = true;
|
||||
}
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user