google / google-authenticator-libpam

Apache License 2.0
1.75k stars 280 forks source link

Add notes on ssh server config to README regarding AuthenticationMethods and keys #209

Closed danboid closed 2 years ago

danboid commented 2 years ago

I am currently struggling to correctly configure my ssh server + PAM for use with GA. The main area of uncertainty for me relates to configuring ssh's AuthenticationMethods option. As far as sshd is concerned, what is GA's verification code classed as? I would presume it is either keyboard-interactive or keyboard-interactive:pam?

So, if I want users outside of our network subnet to be forced to enter a verification code and their password, how would I configure ssh's AuthenticationMethods option? I don't want users on our LAN to be asked for a verification code.

The other area where I'm at a loss is how do ssh keys factor in? Must I disable ssh keys on the ssh server for verification codes to work? That doesn't seem to be the case. So far I've only had GA work with AuthenticationMethods commented out and that was with a user who had a ssh key configured so in that case GA/PAM/SSH seemed to ignore the users key. Would it be possible to allow ssh keys to work on our LAN subnet but not for external users? Is it not feasible to mix ssh keys and OTP codes?

It seems to me that if I try ssh'ing into an account that doesn't have an OTP secret key set up but GA in configure in PAM I get prompted for a password but its a non-functional password prompt that fails when I enter my correct password before prompting me again. Is this a known bug? I'd prefer it error rather than do this.

Apart from these murky areas, I THINK I know how I'm supposed to correctly configure GA/PAM/SSH for my needs but if you have a guide you'd recommend then maybe that should be linked in the README too?

These experiences are relating to Ubuntu 20.04.

ThomasHabets commented 2 years ago

As far as sshd is concerned, what is GA's verification code classed as? I would presume it is either keyboard-interactive or keyboard-interactive:pam?

Yeah. That's an OpenSSH question, but I think either, yes. Should be easy enough to just experiment and see what triggers PAM.

So, if I want users outside of our network subnet to be forced to enter a verification code and their password, how would I configure ssh's AuthenticationMethods option? I don't want users on our LAN to be asked for a verification code.

You need to find a PAM module that checks client networks, and has "success" mean "skip next rule". I don't know the name of such a module, but that's what you need.

See the PAM manpages for how to make the rule that make success mean "skip next rule".

The other area where I'm at a loss is how do ssh keys factor in? Must I disable ssh keys on the ssh server for verification codes to work?

Depends how you specify AuthenticationMethods in SSH. It can accept one or the other, or both, or whatever combination you want.

Would it be possible to allow ssh keys to work on our LAN subnet but not for external users?

OpenSSH config option Match can customize AuthenticationMethods per client network, yes.

Is it not feasible to mix ssh keys and OTP codes?

In many many ways, yes. I don't know exactly what you want, but should be possible. None of this is Google Authenticator questions though, it's all about OpenSSH and PAM.

It seems to me that if I try ssh'ing into an account that doesn't have an OTP secret key set up but GA in configure in PAM I get prompted for a password but its a non-functional password prompt that fails when I enter my correct password before prompting me again. Is this a known bug? I'd prefer it error rather than do this.

It's not a bug. It depends entirely on how you configure it.

if you have a guide you'd recommend

The guide I'd recommend is the current README. Everything past that has too many "well, depends what you want". Yes, ideally there should be a general guide for how to combine passwords, OTP, and SSH keys. But it's out of scope for this project to write that. And if SSH keys it depends on if the key is a hardware or software key.

Personally my recommendation for SSH logins is a yubikey in PIV mode. Even works with Windows clients.

danboid commented 2 years ago

Thanks for your quick response Thomas!

You say these are SSH/PAM questions but I'd imagine most people are configuring GA for use with ssh and the ssh man pages don't mention GA hence my suggestion for covering FAQs relating to ssh in the GA docs. It wouldn't make sense (to me) to try asking the ssh devs to cover GA config in their docs.

I have tried using both:

AuthenticationMethods keyboard-interactive,password

and

AuthenticationMethods keyboard-interactive:pam,password

but ssh stops working with either of those.

I am prepared to sacrifice the use of ssh keys just to keep our config simple because I find PAM utterly bewildering to be honest.

The server I'm trying to configure for use with GA is using LDAP so on our LAN I just want users to have to enter their LDAP password but off site I want them to have to enter a verification code as well as their LDAP password but I need auth to work with the local user accounts on server too. Thats as simple as I can make it if we are going to use GA. If I don't get GA working then we'll have to revoke external ssh access.

Could you please have a quick look at my config to see if you can spot any errors as my head is melting reading the PAM docs :) ?

#   $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

