Domenico Andreoli
2020-Jul-21 01:06 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
Hi, The main (and probably the only) use case of this PAM module is to let sudo authenticate users via their ssh-agent, therefore without having to type any password and without being tempted to use the NOPASSWD sudo option for such convenience. The principle is originally implemented by an existing module [0][1] and many pages that explain how to use it for such purpose can be found online. Why then this new implementation? A few reasons: - it's way smaller, more simple and easier to audit - it wants to remain as such - it reuses everything from openssh-portable; no novel, outdated or alternative crypto implementations - it's based on openssh-portable so it supports all the algorithms that ssh-agent does (eg. ecdsa-sk, ed25519-sk, pkcs#11, ... yuk!) Now, the natural place for this, I think, is right with openssh-portable. Is there, maybe, by any chance, a way to merge it there? This is a critical piece of software for those who use it and needs to be well guarded. It has super healthy tests, the maintenance effort can reimain low and easy. A few things that are missing: - man page - installation - support for multiple keys in the auth file I'm also asking to the Linux PAM people to double-check my usage of PAM. Regards, Domenico [0] https://github.com/jbeverly/pam_ssh_agent_auth [1] https://sourceforge.net/projects/pamsshagentauth/ -- rsa4096: 3B10 0CA1 8674 ACBA B4FE FCD2 CE5B CF17 9960 DE13 ed25519: FFB4 0CC3 7F2E 091D F7DA 356E CC79 2832 ED38 CB05
Domenico Andreoli
2020-Jul-21 01:06 UTC
[RFC PATCH 1/4] pam-ssh-agent: Bootstrap the developemnt / testing cycle
Add a minimal implementation of the PAM ssh-agent module, hook up all the build and test infrastructure, add minimal tests for arguments validation. The module is built as shared object, PIC versions of libssh and libopenbsd-compat are therefore built if needed. Testing is based on pam_wrapper and is enabled only if the required libraries and headers are found during configuration. During test ssh keys of various types are used. The ktype.sh script is split so to reuse the keys generation part. The module is not built by default. Signed-off-by: Domenico Andreoli <domenico.andreoli at linux.com> --- Makefile.in | 27 ++++++++++++- config.h.in | 9 ++++ configure.ac | 35 +++++++++++++++++ openbsd-compat/Makefile.in | 13 +++++- pam-ssh-agent.c | 88 +++++++++++++++++++++++++++++++++++++++++++ regress/Makefile | 2 + regress/keytype.sh | 41 -------------------- regress/keytype_gen.sh | 43 +++++++++++++++++++++ regress/pam-ssh-agent-test.c | 48 +++++++++++++++++++++++ regress/pam-ssh-agent.sh | 43 +++++++++++++++++++++ 10 files changed, 305 insertions(+), 44 deletions(-) Index: b/regress/pam-ssh-agent-test.c ==================================================================--- /dev/null +++ b/regress/pam-ssh-agent-test.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Domenico Andreoli + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <libpamtest.h> + +int +main(int argc, char **argv) +{ + int ret; + + struct pam_testcase tests[] = { + pam_test(PAMTEST_AUTHENTICATE, PAM_SUCCESS), + pam_test(PAMTEST_SETCRED, PAM_SUCCESS), + }; + + ret = run_pamtest(argv[0], getenv("USER"), NULL, tests); + if (ret) { + if (ret == PAMTEST_ERR_CASE) + ret = pamtest_failed_case(tests)->op_rv; + else + ret = 1; + } + + return ret; +} Index: b/regress/Makefile ==================================================================--- a/regress/Makefile +++ b/regress/Makefile @@ -16,6 +16,7 @@ prep: clean: for F in $(CLEANFILES); do rm -f $(OBJ)$$F; done rm -rf $(OBJ).putty + rm -rf $(OBJ)pam-ssh-agent-test.d distclean: clean @@ -92,6 +93,7 @@ LTESTS= connect \ allow-deny-users \ authinfo \ sshsig \ + pam-ssh-agent \ keygen-comment Index: b/Makefile.in ==================================================================--- a/Makefile.in +++ b/Makefile.in @@ -29,6 +29,8 @@ PRIVSEP_PATH=@PRIVSEP_PATH@ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ STRIP_OPT=@STRIP_OPT@ TEST_SHELL=@TEST_SHELL@ +PAM_SSH_AGENT=@PAM_SSH_AGENT@ +PAM_SSH_AGENT_TEST=@PAM_SSH_AGENT_TEST@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \ -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ @@ -68,7 +70,7 @@ MKDIR_P=@MKDIR_P@ .SUFFIXES: .lo -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) $(PAM_SSH_AGENT) XMSS_OBJS=\ ssh-xmss.o \ @@ -152,6 +154,9 @@ SFTPSERVER_OBJS=sftp-common.o sftp-serve SFTP_OBJS= sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o +# These need to be compiled with -fPIC, so they are treated differently. +PAM_SSH_AGENT_OBJS=pam-ssh-agent.lo $(SKHELPER_OBJS:.o=.lo) + MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-sk-helper.8.out sshd_config.5.out ssh_config.5.out MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-sk-helper.8 sshd_config.5 ssh_config.5 MANTYPE = @MANTYPE@ @@ -187,6 +192,7 @@ all: configure-check $(CONFIGFILES) $(MA $(LIBSSH_OBJS): Makefile.in config.h $(SSHOBJS): Makefile.in config.h $(SSHDOBJS): Makefile.in config.h +$(PAM_SSH_AGENT_OBJS): Makefile.in config.h configure-check: $(srcdir)/configure $(srcdir)/configure: configure.ac aclocal.m4 @@ -198,13 +204,20 @@ $(srcdir)/configure: configure.ac acloca LIBCOMPAT=openbsd-compat/libopenbsd-compat.a $(LIBCOMPAT): always - (cd openbsd-compat && $(MAKE)) + (cd openbsd-compat && $(MAKE) libopenbsd-compat.a) +LIBCOMPAT_PIC=openbsd-compat/libopenbsd-compat-pic.a +$(LIBCOMPAT_PIC): always + (cd openbsd-compat && $(MAKE) libopenbsd-compat-pic.a) always: libssh.a: $(LIBSSH_OBJS) $(AR) rv $@ $(LIBSSH_OBJS) $(RANLIB) $@ +libssh-pic.a: $(LIBSSH_OBJS:.o=.lo) + $(AR) rv $@ $(LIBSSH_OBJS:.o=.lo) + $(RANLIB) $@ + ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) @@ -241,6 +254,9 @@ sftp-server$(EXEEXT): $(LIBCOMPAT) libss sftp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTP_OBJS) $(LD) -o $@ $(SFTP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) +pam_ssh_agent.so: $(PAM_SSH_AGENT_OBJS) libssh-pic.a $(LIBCOMPAT_PIC) + $(LD) -o $@ $(PAM_SSH_AGENT_OBJS) $(LDFLAGS_NOPIE) -shared -lpam -lssh-pic -lopenbsd-compat-pic $(LIBS) + # test driver for the loginrec code - not built by default logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) @@ -271,6 +287,7 @@ clean: regressclean rm -f *.out core survey rm -f regress/check-perm$(EXEEXT) rm -f regress/mkdtemp$(EXEEXT) + rm -f regress/pam-ssh-agent-test$(EXEEXT) rm -f regress/unittests/test_helper/*.a rm -f regress/unittests/test_helper/*.o rm -f regress/unittests/sshbuf/*.o @@ -304,6 +321,7 @@ distclean: regressclean rm -rf autom4te.cache rm -f regress/check-perm rm -f regress/mkdtemp + rm -f regress/pam-ssh-agent-test rm -f regress/unittests/test_helper/*.a rm -f regress/unittests/test_helper/*.o rm -f regress/unittests/sshbuf/*.o @@ -521,6 +539,9 @@ regress/mkdtemp$(EXEEXT): $(srcdir)/regr $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/mkdtemp.c \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +regress/pam-ssh-agent-test$(EXEEXT): $(srcdir)/regress/pam-ssh-agent-test.c + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/pam-ssh-agent-test.c $(LDFLAGS) -lpamtest + UNITTESTS_TEST_HELPER_OBJS=\ regress/unittests/test_helper/test_helper.o \ regress/unittests/test_helper/fuzz.o @@ -650,6 +671,7 @@ regress-binaries: regress-prep $(LIBCOMP regress/netcat$(EXEEXT) \ regress/check-perm$(EXEEXT) \ regress/mkdtemp$(EXEEXT) \ + $(PAM_SSH_AGENT_TEST) \ $(SK_DUMMY_LIBRARY) regress-unit-binaries: regress-prep $(REGRESSLIBS) \ @@ -686,6 +708,7 @@ interop-tests t-exec file-tests: regress PATH="$${BUILDDIR}:$${PATH}" \ TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \ TEST_MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \ + TEST_PAM_SSH_AGENT="$(or $(PAM_SSH_AGENT_TEST),no)" \ TEST_SSH_SCP="$${BUILDDIR}/scp" \ TEST_SSH_SSH="$${BUILDDIR}/ssh" \ TEST_SSH_SSHD="$${BUILDDIR}/sshd" \ Index: b/regress/pam-ssh-agent.sh ==================================================================--- /dev/null +++ b/regress/pam-ssh-agent.sh @@ -0,0 +1,43 @@ +# Placed in the Public Domain. + +# Kudos to the Samba team, pam_wrapper made this module possible +# +# https://cwrap.org/pam_wrapper.html +# https://lwn.net/Articles/671094/ + +if [ "x$TEST_PAM_SSH_AGENT" = "xno" ]; then + verbose "PAM ssh-agent testing is disabled, skipping tests..." + exit 0 +fi + +export PAM_WRAPPER_SERVICE_DIR=$OBJ/pam-ssh-agent-test.d + +PAM_SUCCESS=0 +PAM_SERVICE_ERR=3 + +. $OBJ/keytype_gen.sh + +pam_agent_test() +{ + rm -rf $PAM_WRAPPER_SERVICE_DIR + mkdir -p $PAM_WRAPPER_SERVICE_DIR + cat >$PAM_WRAPPER_SERVICE_DIR/other <<EOF +auth required $BUILDDIR/pam_ssh_agent.so $* +EOF + + LD_PRELOAD=libpam_wrapper.so \ + PAM_WRAPPER=1 \ + $BUILDDIR/$TEST_PAM_SSH_AGENT + + local ret=$? + [ "x$ret" = "x$expect" ] || fatal "expected $expect, got $ret" +} + +trace "invalid arguments" +expect=$PAM_SERVICE_ERR pam_agent_test invalid arguments + +trace "debug argument" +expect=$PAM_SUCCESS pam_agent_test debug + +trace "without arguments" +expect=$PAM_SUCCESS pam_agent_test Index: b/pam-ssh-agent.c ==================================================================--- /dev/null +++ b/pam-ssh-agent.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Domenico Andreoli + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include <string.h> +#include <syslog.h> + +#define PAM_SM_AUTH +#if defined(HAVE_SECURITY_PAM_MODULES_H) +#include <security/pam_modules.h> +#elif defined(HAVE_PAM_PAM_MODULES_H) +#include <pam/pam_modules.h> +#endif + +static int pam_debug; + +static int +parse_args(int argc, const char **argv) +{ + int i, invalid = 0; + + for (i=0; i!=argc; i++) { + if (!strcmp(argv[i], "debug")) { + pam_debug = 1; + } else { + syslog(LOG_ERR, "invalid argument: %s", argv[i]); + invalid++; + } + } + + return invalid; +} + +int +pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int ret; + + openlog("pam_ssh_agent_auth", 0, LOG_AUTHPRIV); + + if (parse_args(argc, argv)) { + ret = PAM_SERVICE_ERR; + goto out; + } + + if (pam_debug) { + const char *user = "(unknown)"; + pam_get_user(pamh, &user, NULL); + syslog(LOG_DEBUG, "USER: %s", user); + } + + ret = PAM_SUCCESS; + +out: + if (pam_debug) + syslog(LOG_DEBUG, "result: %s", pam_strerror(pamh, ret)); + closelog(); + return ret; +} + +int +pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} Index: b/configure.ac ==================================================================--- a/configure.ac +++ b/configure.ac @@ -392,6 +392,7 @@ AC_CHECK_HEADERS([ \ ifaddrs.h \ inttypes.h \ langinfo.h \ + libpamtest.h \ limits.h \ locale.h \ login.h \ @@ -401,12 +402,14 @@ AC_CHECK_HEADERS([ \ netdb.h \ netgroup.h \ pam/pam_appl.h \ + pam/pam_modules.h \ paths.h \ poll.h \ pty.h \ readpassphrase.h \ rpc/types.h \ security/pam_appl.h \ + security/pam_modules.h \ sha2.h \ shadow.h \ stddef.h \ @@ -3352,6 +3355,37 @@ AC_ARG_WITH([pam], ] ) +PAM_SSH_AGENT_MSG="no" +AC_ARG_WITH([pam-ssh-agent], + [ --with-pam-ssh-agent Build PAM module for ssh-agent authentication], + [ + if test "x$withval" != "xno" ; then + if test "x$ac_cv_header_security_pam_modules_h" != "xyes" && \ + test "x$ac_cv_header_pam_pam_modules_h" != "xyes" ; then + AC_MSG_ERROR([PAM headers not found]) + fi + + AC_SUBST(PAM_SSH_AGENT, [pam_ssh_agent.so]) + PAM_SSH_AGENT_MSG="yes" + + saved_LIBS="$LIBS" + AC_CHECK_LIB([pam_wrapper], [pam_start], , [have_pam_wrapper=no]) + AC_CHECK_LIB([pamtest], [pamtest_strerror], , [have_pamtest=no]) + LIBS="$saved_LIBS" + + if test "x$have_pam_wrapper" = "xno" || test "x$have_pamtest" = "xno" ; then + PAM_SSH_AGENT_MSG="yes (for testing, install pam_wrapper and libpamtest-dev)" + else + if test "x$ac_cv_header_libpamtest_h" = "xyes" ; then + AC_SUBST(PAM_SSH_AGENT_TEST, [regress/pam-ssh-agent-test\$\(EXEEXT\)]) + else + AC_MSG_ERROR([libpamtest headers not found]) + fi + fi + fi + ] +) + AC_ARG_WITH([pam-service], [ --with-pam-service=name Specify PAM service name ], [ @@ -5452,6 +5486,7 @@ echo " sshd superuser user PATH fi echo " Manpage format: $MANTYPE" echo " PAM support: $PAM_MSG" +echo " PAM ssh-agent support: $PAM_SSH_AGENT_MSG" echo " OSF SIA support: $SIA_MSG" echo " KerberosV support: $KRB5_MSG" echo " SELinux support: $SELINUX_MSG" Index: b/config.h.in ==================================================================--- a/config.h.in +++ b/config.h.in @@ -843,6 +843,9 @@ /* Define to 1 if you have the `pam' library (-lpam). */ #undef HAVE_LIBPAM +/* Define to 1 if you have the <libpamtest.h> header file. */ +#undef HAVE_LIBPAMTEST_H + /* Define to 1 if you have the <libproc.h> header file. */ #undef HAVE_LIBPROC_H @@ -1007,6 +1010,9 @@ /* Define to 1 if you have the <pam/pam_appl.h> header file. */ #undef HAVE_PAM_PAM_APPL_H +/* Define to 1 if you have the <pam/pam_modules.h> header file. */ +#undef HAVE_PAM_PAM_MODULES_H + /* Define to 1 if you have the `pam_putenv' function. */ #undef HAVE_PAM_PUTENV @@ -1152,6 +1158,9 @@ /* Define to 1 if you have the <security/pam_appl.h> header file. */ #undef HAVE_SECURITY_PAM_APPL_H +/* Define to 1 if you have the <security/pam_modules.h> header file. */ +#undef HAVE_SECURITY_PAM_MODULES_H + /* Define to 1 if you have the `sendmsg' function. */ #undef HAVE_SENDMSG Index: b/regress/keytype_gen.sh ==================================================================--- /dev/null +++ b/regress/keytype_gen.sh @@ -0,0 +1,43 @@ +# $OpenBSD: keytype.sh,v 1.10 2019/12/16 02:39:05 djm Exp $ +# Placed in the Public Domain. + +# Construct list of key types based on what the built binaries support. +ktypes="" +for i in ${SSH_KEYTYPES}; do + case "$i" in + ssh-dss) ktypes="$ktypes dsa-1024" ;; + ssh-rsa) ktypes="$ktypes rsa-2048 rsa-3072" ;; + ssh-ed25519) ktypes="$ktypes ed25519-512" ;; + ecdsa-sha2-nistp256) ktypes="$ktypes ecdsa-256" ;; + ecdsa-sha2-nistp384) ktypes="$ktypes ecdsa-384" ;; + ecdsa-sha2-nistp521) ktypes="$ktypes ecdsa-521" ;; + sk-ssh-ed25519*) ktypes="$ktypes ed25519-sk" ;; + sk-ecdsa-sha2-nistp256*) ktypes="$ktypes ecdsa-sk" ;; + esac +done + +for kt in $ktypes; do + rm -f $OBJ/key.$kt + xbits=`echo ${kt} | awk -F- '{print $2}'` + xtype=`echo ${kt} | awk -F- '{print $1}'` + case "$kt" in + *sk) type="$kt"; bits="n/a"; bits_arg="";; + *) type=$xtype; bits=$xbits; bits_arg="-b $bits";; + esac + verbose "keygen $type, $bits bits" + ${SSHKEYGEN} $bits_arg -q -N '' -t $type -C "$kt" -f $OBJ/key.$kt || \ + fail "ssh-keygen for type $type, $bits bits failed" +done + +kname_to_ktype() { + case $1 in + dsa-1024) echo ssh-dss;; + ecdsa-256) echo ecdsa-sha2-nistp256;; + ecdsa-384) echo ecdsa-sha2-nistp384;; + ecdsa-521) echo ecdsa-sha2-nistp521;; + ed25519-512) echo ssh-ed25519;; + rsa-*) echo rsa-sha2-512,rsa-sha2-256,ssh-rsa;; + ed25519-sk) echo sk-ssh-ed25519 at openssh.com;; + ecdsa-sk) echo sk-ecdsa-sha2-nistp256 at openssh.com;; + esac +} Index: b/regress/keytype.sh ==================================================================--- a/regress/keytype.sh +++ b/regress/keytype.sh @@ -6,46 +6,7 @@ tid="login with different key types" cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak -# Construct list of key types based on what the built binaries support. -ktypes="" -for i in ${SSH_KEYTYPES}; do - case "$i" in - ssh-dss) ktypes="$ktypes dsa-1024" ;; - ssh-rsa) ktypes="$ktypes rsa-2048 rsa-3072" ;; - ssh-ed25519) ktypes="$ktypes ed25519-512" ;; - ecdsa-sha2-nistp256) ktypes="$ktypes ecdsa-256" ;; - ecdsa-sha2-nistp384) ktypes="$ktypes ecdsa-384" ;; - ecdsa-sha2-nistp521) ktypes="$ktypes ecdsa-521" ;; - sk-ssh-ed25519*) ktypes="$ktypes ed25519-sk" ;; - sk-ecdsa-sha2-nistp256*) ktypes="$ktypes ecdsa-sk" ;; - esac -done - -for kt in $ktypes; do - rm -f $OBJ/key.$kt - xbits=`echo ${kt} | awk -F- '{print $2}'` - xtype=`echo ${kt} | awk -F- '{print $1}'` - case "$kt" in - *sk) type="$kt"; bits="n/a"; bits_arg="";; - *) type=$xtype; bits=$xbits; bits_arg="-b $bits";; - esac - verbose "keygen $type, $bits bits" - ${SSHKEYGEN} $bits_arg -q -N '' -t $type -f $OBJ/key.$kt || \ - fail "ssh-keygen for type $type, $bits bits failed" -done - -kname_to_ktype() { - case $1 in - dsa-1024) echo ssh-dss;; - ecdsa-256) echo ecdsa-sha2-nistp256;; - ecdsa-384) echo ecdsa-sha2-nistp384;; - ecdsa-521) echo ecdsa-sha2-nistp521;; - ed25519-512) echo ssh-ed25519;; - rsa-*) echo rsa-sha2-512,rsa-sha2-256,ssh-rsa;; - ed25519-sk) echo sk-ssh-ed25519 at openssh.com;; - ecdsa-sk) echo sk-ecdsa-sha2-nistp256 at openssh.com;; - esac -} +. $OBJ/keytype_gen.sh tries="1 2 3" for ut in $ktypes; do Index: b/openbsd-compat/Makefile.in ==================================================================--- a/openbsd-compat/Makefile.in +++ b/openbsd-compat/Makefile.in @@ -17,6 +17,8 @@ INSTALL=@INSTALL@ LDFLAGS=-L. @LDFLAGS@ LDFLAGS_NOPIE=-L. -Lopenbsd-compat/ @LDFLAGS_NOPIE@ +.SUFFIXES: .lo + OPENBSD=base64.o \ basename.o \ bcrypt_pbkdf.o \ @@ -101,7 +103,7 @@ PORTS= port-aix.o \ .c.o: $(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $< -all: libopenbsd-compat.a +all: libopenbsd-compat.a libopenbsd-compat-pic.a $(COMPAT): ../config.h $(OPENBSD): ../config.h @@ -111,8 +113,15 @@ libopenbsd-compat.a: $(COMPAT) $(OPENBS $(AR) rv $@ $(COMPAT) $(OPENBSD) $(PORTS) $(RANLIB) $@ +libopenbsd-compat-pic.a: $(COMPAT:.o=.lo) $(OPENBSD:.o=.lo) $(PORTS:.o=.lo) + $(AR) rv $@ $^ + $(RANLIB) $@ + +.c.lo: Makefile.in config.h + $(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $< -o $@ + clean: - rm -f *.o *.a core + rm -f *.o *.lo *.a core distclean: clean rm -f Makefile *~
Domenico Andreoli
2020-Jul-21 01:06 UTC
[RFC PATCH 2/4] pam-ssh-agent: Add reading of one auth key from file
The module needs to read authorized ssh keys from file. Tests validate the file name and content. This first implementation reads only one key, support for multiple keys would be added later. Fancy ways to obtain auth keys need to be implemented in separate modules and keys would be shared via PAM environment (to be implemented). Signed-off-by: Domenico Andreoli <domenico.andreoli at linux.com> --- pam-ssh-agent.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ regress/pam-ssh-agent.sh | 24 +++++++++++++++--- 2 files changed, 84 insertions(+), 4 deletions(-) Index: b/pam-ssh-agent.c ==================================================================--- a/pam-ssh-agent.c +++ b/pam-ssh-agent.c @@ -35,7 +35,12 @@ #include <pam/pam_modules.h> #endif +#include "authfile.h" +#include "authfd.h" +#include "ssherr.h" + static int pam_debug; +static const char *auth_file; static int parse_args(int argc, const char **argv) @@ -45,6 +50,14 @@ parse_args(int argc, const char **argv) for (i=0; i!=argc; i++) { if (!strcmp(argv[i], "debug")) { pam_debug = 1; + } else if (!strncmp(argv[i], "file=", 5)) { + if (argv[i][5] == '\0') + continue; + auth_file = argv[i] + 5; + if (auth_file[0] != '/') { + syslog(LOG_ERR, "auth file error: Path is not absolute: %s", auth_file); + invalid++; + } } else { syslog(LOG_ERR, "invalid argument: %s", argv[i]); invalid++; @@ -54,9 +67,37 @@ parse_args(int argc, const char **argv) return invalid; } +static int +ssh_read_identitylist(const char *filename, struct ssh_identitylist **idlp) +{ + struct ssh_identitylist *idl = NULL; + int r; + + if ((idl = calloc(1, sizeof(*idl))) == NULL || + (idl->keys = calloc(1, sizeof(*idl->keys))) == NULL || + (idl->comments = calloc(1, sizeof(*idl->comments))) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + r = sshkey_load_public(filename, &idl->keys[0], &idl->comments[0]); + if (r) + goto out; + + idl->nkeys = 1; + *idlp = idl; + idl = NULL; + +out: + if (idl != NULL) + ssh_free_identitylist(idl); + return r; +} + int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { + struct ssh_identitylist *auth_ids = NULL; int ret; openlog("pam_ssh_agent_auth", 0, LOG_AUTHPRIV); @@ -70,11 +111,34 @@ pam_sm_authenticate(pam_handle_t *pamh, const char *user = "(unknown)"; pam_get_user(pamh, &user, NULL); syslog(LOG_DEBUG, "USER: %s", user); + syslog(LOG_DEBUG, "FILE: %s", auth_file ? auth_file : "(null)"); + } + + if (auth_file == NULL) { + syslog(LOG_ERR, "auth file error: file= is not specified"); + ret = PAM_SERVICE_ERR; + goto out; + } + + ret = ssh_read_identitylist(auth_file, &auth_ids); + if (ret) { + syslog(LOG_ERR, "auth file error: %s: %s", ssh_err(ret), auth_file); + ret = PAM_AUTHINFO_UNAVAIL; + goto out; + } + + if (pam_debug) { + unsigned i; + syslog(LOG_DEBUG, "auth file has %u key(s):", (unsigned) auth_ids->nkeys); + for (i=0; i!=auth_ids->nkeys; i++) + syslog(LOG_DEBUG, " %d) %s", i, auth_ids->comments[i]); } ret = PAM_SUCCESS; out: + if (auth_ids != NULL) + ssh_free_identitylist(auth_ids); if (pam_debug) syslog(LOG_DEBUG, "result: %s", pam_strerror(pamh, ret)); closelog(); Index: b/regress/pam-ssh-agent.sh ==================================================================--- a/regress/pam-ssh-agent.sh +++ b/regress/pam-ssh-agent.sh @@ -14,9 +14,13 @@ export PAM_WRAPPER_SERVICE_DIR=$OBJ/pam- PAM_SUCCESS=0 PAM_SERVICE_ERR=3 +PAM_AUTHINFO_UNAVAIL=9 . $OBJ/keytype_gen.sh +first_kt=`echo $ktypes | cut -d" " -f1` +AUTH_FILE=$OBJ/key.$first_kt.pub + pam_agent_test() { rm -rf $PAM_WRAPPER_SERVICE_DIR @@ -36,8 +40,20 @@ EOF trace "invalid arguments" expect=$PAM_SERVICE_ERR pam_agent_test invalid arguments -trace "debug argument" -expect=$PAM_SUCCESS pam_agent_test debug - trace "without arguments" -expect=$PAM_SUCCESS pam_agent_test +expect=$PAM_SERVICE_ERR pam_agent_test # file= is required + +trace "with non-absolute auth file path" +expect=$PAM_SERVICE_ERR pam_agent_test file=nonabsolute.$$ + +trace "with non-existent auth file" +expect=$PAM_AUTHINFO_UNAVAIL pam_agent_test file=/nonexistent.$$ + +trace "with empty auth file" +expect=$PAM_AUTHINFO_UNAVAIL pam_agent_test file=/dev/null + +trace "authenticate agent (debug)" +expect=$PAM_SUCCESS pam_agent_test file=$AUTH_FILE debug + +trace "authenticate agent (non-debug)" +expect=$PAM_SUCCESS pam_agent_test file=$AUTH_FILE
Domenico Andreoli
2020-Jul-21 01:06 UTC
[RFC PATCH 3/4] pam-ssh-agent: Add connecting to the SSH agent
The module now connects to the agent and fetches the identities therein stored, if any. Tests verify the behavior in case of missing SSH_AUTH_SOCK, communication issues and empty ssh-agent. Signed-off-by: Domenico Andreoli <domenico.andreoli at linux.com> --- pam-ssh-agent.c | 31 +++++++++++++++++++++++++++++++ regress/pam-ssh-agent.sh | 24 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+) Index: b/pam-ssh-agent.c ==================================================================--- a/pam-ssh-agent.c +++ b/pam-ssh-agent.c @@ -38,6 +38,7 @@ #include "authfile.h" #include "authfd.h" #include "ssherr.h" +#include "ssh.h" static int pam_debug; static const char *auth_file; @@ -97,7 +98,9 @@ ssh_read_identitylist(const char *filena int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { + struct ssh_identitylist *agent_ids = NULL; struct ssh_identitylist *auth_ids = NULL; + int agent_fd = -1; int ret; openlog("pam_ssh_agent_auth", 0, LOG_AUTHPRIV); @@ -108,10 +111,13 @@ pam_sm_authenticate(pam_handle_t *pamh, } if (pam_debug) { + const char *auth_socket = getenv(SSH_AUTHSOCKET_ENV_NAME); const char *user = "(unknown)"; pam_get_user(pamh, &user, NULL); syslog(LOG_DEBUG, "USER: %s", user); syslog(LOG_DEBUG, "FILE: %s", auth_file ? auth_file : "(null)"); + auth_socket = auth_socket ? auth_socket : "(null)"; + syslog(LOG_DEBUG, "%s: %s", SSH_AUTHSOCKET_ENV_NAME, auth_socket); } if (auth_file == NULL) { @@ -134,9 +140,34 @@ pam_sm_authenticate(pam_handle_t *pamh, syslog(LOG_DEBUG, " %d) %s", i, auth_ids->comments[i]); } + ret = ssh_get_authentication_socket(&agent_fd); + if (ret) { + syslog(LOG_NOTICE, "agent error: %s", ssh_err(ret)); + ret = PAM_AUTH_ERR; + goto out; + } + + ret = ssh_fetch_identitylist(agent_fd, &agent_ids); + if (ret) { + syslog(LOG_NOTICE, "agent error: %s", ssh_err(ret)); + ret = PAM_AUTH_ERR; + goto out; + } + + if (pam_debug) { + unsigned i; + syslog(LOG_DEBUG, "agent has %u key(s):", (unsigned) agent_ids->nkeys); + for (i=0; i!=agent_ids->nkeys; i++) + syslog(LOG_DEBUG, " %d) %s", i, agent_ids->comments[i]); + } + ret = PAM_SUCCESS; out: + if (agent_fd != -1) + ssh_close_authentication_socket(agent_fd); + if (agent_ids != NULL) + ssh_free_identitylist(agent_ids); if (auth_ids != NULL) ssh_free_identitylist(auth_ids); if (pam_debug) Index: b/regress/pam-ssh-agent.sh ==================================================================--- a/regress/pam-ssh-agent.sh +++ b/regress/pam-ssh-agent.sh @@ -14,6 +14,7 @@ export PAM_WRAPPER_SERVICE_DIR=$OBJ/pam- PAM_SUCCESS=0 PAM_SERVICE_ERR=3 +PAM_AUTH_ERR=7 PAM_AUTHINFO_UNAVAIL=9 . $OBJ/keytype_gen.sh @@ -52,8 +53,31 @@ expect=$PAM_AUTHINFO_UNAVAIL pam_agent_ trace "with empty auth file" expect=$PAM_AUTHINFO_UNAVAIL pam_agent_test file=/dev/null +trace "start agent" +eval `${SSHAGENT} ${EXTRA_AGENT_ARGS} -s` > /dev/null +r=$? +if [ $r -ne 0 ]; then + fatal "could not start ssh-agent: exit code $r" +fi + +trace "load key into the agent" +${SSHADD} -q $OBJ/key.$first_kt +r=$? +if [ $r -ne 0 ]; then + fatal "could not add the key: exit code $r" +fi + trace "authenticate agent (debug)" expect=$PAM_SUCCESS pam_agent_test file=$AUTH_FILE debug trace "authenticate agent (non-debug)" expect=$PAM_SUCCESS pam_agent_test file=$AUTH_FILE + +trace "kill agent" +${SSHAGENT} -k > /dev/null + +trace "agent is gone (debug)" +expect=$PAM_AUTH_ERR pam_agent_test file=$AUTH_FILE debug + +trace "agent is gone (non-debug)" +expect=$PAM_AUTH_ERR pam_agent_test file=$AUTH_FILE
Domenico Andreoli
2020-Jul-21 01:06 UTC
[RFC PATCH 4/4] pam-ssh-agent: Add authenticating the SSH agent
The two key sets, agent and auth, are compared. The matching keys are used to challenge the agent in signing some random data. The first positive proof immediately ends the verification with a success. Tests verify the correct behavior with different auth files. A full round with all the supported key types is also performed. Signed-off-by: Domenico Andreoli <domenico.andreoli at linux.com> --- pam-ssh-agent.c | 33 ++++++++++++++++++++++++++++++++- regress/pam-ssh-agent.sh | 23 +++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) Index: b/pam-ssh-agent.c ==================================================================--- a/pam-ssh-agent.c +++ b/pam-ssh-agent.c @@ -38,6 +38,7 @@ #include "authfile.h" #include "authfd.h" #include "ssherr.h" +#include "sshkey.h" #include "ssh.h" static int pam_debug; @@ -95,6 +96,36 @@ out: return r; } +static int +challenge_agent(int agent_fd, const struct sshkey *agent_key, const struct sshkey *auth_key) +{ + u_char *sig = NULL; + size_t slen = 0; + char data[1024]; + int ret; + + arc4random_buf(data, sizeof(data)); + ret = ssh_agent_sign(agent_fd, agent_key, &sig, &slen, data, sizeof(data), NULL, 0) || + sshkey_verify(auth_key, sig, slen, data, sizeof(data), NULL, 0, NULL); + + if (sig != NULL) + free(sig); + return !ret; +} + +static int +authenticate_agent(int agent_fd, const struct ssh_identitylist *agent_ids, + const struct ssh_identitylist *auth_ids) +{ + unsigned i, j; + for (i=0; i!=agent_ids->nkeys; i++) + for (j=0; j!=auth_ids->nkeys; j++) + if (sshkey_equal(agent_ids->keys[i], auth_ids->keys[j])) + if (challenge_agent(agent_fd, agent_ids->keys[i], auth_ids->keys[j])) + return PAM_SUCCESS; + return PAM_AUTH_ERR; +} + int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { @@ -161,7 +192,7 @@ pam_sm_authenticate(pam_handle_t *pamh, syslog(LOG_DEBUG, " %d) %s", i, agent_ids->comments[i]); } - ret = PAM_SUCCESS; + ret = authenticate_agent(agent_fd, agent_ids, auth_ids); out: if (agent_fd != -1) Index: b/regress/pam-ssh-agent.sh ==================================================================--- a/regress/pam-ssh-agent.sh +++ b/regress/pam-ssh-agent.sh @@ -20,7 +20,9 @@ PAM_AUTHINFO_UNAVAIL=9 . $OBJ/keytype_gen.sh first_kt=`echo $ktypes | cut -d" " -f1` +second_kt=`echo $ktypes | cut -d" " -f2` AUTH_FILE=$OBJ/key.$first_kt.pub +AUTH_FILE2=$OBJ/key.$second_kt.pub pam_agent_test() { @@ -73,6 +75,27 @@ expect=$PAM_SUCCESS pam_agent_ trace "authenticate agent (non-debug)" expect=$PAM_SUCCESS pam_agent_test file=$AUTH_FILE +trace "change of auth file (debug)" +expect=$PAM_AUTH_ERR pam_agent_test file=$AUTH_FILE2 debug + +trace "change of auth file (non-debug)" +expect=$PAM_AUTH_ERR pam_agent_test file=$AUTH_FILE2 + +for kt in $ktypes; do + trace "load key $kt into the agent" + ${SSHADD} -q $OBJ/key.$kt + r=$? + if [ $r -ne 0 ]; then + fatal "could not add the key: exit code $r" + fi + + trace "authenticate agent with $kt (debug)" + expect=$PAM_SUCCESS pam_agent_test file=$OBJ/key.$kt.pub debug + + trace "authenticate agent with $kt (non-debug)" + expect=$PAM_SUCCESS pam_agent_test file=$OBJ/key.$kt.pub +done + trace "kill agent" ${SSHAGENT} -k > /dev/null
Peter Moody
2020-Jul-21 03:24 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
I wrote something a lot like this when I was at uber https://github.com/pmoody-/pam-ussh (the uber version is here: https://github.com/uber/pam-ussh) On Mon, Jul 20, 2020 at 6:29 PM Domenico Andreoli <cavokz at gmail.com> wrote:> > Hi, > > The main (and probably the only) use case of this PAM module is to let > sudo authenticate users via their ssh-agent, therefore without having > to type any password and without being tempted to use the NOPASSWD sudo > option for such convenience. > > The principle is originally implemented by an existing module [0][1] > and many pages that explain how to use it for such purpose can be > found online. > > > Why then this new implementation? > > A few reasons: > - it's way smaller, more simple and easier to audit > - it wants to remain as such > - it reuses everything from openssh-portable; no novel, outdated or > alternative crypto implementations > - it's based on openssh-portable so it supports all the algorithms that > ssh-agent does (eg. ecdsa-sk, ed25519-sk, pkcs#11, ... yuk!) > > > Now, the natural place for this, I think, is right with openssh-portable. > > Is there, maybe, by any chance, a way to merge it there? > > This is a critical piece of software for those who use it and needs > to be well guarded. It has super healthy tests, the maintenance effort > can reimain low and easy. > > > A few things that are missing: > - man page > - installation > - support for multiple keys in the auth file > > > I'm also asking to the Linux PAM people to double-check my usage of PAM. > > Regards, > Domenico > > [0] https://github.com/jbeverly/pam_ssh_agent_auth > [1] https://sourceforge.net/projects/pamsshagentauth/ > > -- > rsa4096: 3B10 0CA1 8674 ACBA B4FE FCD2 CE5B CF17 9960 DE13 > ed25519: FFB4 0CC3 7F2E 091D F7DA 356E CC79 2832 ED38 CB05 > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Nico Kadel-Garcia
2020-Jul-21 04:46 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
On Mon, Jul 20, 2020 at 9:28 PM Domenico Andreoli <cavokz at gmail.com> wrote:> > Hi, > > The main (and probably the only) use case of this PAM module is to let > sudo authenticate users via their ssh-agent, therefore without having > to type any password and without being tempted to use the NOPASSWD sudo > option for such convenience.Why? In order to keep your original agent accessible, you'd have to open up permissions to the socket to the other user without using group membership, namely open it to to the world and maybe hiding it by obscurity. Why wouldn't you simply put the public SSH key in the target account, maybe restricting access to loclahost, and use "ssh -A localhost -l targetaccount".> The principle is originally implemented by an existing module [0][1] > and many pages that explain how to use it for such purpose can be > found online. > > > Why then this new implementation? > > A few reasons: > - it's way smaller, more simple and easier to audit > - it wants to remain as such > - it reuses everything from openssh-portable; no novel, outdated or > alternative crypto implementations > - it's based on openssh-portable so it supports all the algorithms that > ssh-agent does (eg. ecdsa-sk, ed25519-sk, pkcs#11, ... yuk!)Or you can avoid sudo altogether and keep it quite auditable by using public key based access for the target accounts.
Brian Candler
2020-Jul-21 08:20 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
On 21/07/2020 05:46, Nico Kadel-Garcia wrote:> On Mon, Jul 20, 2020 at 9:28 PM Domenico Andreoli<cavokz at gmail.com> wrote: >> Hi, >> >> The main (and probably the only) use case of this PAM module is to let >> sudo authenticate users via their ssh-agent, therefore without having >> to type any password and without being tempted to use the NOPASSWD sudo >> option for such convenience. > Why? In order to keep your original agent accessible, you'd have to > open up permissions to the socket to the other user without using > group membership, namely open it to to the world and maybe hiding it > by obscurity. Why wouldn't you simply put the public SSH key in the > target account, maybe restricting access to loclahost, and use "ssh -A > localhost -l targetaccount". >I don't think the target user requires access to the agent socket - that is, it's normal to be able to sudo from user A to user B, without being able to sudo in turn from user B to user C.? In the case where user B is a daemon account, it probably has no sudo rights anyway.
Domenico Andreoli
2020-Jul-21 09:12 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
On Tue, Jul 21, 2020 at 12:46:40AM -0400, Nico Kadel-Garcia wrote:> On Mon, Jul 20, 2020 at 9:28 PM Domenico Andreoli <cavokz at gmail.com> wrote: > > > > Hi, > > > > The main (and probably the only) use case of this PAM module is to let > > sudo authenticate users via their ssh-agent, therefore without having > > to type any password and without being tempted to use the NOPASSWD sudo > > option for such convenience. > > Why? In order to keep your original agent accessible, you'd have to > open up permissions to the socket to the other user without using > group membership, namely open it to to the world and maybe hiding it > by obscurity. Why wouldn't you simply put the public SSH key in the > target account, maybe restricting access to loclahost, and use "ssh -A > localhost -l targetaccount".Nice. I never fully realized but the same idea was clearly lurking in the sub-conscious while I was working at this in these past days. It was clear to me that for switching to any user except root, ssh -l would be the easiest way. That's why I did not have any plan for adding tilde expansion or any other complexity for reaching the auth file. But still, these held in my conscious: 1. I use sudo mostly to become root 2. PermitRootLogin=no 3. Using 'ssh localhost' adds 'something between' 4. I use sudo -E to feel really at home 5. I use sudo NOPASSWD Although I'm admin of just my laptop, I always knew that #5 is really bad and dropping it (and throw U2F/FIDO in the mix) is the main motivation of the work I've just presented. In trying your approach I discovered that actually #2 is wrong, nowadays default is PermitRootLogin=prohibit-password and my sshd_config does not override it. I don't have any good reason to set it back either. #3 is also quite moot but dropping it actually helped me to realize #4, honestly not much less nasty than #5. Now I'll go fixing my 'laptops', I never adopted #5 on sensitive ones but still #4 needs a proper killing. What to say? Your solution is clearly superior and highlighted a bad habit, so I thank you for sharing it. I've to say I liked the idea of contributing to openssh. I digested quite a number of linking errors while searching my way to reuse most of what's aready there and now I've a certain 'feeling' of how things are. Is there any 'good first issue' I could work on to keep the momentum? Dom -- rsa4096: 3B10 0CA1 8674 ACBA B4FE FCD2 CE5B CF17 9960 DE13 ed25519: FFB4 0CC3 7F2E 091D F7DA 356E CC79 2832 ED38 CB05
Domenico Andreoli
2020-Jul-21 11:25 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
On Mon, Jul 20, 2020 at 08:24:45PM -0700, Peter Moody wrote:> I wrote something a lot like this when I was at uber > > https://github.com/pmoody-/pam-ussh > > (the uber version is here: https://github.com/uber/pam-ussh)Needing PAM auth via ssh-agent is not so uncommon and yet using sshd is not necessarily the first (or best) solution to come to mind. Having it available as part of openssh would be a useful bridgehead for educating users towards better solutions, when available, and anyway practically improve the security of the status quo. Superior solutions are not very useful if not widely adopted. Dom -- rsa4096: 3B10 0CA1 8674 ACBA B4FE FCD2 CE5B CF17 9960 DE13 ed25519: FFB4 0CC3 7F2E 091D F7DA 356E CC79 2832 ED38 CB05
Domenico Andreoli
2020-Jul-22 19:50 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
On Tue, Jul 21, 2020 at 12:46:40AM -0400, Nico Kadel-Garcia wrote:> On Mon, Jul 20, 2020 at 9:28 PM Domenico Andreoli <cavokz at gmail.com> wrote: > > > > Hi, > > > > The main (and probably the only) use case of this PAM module is to let > > sudo authenticate users via their ssh-agent, therefore without having > > to type any password and without being tempted to use the NOPASSWD sudo > > option for such convenience. > > Why? In order to keep your original agent accessible, you'd have to > open up permissions to the socket to the other user without using > group membership, namely open it to to the world and maybe hiding it > by obscurity. Why wouldn't you simply put the public SSH key in the > target account, maybe restricting access to loclahost, and use "ssh -A > localhost -l targetaccount".Can sshd cache the credentials as sudo does? Or should I push the button of my Solo key every single time I want to become root?> > The principle is originally implemented by an existing module [0][1] > > and many pages that explain how to use it for such purpose can be > > found online. > > > > > > Why then this new implementation? > > > > A few reasons: > > - it's way smaller, more simple and easier to audit > > - it wants to remain as such > > - it reuses everything from openssh-portable; no novel, outdated or > > alternative crypto implementations > > - it's based on openssh-portable so it supports all the algorithms that > > ssh-agent does (eg. ecdsa-sk, ed25519-sk, pkcs#11, ... yuk!) > > Or you can avoid sudo altogether and keep it quite auditable by using > public key based access for the target accounts.sudo is not going away any time soon and neither ssh-agent, they need to coexist in the same toolbox and play well together. Dom -- rsa4096: 3B10 0CA1 8674 ACBA B4FE FCD2 CE5B CF17 9960 DE13 ed25519: FFB4 0CC3 7F2E 091D F7DA 356E CC79 2832 ED38 CB05
Jakub Jelen
2020-Aug-03 10:51 UTC
[RFC PATCH 0/4] PAM module for ssh-agent user authentication
On Tue, 2020-07-21 at 03:06 +0200, Domenico Andreoli wrote:> Hi, > > The main (and probably the only) use case of this PAM module is to > let > sudo authenticate users via their ssh-agent, therefore without having > to type any password and without being tempted to use the NOPASSWD > sudo > option for such convenience. > > The principle is originally implemented by an existing module [0][1] > and many pages that explain how to use it for such purpose can be > found online.I really like this idea of pam_ssh_agent_auth living inside of openssh repository. We are building these two together in Fedora and RHEL for ages, mostly for the feature-parity. Regards, -- Jakub Jelen Senior Software Engineer Security Technologies Red Hat, Inc.