This post documents how to set up a secure OpenLDAP server that is able to make OpenLDAP client servers accept authorized SSH access requests from users. The following steps assume the OpenLDAP server (slapd) and phpLDAPadmin are installed as referenced in the initial setup.
Instructions and references
- Initial setup
- OpenSSH-LPK and ssh-ldap-pubkey (on LDAP clients)
- Force authentication
- Secure LDAP with SSL/TLS
Understanding cn=config (LDAP database)
The default installation of OpenLDAP in recent versions of Ubuntu uses the new runtime configuration (RTC) system or olc (OpenLDAP Configuration). This installation uses cn=config (the LDAP database) for configuration rather than the old style slapd.conf.
Schemas
The schemas can be imported dynamically into cn=config database, without restarting slapd. The schemas to be imported can placed in /etc/ldap/schema.
The following schema in ldif format will be used and discussed in the subsequent sections:
- openssh-lpk.ldif
- ldap_disable_bind_anon.ldif
- ssl.ldif
Importing openssh-lpk scheme
ldapadd -Y EXTERNAL -H ldapi:/// -f openssh-lpk.ldif
where openssh-lpk.ldif is:
dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
DESC 'MANDATORY: OpenSSH Public key'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
DESC 'MANDATORY: OpenSSH LPK objectclass'
MAY ( sshPublicKey $ uid )
)
Forcing authentication
By default, OpenLDAP allows anonymous query from any client servers. You may want to enable authentication so that only authenticated clients are able to query the server:
ldapadd -Y EXTERNAL -H ldapi:/// -f ldap_disable_bind_anon.ldif
where ldap_disable_bind_anon.ldif is:
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon
dn: cn=config
changetype: modify
add: olcRequires
olcRequires: authc
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcRequires
olcRequires: authc
Securing LDAP with TLS
- Install the package that provides certtool:
apt-get install gnutls-bin
- Generate new certificate (self-signed) and key:
mkdir -p /etc/ldap/gnutls
cd /etc/ldap/gnutls
certtool --generate-self-signed --load-privkey ldap.gnutls.key --outfile ldap.gnutls.crt - Fix permission of private key:
chmod+r/etc/ldap/gnutls/ldap.gnutls.key
Importing SSL schema
ldapmodify -Y EXTERNAL -H ldapi:/// -f ssl.ldif
where ssl.ldif is:
dn: cn=config
changetype: Modify
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/gnutls/ldap.gnutls.key
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/gnutls/ldap.gnutls.crt
-
add: olcTLSCipherSuite
olcTLSCipherSuite: NORMAL
-
add: olcTLSCRLCheck
olcTLSCRLCheck: none
-
add: olcTLSVerifyClient
olcTLSVerifyClient: never
Enabling LDAPS
By default, only ldap and ldapi (Unix domain socket) are enabled. Make ldaplisten to only 127.0.0.1 and keep the latter so that you can run ldap utilty commands against ldapi:/// without providing credentials if working on the same server.
Edit /etc/default/slapd and ensure the following line:
SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///"
Configuring /etc/ldap/ldap.conf
Edit /etc/ldap/ldap.conf and add the following line:
TLS_REQCERT never
Testing the above LDAPS config
ldapsearch -d 9 -D "cn=Bob,ou=users,dc=example,dc=com" \
-w password -b "dc=example,dc=com" -H "ldaps://ldap.example.org""objectClass=*"
Customizing phpLDAPadmin config and templates
You can customize template configurations (/etc/phpldapadmin/config.php).
For example, change the base uid and gid to a greater value:
$servers->setValue('auto_number','min',array('uidNumber'=>3000,'gidNumber'=>3000));
Add
$config->custom->appearance['theme'] = 'tango';
You can also customize templates for various components, for example, POSIX account:
- /etc/phpldapadmin/templates/creation/posixAccount.xml
Customize themes and styles:
- /usr/share/phpldapadmin/lib/page.php
- /usr/share/phpldapadmin/htdocs/css/tango/style.css
Adding a user with SSH public key in phpLDAPadmin
First, create a user with the “Generic: User Account” template. Then, go to the “objectClass” attribute section, click “add value”, and choose the “ldapPublicKey” attribute. After you submit, go back to the user edit page, click “Add new attribute” on the top part, and choose “sshPublicKey”, paste the public key into the text area, and finally click “Update Object”.
----------------
Setting up OpenLDAP client with SSH access on Ubuntu 14.04
This post documents how to set up an OpenLDAP client server (Ubuntu 14.04) that can make its OpenSSH server to load authorized keys from a pre-configured OpenLDAP server with ldaps:// available (discussed in the above post, please read this first if you haven’t). Users are able to SSH access this client server, while their SSH public keys are stored on the OpenLDAP server. The SSH authentication process on the client server is mainly facilitated by ssh-ldap-pubkey.
Install packages
apt-get -y install libpam-ldap nscd ldap-utils
apt-get -y install python-pip python-ldap
# https://github.com/jirutka/ssh-ldap-pubkey
pip install ssh-ldap-pubkey
Configure SSH server
- Add the following lines to /etc/ssh/sshd_config:
AuthorizedKeysCommand /usr/local/bin/ssh-ldap-pubkey-wrapper
AuthorizedKeysCommandUser nobody - Restart SSH server
service ssh restart
Configure PAM
- Edit /etc/ldap.conf:
uri ldaps://ldap.example.com
binddn cn=OpenLDAP Client,ou=users,dc=example,dc=com
bindpw password - Edit /etc/pam.d/common-auth and add the following line:
account required pam_access.so
- Edit /etc/pam.d/common-password and remove use_authtok parameter
- Edit /etc/pam.d/common-session and add the following line:
session required pam_mkhomedir.so skel=/etc/skel umask=0022
Configure NSS, login access control and sudo
- Edit /etc/nsswitch.conf:
passwd: compat ldap
group: compat ldap
shadow: compat ldap - Edit /etc/security/access.conf, replace ldap-team with actual group name:
- : ALL EXCEPT root (admin) (wheel) (ldap-team): ALL EXCEPT LOCAL
- Edit /etc/sudoers using visudo command and add the following lines. Replace ldap-team with actual group name:
%ldap-team ALL=(ALL) ALL
- Restart nscd
service nscd restart
附录:setup-ldap-client.sh:
#!/bin/bash
----------------------------------
# vim: softtabstop=4 shiftwidth=4 expandtab fenc=utf-8 spell spelllang=en cc=120
set -e
# Check Ubuntu release
[ "$(lsb_release -sc)" = "trusty" ] || {
echo 'This script should be run on Ubuntu 14.04.'>&2
exit 1
}
# LDAP group name of team members to be granted access on this server,
LDAP_TEAM_NAME=$1
LDAP_BASE="dc=example,dc=com"
LDAP_URI="ldaps://ldap.example.com"
LDAP_BINDDN="cn=OpenLDAP Client,ou=users,dc=example,dc=com"
LDAP_BINDPW="password"
USAGE="usage: ./$(basename $0) LDAP_TEAM_NAME"
# Check required positional parameters
[ $# -ne 1 ] && {
echo "$USAGE">&2
exit 1
}
# Install required packages
export DEBIAN_FRONTEND=noninteractive
# The following command will implicitly install libnss-ldap
apt-get -y install libpam-ldap nscd ldap-utils
apt-get -y install python-pip python-ldap
pip install ssh-ldap-pubkey
# Configure SSH server
grep 'AuthorizedKeysCommand' /etc/ssh/sshd_config > /dev/null || {
cat >> /etc/ssh/sshd_config <<EOF
AuthorizedKeysCommand /usr/local/bin/ssh-ldap-pubkey-wrapper
AuthorizedKeysCommandUser nobody
EOF
}
#Restart SSH server
service ssh restart
# Edit /etc/ldap.conf
mv /etc/ldap.conf /etc/ldap.conf.bak
cat > /etc/ldap.conf <<EOF
base $LDAP_BASE
uri $LDAP_URI
ldap_version 3
binddn $LDAP_BINDDN
bindpw $LDAP_BINDPW
pam_password md5
nss_initgroups_ignoreusers backup,bin,daemon,games,gnats,irc,landscape,libuuid,list,lp,mail,man,messagebus,news,pollinate,proxy,root,sshd,sync,sys,syslog,uucp,www-data
bind_timelimit 3
timelimit 3
EOF
# Edit /etc/ldap/ldap.conf
cp /etc/ldap/ldap.conf /etc/ldap/ldap.conf.bak
grep 'TLS_REQCERT' /etc/ldap/ldap.conf > /dev/null || {
cat >> /etc/ldap/ldap.conf <<EOF
TLS_REQCERT never
EOF
}
# Configure PAM
# Add pam_access.so
grep 'pam_access.so' /etc/pam.d/common-auth > /dev/null || {
cat >> /etc/pam.d/common-auth <<EOF
account required pam_access.so
EOF
}
# Remove use_authtok from /etc/pam.d/common-password
sed -i -r 's/(.*)(use_authtok)(.*)/\1\3/g' /etc/pam.d/common-password
# Add pam_mkhomedir.so
grep 'pam_mkhomedir.so' /etc/pam.d/common-session > /dev/null || {
cat >> /etc/pam.d/common-session <<EOF
session required pam_mkhomedir.so skel=/etc/skel umask=0022
EOF
}
# Configure NSS
sed -i -r 's/(^passwd:)(\s+)(.*)/\1\2compat ldap/' /etc/nsswitch.conf
sed -i -r 's/(^group:)(\s+)(.*)/\1\2compat ldap/' /etc/nsswitch.conf
sed -i -r 's/(^shadow:)(\s+)(.*)/\1\2compat ldap/' /etc/nsswitch.conf
# Edit /etc/security/access.conf
grep -- '^- : ALL EXCEPT root' /etc/security/access.conf > /dev/null || {
cat >> /etc/security/access.conf <<EOF
+ : ($LDAP_TEAM_NAME) : ALL
- : ALL EXCEPT root (admin) (wheel) : ALL EXCEPT LOCAL
EOF
}
# Edit /etc/sudoers
grep -F -- "%$LDAP_TEAM_NAME" /etc/sudoers > /dev/null || {
cat >> /etc/sudoers <<EOF
%$LDAP_TEAM_NAME ALL=(ALL) ALL
EOF
}
# Restart nscd
service nscd restart
Setting up nss-ldapd on Ubuntu 14.04
The last few posts discussed ‘setting up an OpenLDAP server’ and ‘configuring basic client server’. However, that client server uses nss-ldap with some known issues as presented here. With this old and seemingly buggy setup, I simply can’t make nss_initgroups_ignoreuses option work to bypass querying the LDAP server when authenticating local or system users on the server, and have no idea what nssldap-update-ignoreusers command actually does. When the LDAP server is down or there is network issues connecting the LDAP server, the default configuration will simply block local users from logging in the server (at least for a long time until the query is considered timed out). Also, as I found after checking /var/log/auth.log, it queries the LDAP server even when doing a Bash completion, because it was very slow when I pressed the TAB key after a path name. Setting bind_policy option to soft and timelimit and bind_timelimit to smaller values may just alleviate the symptom but does not solve the problem.
So I decide to use nss-ldapd that comes with the libnss-ldapd package.apt-get install libpam-ldap nscd ldap-utils libnss-ldapd
Running the above command will automatically remove the libnss-ldap package and prompt interacive post-install steps for you to configure the LDAP parameters. You can disable this interactive behavior and directly place your config in /etc/nslcd.conf with the following command:export DEBIAN_FRONTEND=noninteractive
apt-get -y install libpam-ldap nscd ldap-utils libnss-ldapdThen, put your config in /etc/nslcd.conf:uid nslcd
gid nslcd
uri ldaps://ldap.example.com
base dc=example,dc=com
binddn cn=OpenLDAP Client,ou=users,dc=example,dc=com
bindpw password
tls_reqcert never
nss_initgroups_ignoreusers ALLLOCAL
bind_timelimit 3
timelimit 3The last line nss_initgroups_ignoreusers ALLLOCAL prevents group membership lookups through LDAP for all local users.The remaining settings for PAM, sudoers and access.conf are essentially the same as the old nss-ldap setup. Just make sure to restart the LDAP nameservice daemon, nslcd, after making changes to /etc/nslcd.conf:service nslcd restart
If nscd cache daemon is also enabled and you make some changes to the user from the LDAP, you may want to clear the cache:nscd--invalidate=passwd
nscd--invalidate=groupThe nslcd daemon also has the advantage that it can be easily stopped in order to temporarily disable the LDAP lookup. This makes the management of LDAP access more easy.Finally, here is the setup script:#!/bin/bash
# vim: softtabstop=4 shiftwidth=4 expandtab fenc=utf-8 spell spelllang=en cc=120
set -e
# Check Ubuntu release
[ "$(lsb_release -sc)" = "trusty" ] || {
echo 'This script should be run on Ubuntu 14.04.'>&2
exit 1
}
#LDAP group name of team members to be granted access on this server,
LDAP_TEAM_NAME=$1
LDAP_BASE="dc=example,dc=com"
LDAP_URI="ldaps://ldap.example.com"
LDAP_BINDDN="cn=OpenLDAP Client,ou=users,dc=example,dc=com"
LDAP_BINDPW="password"
USAGE="usage: ./$(basename $0) LDAP_TEAM_NAME"
# Check required positional parameters
[ $# -ne 1 ] && {
echo "$USAGE">&2
exit 1
}
# Install required packages
export DEBIAN_FRONTEND=noninteractive
apt-get -y install libpam-ldap nscd ldap-utils libnss-ldapd
apt-get -y install python-pip python-ldap
pip install ssh-ldap-pubkey
# Configure SSH server
grep 'AuthorizedKeysCommand' /etc/ssh/sshd_config > /dev/null || {
cat >> /etc/ssh/sshd_config <<EOF
AuthorizedKeysCommand /usr/local/bin/ssh-ldap-pubkey-wrapper
AuthorizedKeysCommandUser nobody
EOF
}
#Restart SSH server
service ssh restart
# Edit /etc/ldap.conf
# If using nss-ldapd, /etc/ldap.conf will be not used by nslcd. However, it is
# still read by /usr/local/bin/ssh-ldap-pubkey-wrapper to authorize SSH users
mv /etc/ldap.conf /etc/ldap.conf.bak
cat > /etc/ldap.conf <<EOF
base $LDAP_BASE
uri $LDAP_URI
ldap_version 3
binddn $LDAP_BINDDN
bindpw $LDAP_BINDPW
pam_password md5
nss_initgroups_ignoreusers backup,bin,daemon,games,gnats,irc,landscape,libuuid,list,lp,mail,man,messagebus,news,pollinate,proxy,root,sshd,sync,sys,syslog,uucp,www-data
bind_timelimit 3
timelimit 3
EOF
cat > /etc/nslcd.conf <<EOF
uid nslcd
gid nslcd
uri $LDAP_URI
base $LDAP_BASE
binddn $LDAP_BINDDN
bindpw $LDAP_BINDPW
tls_reqcert never
nss_initgroups_ignoreusers ALLLOCAL
bind_timelimit 3
timelimit 3
reconnect_retrytime 3
EOF
#Edit /etc/ldap/ldap.conf
cp /etc/ldap/ldap.conf /etc/ldap/ldap.conf.bak
grep 'TLS_REQCERT' /etc/ldap/ldap.conf > /dev/null || {
cat >> /etc/ldap/ldap.conf <<EOF
TLS_REQCERT never
EOF
}
# Configure PAM
# Add pam_access.so
grep 'pam_access.so' /etc/pam.d/common-auth > /dev/null || {
cat >> /etc/pam.d/common-auth <<EOF
account required pam_access.so
EOF
}
# Remove use_authtok from /etc/pam.d/common-password
sed -i -r 's/(.*)(use_authtok)(.*)/\1\3/g' /etc/pam.d/common-password
#Add pam_mkhomedir.so
grep 'pam_mkhomedir.so' /etc/pam.d/common-session > /dev/null || {
cat >> /etc/pam.d/common-session <<EOF
session required pam_mkhomedir.so skel=/etc/skel umask=0022
EOF
}
# Configure NSS
sed -i -r 's/(^passwd:)(\s+)(.*)/\1\2compat ldap/' /etc/nsswitch.conf
sed -i -r 's/(^group:)(\s+)(.*)/\1\2compat ldap/' /etc/nsswitch.conf
sed -i -r 's/(^shadow:)(\s+)(.*)/\1\2compat ldap/' /etc/nsswitch.conf
# Edit /etc/security/access.conf
grep -- '^- : ALL EXCEPT root' /etc/security/access.conf > /dev/null || {
cat >> /etc/security/access.conf <<EOF
+ : ($LDAP_TEAM_NAME) : ALL
- : ALL EXCEPT root staging-devops (admin) (wheel) : ALL EXCEPT LOCAL
EOF
}
# Edit /etc/sudoers
grep -F -- "%ldap-admin" /etc/sudoers > /dev/null || {
cat >> /etc/sudoers <<EOF
%ldap-admin ALL=(ALL) ALL
EOF
}
grep -F -- "%$LDAP_TEAM_NAME" /etc/sudoers > /dev/null || {
cat >> /etc/sudoers <<EOF
%$LDAP_TEAM_NAME ALL=(ALL) ALL
EOF
}
# Set vim as default editor
echo 3 | update-alternatives --config editor
echo
# Restart nscd
service nscd restart
# Restart nslcd
service nslcd restart