Include /etc/ssh/sshd_config.d/*.conf

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication yes

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

# override default of no subsystems
Subsystem sftp  /usr/lib/openssh/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
#   X11Forwarding no
#   AllowTcpForwarding no
#   PermitTTY no
#   ForceCommand cvs server
#AuthenticationMethods keyboard-interactive,password
# cat /etc/pam.d/sshd 
# PAM configuration for the Secure Shell service
auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/campus.conf
auth      required  pam_google_authenticator.so
# Standard Un*x authentication.
@include common-auth

# Disallow non-root logins when /etc/nologin exists.
account    required     pam_nologin.so

# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
# account  required     pam_access.so

# Standard Un*x authorization.
@include common-account

# SELinux needs to be the first session rule.  This ensures that any
# lingering context has been cleared.  Without this it is possible that a
# module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so close

# Set the loginuid process attribute.
session    required     pam_loginuid.so

# Create a new session keyring.
session    optional     pam_keyinit.so force revoke

# Standard Un*x session setup and teardown.
@include common-session

# Print the message of the day upon successful login.
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session    optional     pam_motd.so  motd=/run/motd.dynamic
session    optional     pam_motd.so noupdate

# Print the status of the user's mailbox upon successful login.
session    optional     pam_mail.so standard noenv # [1]

# Set up user limits from /etc/security/limits.conf.
session    required     pam_limits.so

# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
session    required     pam_env.so # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
session    required     pam_env.so user_readenv=1 envfile=/etc/default/locale
# SELinux needs to intervene at login time to ensure that the process starts
# in the proper default security context.  Only sessions which are intended
# to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so open
# Standard Un*x password updating.
@include common-password
# cat /etc/security/campus.conf
# Only allow IPs from campus LAN
+ : ALL : LANSUBNETHERE
# Additional network: VPN tunnel IP range
#+ : ALL : ANOTHERNETWORK
+ : ALL : LOCAL
- : ALL : ALL
# cat /etc/pam.d/sshd 
# PAM configuration for the Secure Shell service
auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/campus.conf
auth      required  pam_google_authenticator.so
# Standard Un*x authentication.
@include common-auth

# Disallow non-root logins when /etc/nologin exists.
account    required     pam_nologin.so

# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
# account  required     pam_access.so

# Standard Un*x authorization.
@include common-account

# SELinux needs to be the first session rule.  This ensures that any
# lingering context has been cleared.  Without this it is possible that a
# module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so close

# Set the loginuid process attribute.
session    required     pam_loginuid.so

# Create a new session keyring.
session    optional     pam_keyinit.so force revoke

# Standard Un*x session setup and teardown.
@include common-session

# Print the message of the day upon successful login.
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session    optional     pam_motd.so  motd=/run/motd.dynamic
session    optional     pam_motd.so noupdate

# Print the status of the user's mailbox upon successful login.
session    optional     pam_mail.so standard noenv # [1]

# Set up user limits from /etc/security/limits.conf.
session    required     pam_limits.so

# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
session    required     pam_env.so # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
session    required     pam_env.so user_readenv=1 envfile=/etc/default/locale
# SELinux needs to intervene at login time to ensure that the process starts
# in the proper default security context.  Only sessions which are intended
# to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so open
# Standard Un*x password updating.
@include common-password
# cat /etc/pam.d/common-auth 
#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
# traditional Unix authentication mechanisms.
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules.  See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
auth    [success=2 default=ignore]  pam_unix.so nullok
auth    [success=1 default=ignore]  pam_ldap.so minimum_uid=1000 use_first_pass
# here's the fallback if no module succeeds
auth    requisite           pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required            pam_permit.so
# and here are more per-package modules (the "Additional" block)
auth    optional            pam_cap.so 
# end of pam-auth-update config

LDAP login was working fine until I tried to introduce GA but now I'm lost in PAM hell.

I probably need to change pam_unix or pam_ldap to required and I don't think I want the nullok option either?

Thanks Thomas!

danboid commented 2 years ago

Also, there is this option:

-d, --disallow-reuse           Disallow reuse of previously used TOTP tokens

Is this just for the 'recovery' tokens or does it mean re-using the secret key? How does GA know when a token has already been used ie where is the file that caches token use? If a user creates a key using -d, can they only login once with it?

Because I am unable to configure AuthenticationMethods, I have to explicitly disable ssh keys for GA to work.

ThomasHabets commented 2 years ago

AuthenticationMethods keyboard-interactive,password

That doesn't look right. password? keyboard-interactive already deals with password, right? So here you're saying password+password?

I would guess that it should be more like:

# Default: need both publickey and keyboard-interactive
AuthenticationMethods publickey,keyboard-interactive

# From LAN: only password
Match Address 10.0.0.0/8
  AuthenticationMethods keyboard-interactive

But I don't know. I'm only aware of these features. I've not set them up enough to actually know the syntax by heart.

auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/campus.conf

I dunno. Looks about right. Skip GA if from campus.

ThomasHabets commented 2 years ago

The "disallow reuse" option by default asked:

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) 
danboid commented 2 years ago

That doesn't look right. password? keyboard-interactive already deals with password, right? So here you're saying password+password?

What I'm trying to say here is users need to enter the GA verification code and their LDAP password. From what I've read:

The available authentication methods are: gssapi-with-mic, hostbased, keyboard-interactive, none (used for access to password-less accounts when PermitEmptyPassword is enabled),, password, and publickey.

Those would seem to be my options so you're saying I should only need to list keyboard-interactive and that covers both the verification code and their LDAP (or local?) password being correct?

ThomasHabets commented 2 years ago

Again, keyboard-interactive activates PAM and therefore password. I believe password manually checks /etc/shadow. I don't think you ever want to use password on a Linux system.

But I'm not an expert on that. These are questions for OpenSSH and PAM people.

danboid commented 2 years ago

It seems that disabling ssh pubkey auth and then using ssh's Match Address with a couple of comma separated subnets has done the trick for me without having to use any AuthenticationMethod config.