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}