SSH Client and pam Module on CentOS 7

Hell everybody,

we are using privacyIDEA 3.2.1 and i’m trying to setup SSH Key Management.

In privacyID3A everything is ready: User Resolver, Realm, Host Resolver, Hosts, SSH Key.

On the client is privacyideaadm for python3 installed (via git) and after some error message suppressing, it can pull the keys from the server:

#!/bin/bash
/opt/rh/rh-python36/root/usr/bin/privacyidea-authorizedkeys $1 2>&1 | grep -v "^/opt/rh/rh-python36/" | grep -v InsecureRequestWarning

/usr/local/bin/getauthkeys root
ssh-rsa......

So this works. Now i trying to setup the 2FA on a Centos 7 machine.

Therefor i installed first pam_python from https://github.com/privacyidea/pam_python and pam-python-1.0.7.

The installation was easy, i just needed to install some more packages like sphinx or pam-devel, but in the end i’ve got a pam_python.so for my PAM System.

Now i’m stuck at the usage of the PAM module and sshd:

In /etc/pam.d/sshd i have:

#%PAM-1.0
auth       required     pam_sepermit.so
auth       substack     password-auth
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare
auth        requisite    pam_python.so /opt/pam_python/build/lib/privacyidea_pam.py url=https://otp-server nosslverify prompt=privacyIDEA_Authentication debug

In my sshd_config:

Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTH
LogLevel INFO
PermitRootLogin yes
ChallengeResponseAuthentication no
PasswordAuthentication yes
PubkeyAuthentication yes
StrictModes no
IgnoreRhosts yes
PermitEmptyPasswords no
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com
MACs hmac-sha1-etm@openssh.com,umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160
X11Forwarding yes
X11UseLocalhost yes
AllowTcpForwarding yes
PrintMotd no
MaxAuthTries 12
MaxStartups 100
Subsystem	sftp	/usr/local_rwth/sbin/sftp-server
ClientAliveInterval 60
AcceptEnv XAUTHORITY REMOTEUSER REAL_USERNAME GRSH_TASK_ID PRIVATE_* R_SKIP_PROFILES
AllowUsers root *@localhost *@machine
AuthorizedKeysFile none
AuthorizedKeysCommandUser nobody
AuthorizedKeysCommand /usr/local/bin/getauthkeys

But sshd does not ask for my otp. Is something wrong in my configuration? Did i miss a step?

Regards

Stephan

Hello Stephan,

You need to get clear about what you actually want to achieve! You are mixing up two topics here:

  1. SSH key authentication with sshd and
  2. OTP authentication with sshd.

I am not really familiar with the Cent OS PAM Stack.
But it looks like you are including the “normal” authentication via

auth    substack  password-auth

so probably your

auth pam_python.so

later might have no effect.
You should investigate in this direction!

Also, each distribution has a log file like /var/log/auth.log, that logs the results of the PAM stack which helps me a lot in those cases.

Regards
Cornelius

Hello Cornelius,

i’m trying to achieve 2 things:

  1. SSH Key Management via privacyIDE3A [done]
  2. 2FA/MFA via SSH

So the user can login with SSH Key and as a second factor one of the multiple OTP tokens.

In my /etc/pam.d/sshd is now:

#%PAM-1.0
auth       required     pam_sepermit.so
#auth       substack     password-auth
auth       required     pam_python.so /opt/pam_python/build/lib/privacyidea_pam.py url=https://otp-test.itc.rwth-aachen.de nosslverify prompt=privacyIDEA_Authentication debug
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare

So it should ask for the OTP after login, right?

UPDATE

the /etc/pam.d/sshd references /etc/pam.d/password-auth, so i tried the following in password-auth:

#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        required      pam_faildelay.so delay=2000000
#auth        sufficient    pam_unix.so nullok try_first_pass
auth        sufficient    pam_python.so /usr/lib/python2.7/site-packages/privacyidea_pam-2.11dev0-py2.7.egg/privacyidea_pam.py url=https://otp-test.itc.rwth-aachen.de nosslverify prompt=privacyIDEA_Authentication debug
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     required      pam_permit.so

password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok


password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so

In my log is now the following error:

Jan 22 13:39:56 otp-test /usr/lib/python2.7/site-packages/privacyidea_pam-2.11dev0-py2.7.egg/privacyidea_pam.py[16846]: Traceback (most recent call last):
Jan 22 13:39:56 otp-test /usr/lib/python2.7/site-packages/privacyidea_pam-2.11dev0-py2.7.egg/privacyidea_pam.py[16846]:   File "/usr/lib/python2.7/site-packages/privacyidea_pam-2.11dev0-py2.7.egg/privacyidea_pam.py", line 44, in <module>
Jan 22 13:39:56 otp-test /usr/lib/python2.7/site-packages/privacyidea_pam-2.11dev0-py2.7.egg/privacyidea_pam.py[16846]:     import requests
Jan 22 13:39:56 otp-test /usr/lib/python2.7/site-packages/privacyidea_pam-2.11dev0-py2.7.egg/privacyidea_pam.py[16846]: ImportError: No module named requests

But the “requests” module is installed:

pip install requests
Requirement already satisfied (use --upgrade to upgrade): requests in /usr/lib/python2.7/site-packages

I’m using pam_python.so 1.0.7 and the latest privacyidea_pam.py

We’re seeing the same problem, there seems to be a mismatch between sys.path in the interactive Python interpreter and what pam_python uses:

pam_python:

['/usr/lib64/python27.zip', '/usr/lib64/python2.7/', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload']

python:

['', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/gtk-2.0', '/usr/lib/python2.7/site-packages']

In particular the last path /usr/lib/python2.7/site-packages, which is the one where pip installed packages to.

I suppose it is due to the flag defined here:
https://sourceforge.net/p/pam-python/code/ci/default/tree/src/pam_python.c#l93

See also https://sourceforge.net/p/pam-python/tickets/8/#0001/7b91/dea5/0aab/32b1/34ac/8881/b469

I’ve added an issue on GitHub:

I ran into the same issue with the import statements. Following the thread here and on sourceforge, I ended up using the following workaround:

I installed privacyidea into is own python3 virtual environment. Within that venv, I noted the path where the site-packages were installed and then edited privacyidea_pam.py as follows:

Add the following lines above the import section
import site
import sys
site.addsitedir('/opt/xxx/privacyidea/pam_python/lib/python3.6/site-packages')

#the addsitedir line is the path to your site-packages
#it is also where I created my python venv

...import blah # the rest of the original import statements can then follow

This has worked for me. I know it’s not a “forever” solution, but since it is in its own virtual environment, it should be stable until a more permanent fix is made. I hope it helps someone