1{ lib, pkgs, ... }: 2let 3 inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey; 4in 5{ 6 name = "ssh-agent-auth"; 7 meta.maintainers = with lib.maintainers; [ nicoo ]; 8 9 nodes = 10 let 11 nodeConfig = 12 n: 13 { ... }: 14 { 15 users.users = { 16 admin = { 17 isNormalUser = true; 18 extraGroups = [ "wheel" ]; 19 openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; 20 }; 21 foo.isNormalUser = true; 22 }; 23 24 security.pam.sshAgentAuth = { 25 # Must be specified, as nixpkgs CI expects everything to eval without warning 26 authorizedKeysFiles = [ "/etc/ssh/authorized_keys.d/%u" ]; 27 enable = true; 28 }; 29 security.${lib.replaceStrings [ "_" ] [ "-" ] n} = { 30 enable = true; 31 wheelNeedsPassword = true; # We are checking `pam_ssh_agent_auth(8)` works for a sudoer 32 }; 33 34 # Necessary for pam_ssh_agent_auth >_>' 35 services.openssh.enable = true; 36 }; 37 in 38 lib.genAttrs [ "sudo" "sudo_rs" ] nodeConfig; 39 40 testScript = 41 let 42 privateKeyPath = "/home/admin/.ssh/id_ecdsa"; 43 userScript = pkgs.writeShellScript "test-script" '' 44 set -e 45 ssh-add -q ${privateKeyPath} 46 47 # faketty needed to ensure `sudo` doesn't write to the controlling PTY, 48 # which would break the test-driver's line-oriented protocol. 49 ${lib.getExe pkgs.faketty} sudo -u foo -- id -un 50 ''; 51 in 52 '' 53 for vm in (sudo, sudo_rs): 54 sudo_impl = vm.name.replace("_", "-") 55 with subtest(f"wheel user can auth with ssh-agent for {sudo_impl}"): 56 vm.copy_from_host("${snakeOilPrivateKey}", "${privateKeyPath}") 57 vm.succeed("chmod -R 0700 /home/admin") 58 vm.succeed("chown -R admin:users /home/admin") 59 60 # Run `userScript` in an environment with an SSH-agent available 61 assert vm.succeed("sudo -u admin -- ssh-agent ${userScript} 2>&1").strip() == "foo" 62 ''; 63}