"Semi-Trusted" SSH-Keys that also require PAM login

raf ssh at raf.org
Thu Oct 22 09:47:56 AEDT 2020


On Wed, Oct 21, 2020 at 03:05:38PM +0200, Jan Bergner <jan.bergner at indurad.com> wrote:

> Hello all,
> 
> in order to connect to my SSH servers from untrusted devices like company computers or my smartphone, I set up 2FA with
> google-authenticator hooked into PAM.
> 
> However, this is not really 2FA at least for the smartphone, since I use the same device for generating the TANs and it
> is also at least inconvenient to always require a new TAN for each connection. I do not want to solely rely on SSH keys
> on these devices since - as I pointed out - I do not really trust them.
> 
> So, my idea was to use SSH keys but to also require the server's PAM login for these "semi-trusted" keys. But of course,
> I want to trust the keys on my own laptop and desktop without an additional PAM password. Therefore, I cannot simply use
> something like
> 
> AuthenticationMethods publickey,password
> 
> I want to be able to specify this per key. Right now, I do a work-around by specifying
> 
> command="/usr/bin/sudo /bin/login myusername"
> 
> for the "semi-trusted" keys in the login users' authorized_keys, but this has issues when using scp or rsync. (As I
> understand, they execute some kind of remote shell or remote daemon, which is overwritten by the command-directive.
> Unfortunately, this is where my expertise finds its limits and therefore, I was wondering whether anyone already had
> a similar problem and found a solution or whether anyone would have an idea on how to proceed.
> 
> My thoughts go in the direction of still using authorized_keys and do something like
> 
> command="/verify/pam/login/or/whatever/via/some/script.sh && $SSH_ORIGINAL_COMMAND"
> 
> to use a script for external verification (allowing for any kind of additional checking, including PAM, but with a
> different configuration) and then continue the normal execution.
> Unfortunately, this has not worked for me.
> 
> 
> So, is there any solution for this? Might it be as simple as using a different environment variable that I am simply not
> aware of? Or could there be an entirely different approach? (Again, I want this for normal login, scp and rsync at
> least.)
> 
> Thanks to all and best regards,
> 
> Jan

I can't answer your question, but if you do get this
working this way, make sure that you don't explicitly
use $SSH_ORIGINAL_COMMAND in the command parameter.
That's never the right thing to do. If you do, it will
be re-evaluated by the user's login shell an extra time
before it is finally evaluated and executed, which will
often not do what you want.

Whatever command you put in the command parameter
should just inherit SSH_ORIGINAL_COMMAND in its
environment, without an additional round of shell
evaluation, and then, if the extra validation passes,
perform the equivalent of:

  execv('/path/to/sh', ['sh', '-c', env('SSH_ORIGINAL_COMMAND')])

where the sh is the user's login shell (or /bin/sh if
there isn't a login shell listed in /etc/passwd).

This way, the original command will be executed exactly
as ssh would have done it, and so will be able to
support any original command.

cheers,
raf

P.S. If you only want the semi-trusted keys to be able
to execute a particular fixed set of arbitrary commands
(e.g. cronjobs), then an ssh command whitelisting tool
might meet your needs. Examples are:

  https://github.com/raforg/sshdo (auto-learn/unlearn, exact commands only)
  https://github.com/daethnir/authprogs (manual config, supports regexps)

But these won't help if those keys need to be used for
arbitrary unpredictable commands (e.g. humans).



More information about the openssh-unix-dev mailing list