3p/nixpkgs: add pr164025

This commit is contained in:
Luke Granger-Brown 2022-03-13 17:33:59 +00:00
parent b29a330382
commit edf6671aff
11 changed files with 710 additions and 1 deletions

View file

@ -1271,6 +1271,15 @@
been added by default. been added by default.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>security.pam.ussh</literal> has been added, which
allows authorizing PAM sessions based on SSH
<emphasis>certificates</emphasis> held within an SSH agent,
using
<link xlink:href="https://github.com/uber/pam-ussh">pam-ussh</link>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The <literal>zrepl</literal> package has been updated from The <literal>zrepl</literal> package has been updated from

View file

@ -466,6 +466,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.logrotate.enable` now defaults to true if any rotate path has - `services.logrotate.enable` now defaults to true if any rotate path has
been defined, and some paths have been added by default. been defined, and some paths have been added by default.
- `security.pam.ussh` has been added, which allows authorizing PAM sessions based on SSH _certificates_ held within an SSH agent, using [pam-ussh](https://github.com/uber/pam-ussh).
- The `zrepl` package has been updated from 0.4.0 to 0.5: - The `zrepl` package has been updated from 0.4.0 to 0.5:
- The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume. - The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume.

View file

@ -61,6 +61,19 @@ let
''; '';
}; };
usshAuth = mkOption {
default = false;
type = types.bool;
description = ''
If set, users with an SSH certificate containing an authorized principal
in their SSH agent are able to log in. Specific options are controlled
using the <option>security.pam.ussh</option> options.
Note that the <option>security.pam.ussh.enable</option> must also be
set for this option to take effect.
'';
};
yubicoAuth = mkOption { yubicoAuth = mkOption {
default = config.security.pam.yubico.enable; default = config.security.pam.yubico.enable;
defaultText = literalExpression "config.security.pam.yubico.enable"; defaultText = literalExpression "config.security.pam.yubico.enable";
@ -475,6 +488,9 @@ let
optionalString cfg.usbAuth '' optionalString cfg.usbAuth ''
auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
'' + '' +
(let ussh = config.security.pam.ussh; in optionalString (config.security.pam.ussh.enable && cfg.usshAuth) ''
auth ${ussh.control} ${pkgs.pam_ussh}/lib/security/pam_ussh.so ${optionalString (ussh.caFile != null) "ca_file=${ussh.caFile}"} ${optionalString (ussh.authorizedPrincipals != null) "authorized_principals=${ussh.authorizedPrincipals}"} ${optionalString (ussh.authorizedPrincipalsFile != null) "authorized_principals_file=${ussh.authorizedPrincipalsFile}"} ${optionalString (ussh.group != null) "group=${ussh.group}"}
'') +
(let oath = config.security.pam.oath; in optionalString cfg.oathAuth '' (let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits} auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
'') + '') +
@ -926,6 +942,96 @@ in
}; };
}; };
security.pam.ussh = {
enable = mkOption {
default = false;
type = types.bool;
description = ''
Enables Uber's USSH PAM (<literal>pam-ussh</literal>) module.
This is similar to <literal>pam-ssh-agent</literal>, except that
the presence of a CA-signed SSH key with a valid principal is checked
instead.
Note that this module must both be enabled using this option and on a
per-PAM-service level as well (using <literal>usshAuth</literal>).
More information can be found <link
xlink:href="https://github.com/uber/pam-ussh">here</link>.
'';
};
caFile = mkOption {
default = null;
type = with types; nullOr path;
description = ''
By default <literal>pam-ussh</literal> reads the trusted user CA keys
from <filename>/etc/ssh/trusted_user_ca</filename>.
This should be set the same as your <literal>TrustedUserCAKeys</literal>
option for sshd.
'';
};
authorizedPrincipals = mkOption {
default = null;
type = with types; nullOr commas;
description = ''
Comma-separated list of authorized principals to permit; if the user
presents a certificate with one of these principals, then they will be
authorized.
Note that <literal>pam-ussh</literal> also requires that the certificate
contain a principal matching the user's username. The principals from
this list are in addition to those principals.
Mutually exclusive with <literal>authorizedPrincipalsFile</literal>.
'';
};
authorizedPrincipalsFile = mkOption {
default = null;
type = with types; nullOr path;
description = ''
Path to a list of principals; if the user presents a certificate with
one of these principals, then they will be authorized.
Note that <literal>pam-ussh</literal> also requires that the certificate
contain a principal matching the user's username. The principals from
this file are in addition to those principals.
Mutually exclusive with <literal>authorizedPrincipals</literal>.
'';
};
group = mkOption {
default = null;
type = with types; nullOr str;
description = ''
If set, then the authenticating user must be a member of this group
to use this module.
'';
};
control = mkOption {
default = "sufficient";
type = types.enum [ "required" "requisite" "sufficient" "optional" ];
description = ''
This option sets pam "control".
If you want to have multi factor authentication, use "required".
If you want to use the SSH certificate instead of the regular password,
use "sufficient".
Read
<citerefentry>
<refentrytitle>pam.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
for better understanding of this option.
'';
};
};
security.pam.yubico = { security.pam.yubico = {
enable = mkOption { enable = mkOption {
default = false; default = false;
@ -1110,6 +1216,9 @@ in
optionalString (isEnabled (cfg: cfg.usbAuth)) '' optionalString (isEnabled (cfg: cfg.usbAuth)) ''
mr ${pkgs.pam_usb}/lib/security/pam_usb.so, mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
'' + '' +
optionalString (isEnabled (cfg: cfg.usshAuth)) ''
mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
'' +
optionalString (isEnabled (cfg: cfg.oathAuth)) '' optionalString (isEnabled (cfg: cfg.oathAuth)) ''
"mr ${pkgs.oathToolkit}/lib/security/pam_oath.so, "mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,
'' + '' +

View file

@ -245,7 +245,7 @@ in
environment.systemPackages = [ sudo ]; environment.systemPackages = [ sudo ];
security.pam.services.sudo = { sshAgentAuth = true; }; security.pam.services.sudo = { sshAgentAuth = true; usshAuth = true; };
environment.etc.sudoers = environment.etc.sudoers =
{ source = { source =

View file

@ -387,6 +387,7 @@ in
pam-file-contents = handleTest ./pam/pam-file-contents.nix {}; pam-file-contents = handleTest ./pam/pam-file-contents.nix {};
pam-oath-login = handleTest ./pam/pam-oath-login.nix {}; pam-oath-login = handleTest ./pam/pam-oath-login.nix {};
pam-u2f = handleTest ./pam/pam-u2f.nix {}; pam-u2f = handleTest ./pam/pam-u2f.nix {};
pam-ussh = handleTest ./pam/pam-ussh.nix {};
pantalaimon = handleTest ./matrix/pantalaimon.nix {}; pantalaimon = handleTest ./matrix/pantalaimon.nix {};
pantheon = handleTest ./pantheon.nix {}; pantheon = handleTest ./pantheon.nix {};
paperless-ng = handleTest ./paperless-ng.nix {}; paperless-ng = handleTest ./paperless-ng.nix {};

View file

@ -0,0 +1,70 @@
import ../make-test-python.nix ({ pkgs, lib, ... }:
let
testOnlySSHCredentials = pkgs.runCommand "pam-ussh-test-ca" {
nativeBuildInputs = [ pkgs.openssh ];
} ''
mkdir $out
ssh-keygen -t ed25519 -N "" -f $out/ca
ssh-keygen -t ed25519 -N "" -f $out/alice
ssh-keygen -s $out/ca -I "alice user key" -n "alice,root" -V 19700101:forever $out/alice.pub
ssh-keygen -t ed25519 -N "" -f $out/bob
ssh-keygen -s $out/ca -I "bob user key" -n "bob" -V 19700101:forever $out/bob.pub
'';
makeTestScript = user: pkgs.writeShellScript "pam-ussh-${user}-test-script" ''
set -euo pipefail
eval $(${pkgs.openssh}/bin/ssh-agent)
mkdir -p $HOME/.ssh
chmod 700 $HOME/.ssh
cp ${testOnlySSHCredentials}/${user}{,.pub,-cert.pub} $HOME/.ssh
chmod 600 $HOME/.ssh/${user}
chmod 644 $HOME/.ssh/${user}{,-cert}.pub
set -x
${pkgs.openssh}/bin/ssh-add $HOME/.ssh/${user}
${pkgs.openssh}/bin/ssh-add -l &>2
exec sudo id -u -n
'';
in {
name = "pam-ussh";
meta.maintainers = with lib.maintainers; [ lukegb ];
machine =
{ ... }:
{
users.users.alice = { isNormalUser = true; extraGroups = [ "wheel" ]; };
users.users.bob = { isNormalUser = true; extraGroups = [ "wheel" ]; };
security.pam.ussh = {
enable = true;
authorizedPrincipals = "root";
caFile = "${testOnlySSHCredentials}/ca.pub";
};
security.sudo = {
enable = true;
extraConfig = ''
Defaults lecture="never"
'';
};
};
testScript =
''
with subtest("alice should be allowed to escalate to root"):
machine.succeed(
'su -c "${makeTestScript "alice"}" -l alice | grep root'
)
with subtest("bob should not be allowed to escalate to root"):
machine.fail(
'su -c "${makeTestScript "bob"}" -l bob | grep root'
)
'';
})

View file

@ -0,0 +1,433 @@
From f63d93bc3d0ad73b24b2cf9c0ee0381161071395 Mon Sep 17 00:00:00 2001
From: Luke Granger-Brown <git@lukegb.com>
Date: Sun, 13 Mar 2022 17:20:16 +0000
Subject: [PATCH 1/2] pam_ussh: init at unstable-20210615
---
pkgs/os-specific/linux/pam_ussh/default.nix | 64 +++++++++++++++++++++
pkgs/os-specific/linux/pam_ussh/go.mod | 15 +++++
pkgs/top-level/all-packages.nix | 2 +
3 files changed, 81 insertions(+)
create mode 100644 pkgs/os-specific/linux/pam_ussh/default.nix
create mode 100644 pkgs/os-specific/linux/pam_ussh/go.mod
diff --git a/pkgs/os-specific/linux/pam_ussh/default.nix b/pkgs/os-specific/linux/pam_ussh/default.nix
new file mode 100644
index 0000000000000..499239500acce
--- /dev/null
+++ b/pkgs/os-specific/linux/pam_ussh/default.nix
@@ -0,0 +1,64 @@
+{ buildGoModule
+, fetchFromGitHub
+, pam
+, lib
+}:
+
+buildGoModule rec {
+ pname = "pam_ussh";
+ version = "unstable-20210615";
+
+ src = fetchFromGitHub {
+ owner = "uber";
+ repo = "pam-ussh";
+ rev = "e9524bda90ba19d3b9eb24f49cb63a6a56a19193"; # HEAD as of 2022-03-13
+ sha256 = "0nb9hpqbghgi3zvq41kabydzyc6ffaaw9b4jkc5jrwn1klpw1xk8";
+ };
+
+ prePatch = ''
+ cp ${./go.mod} go.mod
+ '';
+ overrideModAttrs = (_: {
+ inherit prePatch;
+ });
+
+ vendorSha256 = "0hjifc3kbwmx7kjn858vi05cwwra6q19cqjfd94k726pwhk37qkw";
+
+ buildInputs = [
+ pam
+ ];
+
+ buildPhase = ''
+ runHook preBuild
+
+ if [ -z "$enableParallelBuilding" ]; then
+ export NIX_BUILD_CORES=1
+ fi
+ go build -buildmode=c-shared -o pam_ussh.so -v -p $NIX_BUILD_CORES .
+
+ runHook postBuild
+ '';
+ checkPhase = ''
+ runHook preCheck
+
+ go test -v -p $NIX_BUILD_CORES .
+
+ runHook postCheck
+ '';
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out/lib/security
+ cp pam_ussh.so $out/lib/security
+
+ runHook postInstall
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/uber/pam-ussh";
+ description = "PAM module to authenticate using SSH certificates";
+ license = licenses.mit;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ lukegb ];
+ };
+}
diff --git a/pkgs/os-specific/linux/pam_ussh/go.mod b/pkgs/os-specific/linux/pam_ussh/go.mod
new file mode 100644
index 0000000000000..9adc453560a43
--- /dev/null
+++ b/pkgs/os-specific/linux/pam_ussh/go.mod
@@ -0,0 +1,15 @@
+module github.com/uber/pam-ussh
+
+go 1.17
+
+require (
+ github.com/stretchr/testify v1.7.0
+ golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.0 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
+ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+)
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 6c6832ae05475..539ecd4ec481b 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -23052,6 +23052,8 @@ with pkgs;
pam_usb = callPackage ../os-specific/linux/pam_usb { };
+ pam_ussh = callPackage ../os-specific/linux/pam_ussh { };
+
paxctl = callPackage ../os-specific/linux/paxctl { };
paxtest = callPackage ../os-specific/linux/paxtest { };
From 1853015550a78acbc3e9d090d174120796c4b784 Mon Sep 17 00:00:00 2001
From: Luke Granger-Brown <git@lukegb.com>
Date: Sun, 13 Mar 2022 17:20:23 +0000
Subject: [PATCH 2/2] nixos/pam: add support for pam-ussh
pam-ussh allows authorizing using an SSH certificate stored in your
SSH agent, in a similar manner to pam-ssh-agent-auth, but for
certificates rather than raw public keys.
---
.../from_md/release-notes/rl-2205.section.xml | 9 ++
.../manual/release-notes/rl-2205.section.md | 2 +
nixos/modules/security/pam.nix | 109 ++++++++++++++++++
nixos/modules/security/sudo.nix | 2 +-
nixos/tests/all-tests.nix | 1 +
nixos/tests/pam/pam-ussh.nix | 70 +++++++++++
pkgs/os-specific/linux/pam_ussh/default.nix | 3 +
7 files changed, 195 insertions(+), 1 deletion(-)
create mode 100644 nixos/tests/pam/pam-ussh.nix
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 9cf27e56827a1..ede0e10e03466 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -1286,6 +1286,15 @@
been added by default.
</para>
</listitem>
+ <listitem>
+ <para>
+ <literal>security.pam.ussh</literal> has been added, which
+ allows authorizing PAM sessions based on SSH
+ <emphasis>certificates</emphasis> held within an SSH agent,
+ using
+ <link xlink:href="https://github.com/uber/pam-ussh">pam-ussh</link>.
+ </para>
+ </listitem>
<listitem>
<para>
The <literal>zrepl</literal> package has been updated from
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index 58a1b23d17bf6..90ac7e90e7295 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -470,6 +470,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.logrotate.enable` now defaults to true if any rotate path has
been defined, and some paths have been added by default.
+- `security.pam.ussh` has been added, which allows authorizing PAM sessions based on SSH _certificates_ held within an SSH agent, using [pam-ussh](https://github.com/uber/pam-ussh).
+
- The `zrepl` package has been updated from 0.4.0 to 0.5:
- The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume.
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index c0ef8b5f30bd4..f9697d61f1b27 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -61,6 +61,19 @@ let
'';
};
+ usshAuth = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ If set, users with an SSH certificate containing an authorized principal
+ in their SSH agent are able to log in. Specific options are controlled
+ using the <option>security.pam.ussh</option> options.
+
+ Note that the <option>security.pam.ussh.enable</option> must also be
+ set for this option to take effect.
+ '';
+ };
+
yubicoAuth = mkOption {
default = config.security.pam.yubico.enable;
defaultText = literalExpression "config.security.pam.yubico.enable";
@@ -475,6 +488,9 @@ let
optionalString cfg.usbAuth ''
auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
'' +
+ (let ussh = config.security.pam.ussh; in optionalString (config.security.pam.ussh.enable && cfg.usshAuth) ''
+ auth ${ussh.control} ${pkgs.pam_ussh}/lib/security/pam_ussh.so ${optionalString (ussh.caFile != null) "ca_file=${ussh.caFile}"} ${optionalString (ussh.authorizedPrincipals != null) "authorized_principals=${ussh.authorizedPrincipals}"} ${optionalString (ussh.authorizedPrincipalsFile != null) "authorized_principals_file=${ussh.authorizedPrincipalsFile}"} ${optionalString (ussh.group != null) "group=${ussh.group}"}
+ '') +
(let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
'') +
@@ -926,6 +942,96 @@ in
};
};
+ security.pam.ussh = {
+ enable = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Enables Uber's USSH PAM (<literal>pam-ussh</literal>) module.
+
+ This is similar to <literal>pam-ssh-agent</literal>, except that
+ the presence of a CA-signed SSH key with a valid principal is checked
+ instead.
+
+ Note that this module must both be enabled using this option and on a
+ per-PAM-service level as well (using <literal>usshAuth</literal>).
+
+ More information can be found <link
+ xlink:href="https://github.com/uber/pam-ussh">here</link>.
+ '';
+ };
+
+ caFile = mkOption {
+ default = null;
+ type = with types; nullOr path;
+ description = ''
+ By default <literal>pam-ussh</literal> reads the trusted user CA keys
+ from <filename>/etc/ssh/trusted_user_ca</filename>.
+
+ This should be set the same as your <literal>TrustedUserCAKeys</literal>
+ option for sshd.
+ '';
+ };
+
+ authorizedPrincipals = mkOption {
+ default = null;
+ type = with types; nullOr commas;
+ description = ''
+ Comma-separated list of authorized principals to permit; if the user
+ presents a certificate with one of these principals, then they will be
+ authorized.
+
+ Note that <literal>pam-ussh</literal> also requires that the certificate
+ contain a principal matching the user's username. The principals from
+ this list are in addition to those principals.
+
+ Mutually exclusive with <literal>authorizedPrincipalsFile</literal>.
+ '';
+ };
+
+ authorizedPrincipalsFile = mkOption {
+ default = null;
+ type = with types; nullOr path;
+ description = ''
+ Path to a list of principals; if the user presents a certificate with
+ one of these principals, then they will be authorized.
+
+ Note that <literal>pam-ussh</literal> also requires that the certificate
+ contain a principal matching the user's username. The principals from
+ this file are in addition to those principals.
+
+ Mutually exclusive with <literal>authorizedPrincipals</literal>.
+ '';
+ };
+
+ group = mkOption {
+ default = null;
+ type = with types; nullOr str;
+ description = ''
+ If set, then the authenticating user must be a member of this group
+ to use this module.
+ '';
+ };
+
+ control = mkOption {
+ default = "sufficient";
+ type = types.enum [ "required" "requisite" "sufficient" "optional" ];
+ description = ''
+ This option sets pam "control".
+ If you want to have multi factor authentication, use "required".
+ If you want to use the SSH certificate instead of the regular password,
+ use "sufficient".
+
+ Read
+ <citerefentry>
+ <refentrytitle>pam.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ for better understanding of this option.
+ '';
+ };
+ };
+
security.pam.yubico = {
enable = mkOption {
default = false;
@@ -1110,6 +1216,9 @@ in
optionalString (isEnabled (cfg: cfg.usbAuth)) ''
mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
'' +
+ optionalString (isEnabled (cfg: cfg.usshAuth)) ''
+ mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
+ '' +
optionalString (isEnabled (cfg: cfg.oathAuth)) ''
"mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,
'' +
diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix
index 99e578f8adae6..4bf239fca8f90 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -245,7 +245,7 @@ in
environment.systemPackages = [ sudo ];
- security.pam.services.sudo = { sshAgentAuth = true; };
+ security.pam.services.sudo = { sshAgentAuth = true; usshAuth = true; };
environment.etc.sudoers =
{ source =
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 043d8a56d0c63..1ed12c54c5752 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -388,6 +388,7 @@ in
pam-file-contents = handleTest ./pam/pam-file-contents.nix {};
pam-oath-login = handleTest ./pam/pam-oath-login.nix {};
pam-u2f = handleTest ./pam/pam-u2f.nix {};
+ pam-ussh = handleTest ./pam/pam-ussh.nix {};
pantalaimon = handleTest ./matrix/pantalaimon.nix {};
pantheon = handleTest ./pantheon.nix {};
paperless-ng = handleTest ./paperless-ng.nix {};
diff --git a/nixos/tests/pam/pam-ussh.nix b/nixos/tests/pam/pam-ussh.nix
new file mode 100644
index 0000000000000..ba0570dbf97d2
--- /dev/null
+++ b/nixos/tests/pam/pam-ussh.nix
@@ -0,0 +1,70 @@
+import ../make-test-python.nix ({ pkgs, lib, ... }:
+
+let
+ testOnlySSHCredentials = pkgs.runCommand "pam-ussh-test-ca" {
+ nativeBuildInputs = [ pkgs.openssh ];
+ } ''
+ mkdir $out
+ ssh-keygen -t ed25519 -N "" -f $out/ca
+
+ ssh-keygen -t ed25519 -N "" -f $out/alice
+ ssh-keygen -s $out/ca -I "alice user key" -n "alice,root" -V 19700101:forever $out/alice.pub
+
+ ssh-keygen -t ed25519 -N "" -f $out/bob
+ ssh-keygen -s $out/ca -I "bob user key" -n "bob" -V 19700101:forever $out/bob.pub
+ '';
+ makeTestScript = user: pkgs.writeShellScript "pam-ussh-${user}-test-script" ''
+ set -euo pipefail
+
+ eval $(${pkgs.openssh}/bin/ssh-agent)
+
+ mkdir -p $HOME/.ssh
+ chmod 700 $HOME/.ssh
+ cp ${testOnlySSHCredentials}/${user}{,.pub,-cert.pub} $HOME/.ssh
+ chmod 600 $HOME/.ssh/${user}
+ chmod 644 $HOME/.ssh/${user}{,-cert}.pub
+
+ set -x
+
+ ${pkgs.openssh}/bin/ssh-add $HOME/.ssh/${user}
+ ${pkgs.openssh}/bin/ssh-add -l &>2
+
+ exec sudo id -u -n
+ '';
+in {
+ name = "pam-ussh";
+ meta.maintainers = with lib.maintainers; [ lukegb ];
+
+ machine =
+ { ... }:
+ {
+ users.users.alice = { isNormalUser = true; extraGroups = [ "wheel" ]; };
+ users.users.bob = { isNormalUser = true; extraGroups = [ "wheel" ]; };
+
+ security.pam.ussh = {
+ enable = true;
+ authorizedPrincipals = "root";
+ caFile = "${testOnlySSHCredentials}/ca.pub";
+ };
+
+ security.sudo = {
+ enable = true;
+ extraConfig = ''
+ Defaults lecture="never"
+ '';
+ };
+ };
+
+ testScript =
+ ''
+ with subtest("alice should be allowed to escalate to root"):
+ machine.succeed(
+ 'su -c "${makeTestScript "alice"}" -l alice | grep root'
+ )
+
+ with subtest("bob should not be allowed to escalate to root"):
+ machine.fail(
+ 'su -c "${makeTestScript "bob"}" -l bob | grep root'
+ )
+ '';
+})
diff --git a/pkgs/os-specific/linux/pam_ussh/default.nix b/pkgs/os-specific/linux/pam_ussh/default.nix
index 499239500acce..889c8bc6f57cf 100644
--- a/pkgs/os-specific/linux/pam_ussh/default.nix
+++ b/pkgs/os-specific/linux/pam_ussh/default.nix
@@ -2,6 +2,7 @@
, fetchFromGitHub
, pam
, lib
+, nixosTests
}:
buildGoModule rec {
@@ -54,6 +55,8 @@ buildGoModule rec {
runHook postInstall
'';
+ passthru.tests = { inherit (nixosTests) pam-ussh; };
+
meta = with lib; {
homepage = "https://github.com/uber/pam-ussh";
description = "PAM module to authenticate using SSH certificates";

View file

@ -1,5 +1,6 @@
nvidia-sideband-socket.patch nvidia-sideband-socket.patch
pr163673.patch pr163673.patch
pr163678.patch pr163678.patch
pr164025.patch
networkd-support-more-wg-options.patch networkd-support-more-wg-options.patch
networkd-global-options.patch networkd-global-options.patch

View file

@ -0,0 +1,67 @@
{ buildGoModule
, fetchFromGitHub
, pam
, lib
, nixosTests
}:
buildGoModule rec {
pname = "pam_ussh";
version = "unstable-20210615";
src = fetchFromGitHub {
owner = "uber";
repo = "pam-ussh";
rev = "e9524bda90ba19d3b9eb24f49cb63a6a56a19193"; # HEAD as of 2022-03-13
sha256 = "0nb9hpqbghgi3zvq41kabydzyc6ffaaw9b4jkc5jrwn1klpw1xk8";
};
prePatch = ''
cp ${./go.mod} go.mod
'';
overrideModAttrs = (_: {
inherit prePatch;
});
vendorSha256 = "0hjifc3kbwmx7kjn858vi05cwwra6q19cqjfd94k726pwhk37qkw";
buildInputs = [
pam
];
buildPhase = ''
runHook preBuild
if [ -z "$enableParallelBuilding" ]; then
export NIX_BUILD_CORES=1
fi
go build -buildmode=c-shared -o pam_ussh.so -v -p $NIX_BUILD_CORES .
runHook postBuild
'';
checkPhase = ''
runHook preCheck
go test -v -p $NIX_BUILD_CORES .
runHook postCheck
'';
installPhase = ''
runHook preInstall
mkdir -p $out/lib/security
cp pam_ussh.so $out/lib/security
runHook postInstall
'';
passthru.tests = { inherit (nixosTests) pam-ussh; };
meta = with lib; {
homepage = "https://github.com/uber/pam-ussh";
description = "PAM module to authenticate using SSH certificates";
license = licenses.mit;
platforms = platforms.linux;
maintainers = with maintainers; [ lukegb ];
};
}

View file

@ -0,0 +1,15 @@
module github.com/uber/pam-ussh
go 1.17
require (
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000
)
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

View file

@ -23046,6 +23046,8 @@ with pkgs;
pam_usb = callPackage ../os-specific/linux/pam_usb { }; pam_usb = callPackage ../os-specific/linux/pam_usb { };
pam_ussh = callPackage ../os-specific/linux/pam_ussh { };
paxctl = callPackage ../os-specific/linux/paxctl { }; paxctl = callPackage ../os-specific/linux/paxctl { };
paxtest = callPackage ../os-specific/linux/paxtest { }; paxtest = callPackage ../os-specific/linux/paxtest { };