This is a setup for NFS4 with Kerberos and secure LDAP on Debian Wheezy. It's an update on the Squeeze manual (see history) and it is not really well tested at the moment (I did an upgrade from Squeeze myself, not a new install).
Kerberos will use LDAP as backend database. Most of this setup comes from Heiko Noordhof. I know, there are allready pages in this wiki about NFS4, Kerberos and LDAP. This howto tries to give an easy start.
This page is about the server setup. You can find the client setup here: http://wiki.debian.org/nfs4-kerberos-ldap-client
The idea is, that you copy/paste parts of the howto to your console. Look out when you copy many lines, some commands (like "apt-get" and "read") will remove later lines from memory. That's why I made an empty line after that commands.
First of all, you will need a correct FQDN hostname. If you give the command "hostname --fqdn" this should give something like "server.example.com" and not only "server". And you need also a correct reversed DNS, so e.g. "host 192.168.1.1" should give the complete name. I will advice you to add a line like this to /etc/hosts :
192.168.1.1 server.example.com server
where "server" is the hostname of this machine, and "example.com" is your domain.
This manual is not really about DNS, but I use the program "dnsmasq", because it does both DHCP and DNS, and it adds an IP it gives with DHCP automatically to DNS and reversed DNS. After installing it, you can edit the configfile (/etc/dnsmasq.conf), but I think it's better to create a configfile /etc/dnsmasq.d/default , something like :
server=1.2.3.4 # dns server 1 of your provider server=5.6.7.8 # dns server 2 of your provider domain="example.com" # your domain name dhcp-range=192.168.1.30,192.168.1.99,12h # the dhcp range and lease time # with lines like this you can make fixed IP's: # dhcp-host=14:da:e9:96:c3:2b,192.168.1.22
After this you have to restart dnsmasq and to test it:
service dnsmasq restart host www.google.com 127.0.0.1
And when it works:
echo "nameserver 127.0.0.1" > /etc/resolv.conf
In the firewall you need this ports open: 53 tcp and udp (dns), 67 udp (dhcp), 88 tcp and udp (kerberos), 123 udp (ntp), 636 tcp (ldaps), 749 tcp (kadmin), 2049 tcp (nfs).
Server setup:
# become root: su - # When you did install LDAP or Kerberos or NFS before, it is a good idea to remove it to # have a clean start. Backup it first if you want to keep it! apt-get purge krb5-kdc-ldap gnutls-bin krb5-admin-server nfs-kernel-server \ ldap-utils slapd krb5-kdc rm -r /var/lib/ldap/ rm -r /etc/ldap/ rm -r /etc/krb5kdc/ rm -r /root/kerberos-setup/ rm -r /srv/nfs4/ rm /etc/krb5.keytab rm /etc/krb5.conf rm /etc/idmapd.conf rm /etc/ssl/certs/CAself-cert.pem rm /etc/ssl/certs/*_slapd_cert.pem rm /etc/ssl/*.info rm /etc/ssl/private/*_slapd_key.pem rm /etc/ssl/private/CAself-key.pem # check your hostname if it's correct. When not, see the part at the begin of the howto hostname --fqdn # Main setup variables defaults SERVER=$(hostname --fqdn) # something like: server1.example.com DOMAIN=${SERVER#*.} # something like: example.com REALM=$(echo "${DOMAIN}" | tr '[:lower:]' '[:upper:]') # something like: EXAMPLE.COM LDAPROOT=""; IFS="."; for DC in $DOMAIN ; do LDAPROOT="${LDAPROOT},dc=$DC"; done; LDAPROOT="${LDAPROOT#,}" # something like: dc=example,dc=com echo -e "\nSERVER: $SERVER \nDOMAIN: $DOMAIN \nREALM: $REALM \nLDAPROOT: $LDAPROOT \n\ Change this defaults when needed with something like: DOMAIN='example2.com' \n" # Install packages without questions. You can also answer the questions but this is # pointless, because the configuration will be overwritten later. # Some errors are normal because of the noninteractive install DEBIAN_FRONTEND=noninteractive apt-get install ldap-utils slapd nfs-kernel-server \ krb5-admin-server krb5-kdc krb5-kdc-ldap krb5-doc libnss-ldap nscd libpam-ldap \ gnutls-bin ssl-cert ntp pwgen ssh rpl # Directory for temporary setup files, good place to search later for passwords: SETUPDIR=/root/kerberos-setup/ mkdir "$SETUPDIR" chmod 700 "$SETUPDIR" cd "$SETUPDIR" # Setup ldap.conf for clients cat <<EOF >/etc/ldap/ldap.conf BASE ${LDAPROOT} URI ldapi:// EOF # Setup SSL/TLS certificate (self-signed) for TLS on LDAP CA_KEY=/etc/ssl/private/CAself-key.pem CA_INFO=/etc/ssl/CAself.info CA_CERT=/etc/ssl/certs/CAself-cert.pem certtool --generate-privkey >"${CA_KEY}" cat <<EOF >"${CA_INFO}" cn = ${DOMAIN} ca cert_signing_key expiration_days = 8700 EOF certtool \ --generate-self-signed \ --load-privkey "${CA_KEY}" \ --template "${CA_INFO}" \ --outfile "${CA_CERT}" chgrp ssl-cert "${CA_KEY}" chmod 0640 "${CA_KEY}" # Generate private-key for TLS on the LDAP-service LDAP_TLS_KEY="/etc/ssl/private/${SERVER}_slapd_key.pem" LDAP_TLS_INFO="/etc/ssl/${SERVER}.info" LDAP_TLS_CERT="/etc/ssl/certs/${SERVER}_slapd_cert.pem" certtool --generate-privkey >"${LDAP_TLS_KEY}" cat <<EOF >"${LDAP_TLS_INFO}" organization = ${DOMAIN} cn = ${SERVER} tls_www_server encryption_key signing_key expiration_days = 8700 EOF certtool \ --generate-certificate \ --load-privkey "${LDAP_TLS_KEY}" \ --load-ca-certificate "${CA_CERT}" \ --load-ca-privkey "${CA_KEY}" \ --template "${LDAP_TLS_INFO}" \ --outfile "${LDAP_TLS_CERT}" chgrp ssl-cert "${LDAP_TLS_KEY}" chmod 0640 "${LDAP_TLS_KEY}" # Set access to ssl keys for LDAP-daemon (slapd) adduser openldap ssl-cert # Generate hash from admin password LDAP_ADMIN_PW=$(pwgen -s 10 1) echo -n "$LDAP_ADMIN_PW" >ldap-admin-pw.txt chmod 600 ldap-admin-pw.txt LDAP_ADMIN_HASH=$(slappasswd -h '{SHA}' -T ldap-admin-pw.txt) touch passwords.txt; chmod 600 passwords.txt echo "LDAP admin password: $LDAP_ADMIN_PW" >> passwords.txt # Create ldif 1 and load it into LDAP cat <<EOF >slapd-loglevel.ldif dn: cn=config changeType: modify replace: olcLogLevel olcLogLevel: stats EOF ldapmodify -v -Y EXTERNAL -H ldapi:/// -f slapd-loglevel.ldif # Create ldif 2 and load it into LDAP cat <<EOF >slapd-tls.ldif dn: cn=config changeType: modify add: olcTLSCACertificateFile olcTLSCACertificateFile: ${CA_CERT} - add: olcTLSCertificateFile olcTLSCertificateFile: ${LDAP_TLS_CERT} - add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: ${LDAP_TLS_KEY} EOF ldapmodify -v -Y EXTERNAL -H ldapi:/// -f slapd-tls.ldif # Create ldif 3 and load it into LDAP cat <<EOF >slapd-database.ldif dn: olcDatabase={1}hdb,cn=config changeType: modify replace: olcDbConfig olcDbConfig: {0}set_cachesize 0 2097152 0 olcDbConfig: {1}set_lk_max_objects 1500 olcDbConfig: {2}set_lk_max_locks 1500 olcDbConfig: {3}set_lk_max_lockers 1500 olcDbConfig: {4}set_flags DB_LOG_AUTOREMOVE - replace: olcRootPW olcRootPW: ${LDAP_ADMIN_HASH} EOF ldapmodify -v -Y EXTERNAL -H ldapi:/// -f slapd-database.ldif # Do not listen on the clear-text port (389) only SSL/LDAPS (636) sed -i 's|^SLAPD_SERVICES.*|SLAPD_SERVICES="ldaps:/// ldapi:///"|' /etc/default/slapd # Add indices cat <<EOF >indices.ldif dn: olcDatabase={1}hdb,cn=config add: olcDbIndex olcDbIndex: cn eq,pres olcDbIndex: uid eq,pres olcDbIndex: uidNumber eq,pres olcDbIndex: gidNumber eq,pres EOF ldapmodify -v -Y EXTERNAL -H ldapi:/// -f indices.ldif # Restart LDAP-server /etc/init.d/slapd restart # Setup LDAP structure # Generate random password for kerberos-admin account in LDAP, and a hash. LDAP_KRBADMIN_PW=$(pwgen -s 12 1) echo -n "$LDAP_KRBADMIN_PW" >ldap-krbadmin-pw.txt chmod 600 ldap-krbadmin-pw.txt LDAP_KRBADMIN_HASH=$(slappasswd -h '{SHA}' -T ldap-krbadmin-pw.txt) # Create ldif 4 and load it into LDAP cat <<EOF >structure.ldif dn: cn=krb-admin,${LDAPROOT} cn: krb-admin objectClass: organizationalRole objectClass: simpleSecurityObject userPassword: ${LDAP_KRBADMIN_HASH} dn: ou=groups,${LDAPROOT} objectClass: organizationalUnit ou: groups dn: ou=users,${LDAPROOT} objectClass: organizationalUnit ou: users EOF ldapadd -x -D cn=admin,"${LDAPROOT}" -y ldap-admin-pw.txt -f structure.ldif # Setup kerberos services, with backend database in LDAP gunzip -c /usr/share/doc/krb5-kdc-ldap/kerberos.schema.gz >krb.schema echo 'include krb.schema' >slapd.tmp.conf slaptest -f slapd.tmp.conf -F ./ mv 'cn=config/cn=schema/cn={0}krb.ldif' krb.schema.ldif sed -i 's/^dn: cn={0}krb/dn: cn=kerberos,cn=schema,cn=config/' krb.schema.ldif sed -i 's/^cn: {0}krb/cn: kerberos/' krb.schema.ldif sed -i '/^structuralObjectClass/,$d' krb.schema.ldif ldapadd -QY EXTERNAL -H ldapi:/// -f krb.schema.ldif # Add index cat <<EOF >krbindex.ldif dn: olcDatabase={1}hdb,cn=config add: olcDbIndex olcDbIndex: krbPrincipalName eq,pres,sub EOF ldapmodify -v -Y EXTERNAL -H ldapi:/// -f krbindex.ldif # Add some ACL's cat <<EOF >krbacl.ldif dn: olcDatabase={1}hdb,cn=config replace: olcAccess olcAccess: to attrs=userPassword,shadowLastChange,krbPrincipalKey by dn="cn=krb-admin,${LDAPROOT}" write by anonymous auth by self write by * none - add: olcAccess olcAccess: to dn.base="" by * read - add: olcAccess olcAccess: to * by dn="cn=krb-admin,${LDAPROOT}" write by * read EOF ldapmodify -v -Y EXTERNAL -H ldapi:/// -f krbacl.ldif # Setup MIT-kerberos cp /etc/krb5.conf /etc/krb5.conf.bak-$(date +%Y%m%d_%H%M) cat <<EOF >/etc/krb5.conf [libdefaults] default_realm = ${REALM} krb4_config = /etc/krb.conf krb4_realms = /etc/krb.realms kdc_timesync = 1 ccache_type = 4 forwardable = true proxiable = true ticket_lifetime = 525600 [realms] ${REALM} = { kdc = ${SERVER} admin_server = ${SERVER} default_domain = ${DOMAIN} database_module = openldap_ldapconf } [domain_realm] .${DOMAIN} = ${REALM} [login] krb4_convert = true krb4_get_tickets = false [logging] kdc = SYSLOG:INFO:DAEMON admin_server = SYSLOG:INFO:DAEMON default = SYSLOG:INFO:DAEMON [dbdefaults] ldap_kerberos_container_dn = ${LDAPROOT} [dbmodules] openldap_ldapconf = { db_library = kldap ldap_kdc_dn = "cn=krb-admin,${LDAPROOT}" ldap_kadmind_dn = "cn=krb-admin,${LDAPROOT}" ldap_service_password_file = /etc/krb5kdc/service.keyfile ldap_servers = ldapi:/// ldap_conns_per_server = 5 EOF # create kdc.conf cat <<EOF > /etc/krb5kdc/kdc.conf [kdcdefaults] kdc_ports = 750,88 [realms] ${REALM} = { database_name = /var/lib/krb5kdc/principal admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab acl_file = /etc/krb5kdc/kadm5.acl key_stash_file = /etc/krb5kdc/stash kdc_ports = 750,88 max_life = 365d 10h 0m 0s max_renewable_life = 7d 0h 0m 0s master_key_type = des3-hmac-sha1 supported_enctypes = aes256-cts:normal arcfour-hmac:normal des3-hmac-sha1:normal default_principal_flags = +preauth } EOF # ACL to grant all permissions to principals like "<name>/admin@<REALM>" echo '*/admin *' >>/etc/krb5kdc/kadm5.acl # Ppassword for kerberos LDAP backend KLDAPPW=`pwgen -s 10 1` echo "$KLDAPPW" > $SETUPDIR/kerberos-ldap-password.txt echo "Kerberos LDAP password: $KLDAPPW" >> passwords.txt # Create basic entries in the kerberos LDAP backend echo -e "You will now be asked to enter the password (twice). \n Please copy and paste the password, it is: $KLDAPPW\n" kdb5_ldap_util -w "$LDAP_KRBADMIN_PW" \ -D "cn=krb-admin,$LDAPROOT" \ create \ -subtrees "$LDAPROOT" \ -r "$REALM" \ -s \ -H ldapi:/// # Stash the LDAP-password for the account the kerberos daemons use to # read and write to LDAP echo -e "You will now be asked to enter another password (twice). \n Please copy/paste the following password in there: $LDAP_KRBADMIN_PW\n" kdb5_ldap_util -w "$LDAP_KRBADMIN_PW" \ -D "cn=krb-admin,$LDAPROOT" \ stashsrvpw \ -f /etc/krb5kdc/service.keyfile \ "cn=krb-admin,$LDAPROOT" # Restart the Kerberos daemons /etc/init.d/krb5-kdc restart /etc/init.d/krb5-admin-server restart # policies, not very secure, you can change it later with modify_policy, see "man kadmin" kadmin.local -q "add_policy user" kadmin.local -q "add_policy machine" kadmin.local -q "add_policy admin" # create an kerberos admin user: read -p "Kerberos admin username, normally your name (without '/admin'): " KADMIN echo "kerberos admin username: $KADMIN/admin" >> passwords.txt KADMINPWD=`pwgen -s 10 1` read -p "Password for Kerberos admin user, specify a password (return='$KADMINPWD') : " KADMINPW if test "$KADMINPW" = ""; then KADMINPW="$KADMINPWD"; fi echo "kerberos admin paswword: $KADMINPW" >> passwords.txt kadmin.local -q "addprinc -pw $KADMINPW -policy admin $KADMIN/admin" # The NFS-server must know the same user names and UID's as the clients. # Therefore our server name service switch needs to be a client of the server itself. cp /etc/libnss-ldap.conf /etc/libnss-ldap.conf -$(date +%Y%m%d_%H%M) cat <<EOF >/etc/libnss-ldap.conf uri ldapi:// ldap_version 3 base ${LDAPROOT} scope sub EOF # Activate LDAP in name service switch sed -i 's/compat/files ldap/' /etc/nsswitch.conf /etc/init.d/nscd restart # Setup NFS4-service # ==> Security level "krb5i" is middle level. More secure (everything encrypted) # would be: "krb5p". This must match mount option on the client. mkdir -p /srv/nfs4/home echo "/srv/nfs4 *.${DOMAIN}(rw,sync,sec=krb5i,fsid=0,crossmnt,no_subtree_check) " >> /etc/exports echo "/srv/nfs4/home *.${DOMAIN}(rw,sync,sec=krb5i,no_subtree_check) " >> /etc/exports # Create kerberos principal for NFS-server kadmin.local -q "addprinc -randkey nfs/${SERVER}" # Store the key for the nfs-service principal in (default) keytab file kadmin.local -q "ktadd nfs/${SERVER}" # Configure NFS-service daemons for kerberized NFS4: sed -i 's/^ *NEED_SVCGSSD=.*$/NEED_SVCGSSD=yes/' /etc/default/nfs-kernel-server sed -i 's/^ *NEED_IDMAPD=.*$/NEED_IDMAPD=yes/' /etc/default/nfs-common sed -i 's/^ *NEED_GSSD=.*$/NEED_GSSD=yes/' /etc/default/nfs-common # create idmapd.conf cat <<EOF >/etc/idmapd.conf [General] Verbosity = 1 Pipefs-Directory = /var/lib/nfs/rpc_pipefs [Mapping] Nobody-User = nobody Nobody-Group = nogroup EOF # Restart the NFS4 (related) services /etc/init.d/nfs-kernel-server stop /etc/init.d/nfs-common restart /etc/init.d/nfs-kernel-server start # in many cases you want to change the umask, so normal users will give write access for the group. # see "man pam_umask" or http://wiki.debian.org/DebianDesktopHowTo for more information. echo -e "\nsession optional pam_umask.so umask=0002" >> /etc/pam.d/common-session # Download and install some usefull scripts in /usr/local/sbin/ # maybe take a look first in http://vandervlis.nl/krb5/ mkdir -p /srv/nfs4/data/; mkdir /srv/nfs4/home/ mkdir scripts; cd scripts wget -qr -nd --no-parent http://vandervlis.nl/krb5/ rm index.html* rpl "dc=example,dc=com" "$LDAPROOT" variables rpl "secret" "$LDAP_ADMIN_PW" variables chmod +x * chmod 600 variables uid guid cp -a * /usr/local/sbin/ cd $SETUPDIR touch /var/log/au.log chmod 600 /var/log/au.log # Test creating users au jan25 # creates a user "jan25" in Kerberos and LDAP getent passwd jan25 # check if the user excists ru jan25 # removes the test user # Add a real user and an machine account au # add user ama # add machine account # There is a problem starting the daemons, see: # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=582122 rpl "exit 0" "krb5-admin-server start krb5-kdc start exit 0" /etc/rc.local # Write some extra information to the password.txt file: echo "LDAP root: ${LDAPROOT}" >> $SETUPDIR/passwords.txt echo "LDAP super-user account: cn=admin,${LDAPROOT}" >> $SETUPDIR/passwords.txt echo "Kerberos realm: ${REALM}" >> $SETUPDIR/passwords.txt
The setupdir contains all passwords among other things. Please make sure to remove this directory later.
When you have troubles, it's a good idea to check if all the daemons are running:
ps aux | grep [r]pc.gssd ps aux | grep [i]dmap ps aux | grep [r]pc.svcgssd ps aux | grep [k]rb5kdc ps aux | grep [k]admind
When you upgrade from Squeeze, you need a new /etc/krb5.keytab file, because in the old key are wrong encryption-types. And you need in many cases a new private-key for TLS on the LDAP-service. In the old situation (Squeeze) the validity date of this key was not correct checked, but in Wheezy it is, see this bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=751002