Linux SFTP Server with CIFS and Kerberos

This is a configuration example for an SFTP server implemented for a customer with the specific requirements listed below.

IMPORTANT NOTES:  This configuration has been tested on CentOS 6.1., due to this customer’s request that incoming files be stored on a CIFS-based NAS (Solaris 10 does have a suitable CIFS kernel module, although CIFS support was added in Solaris 11). However, the rest of the guide could be implemented (with minor changes) on any Unix-like platform for which Samba/Winbind is available.

CONFIGURATION REQUIREMENTS

  • Allow Active Directory user logins, restricted to a certain AD group
  • Restrict users in a certain AD group to a chroot jail
  • Restrict users in the same AD group to SFTP login only (no interactive login)
  • Store files on a SAMBA/CIFS NAS in a central share (not separate home directories)
  • Log all SFTP sessions and file transfers
  • Email specific recipients if files have been uploaded to a specific time-sensitive directory, no later than 15 minutes after the upload
  • Use a reasonable level of debug logging in order to effectively troubleshoot emergent issues

In other words, users in the SFTP Security Group in Active Directory will be permitted to authenticate against the SFTP server. The system will be set up with Kerberos authentication and autofs with CIFS to connect to a Kerberos-enabled NAS. When a user connects, his or her credentials will be validated by the domain controller via Kerberos and a ticket-granting-ticket is issued and cached. This cached ticket will be used to re-authenticate the user automatically for additional kerberized services (like CIFS). When the session modules change the user’s session to the user’s home directory, autofs will mount a centralized share on the Samba server using that user’s cached credentials (validated again by the Samba server against the Domain Controller) to the local home directory.

All file permissions will be deferred to the NAS.

First, configure Kerberos and Winbind to permit AD logins. This requires configuration of NTP, Windbind itself, Kerberos, and the winbind PAM module.

NTP

 NTP syncronizes the system clock with the Active Directory domain controller – a requirement to participate in domain functions. NOTE: Solaris Zones can be NTP clients, but they require the “sys_time” privilege added to the configuration in order to be allowed to set the global clock.

 
/etc/ntp.conf
 server ipOfDomainController
# chkconfig --levels 235 ntpd on
# ntpdate 10.144.10.62
# service ntpd start

WINBIND

 Winbind is the mechanism which maintains Active Directory domain membership and which maps AD identities to Unix-style sets of account attributes. For a single server, the attributes can be stored in a local table file – tdb. However, other options exist for centralized storage.

/etc/samba/smb.conf

# Domain NETBIOS name
workgroup = DOMAIN

# Domain controller
password server = ipOfDomainController

# Domain FQDN for Kerberos
realm = REALM (domain fqdn, must be capitalized)

# Active Directory mode
security = ads

# Set the idmap backend to local tables
# NOTE: this creates a mapping of UIDs to SIDs unique to this server.
# If consistent UIDs between servers are desired (usually for NFS
# purposes), several options are available.
# See http://www.samba.org/samba/docs/man/Samba-HOWTO-Collection/idmapper.html
idmap alloc backend = tdb

# One simple alternative is to use IDMAP_RID, which creates a predictable mapping
# between UIDs and GIDs that will be consistent across multiple servers in the
# same domain. Unfortunately, it cannot be used when multiple domains are
# involved. In that case, an LDAP server or AD schema addition must be used
# to store the mappings.
;allow trusted domains = no
;idmap backend = idmap_rid:DOMAIN=7000-50000

# UID and GID range to map to new AD users
idmap uid = 7000-50000
idmap gid = 7000-50000

# Separator to use when specfying DOMAIN and USER or GROUP together. Ex: COMPANYDOMAIN\User or COMPANYDOMAIN_User or COMPANYDOMAIN_SFTP
winbind separator = _

# Home directory for AD users. May use %D and %U for DOMAIN and USER wildcards. Using single homedir here for SFTP users, so they can share a login script that cd’s to a user’s home directory under the AutoFS root, causing a central NAS share to be mounted using his or her credentials.
template homedir = /export/SFTP/temphome

# Needed to execute login scripts
template shell = /bin/bash

# Remote accounts normally require DOMAIN_USER syntax. Remove DOMAIN requirement; invisibly prefix default DOMAIN to any non-local USER
winbind use default domain = true

# Require connectivity to the Domain Controller(s) in order to permit remote logins
winbind offline logon = false

# Track uids for users
winbind enum users = yes

# Track gids for groups
winbind enum groups = yes

# Activate code to handle nested AD groups
winbind nested groups = yes

# Automatically refresh Kerberos tickets as needed
winbind refresh tickets = true

# Use Kerberos
client use spnego = yes

# Don’t use other auth mechanisms (password-based)
client lanman auth = no
client ntlmv2 auth = no
lanman auth = no
ntlm auth = no
nt pipe support = no

# See http://bugzilla.samba.org/show_bug.cgi?id=6833
kerberos method = secrets and keytab

KERBEROS

 Kerberos is an authentication protocol implemented by Active Directory uses tickets to allow users and systems to authenticate in a secure manner.

/etc/krb5.conf

[libdefaults]
# Specify DOMAIN FQDN as the default Kerberos realm
default_realm = REALM (domain fqdn, must be capitalized)

# Do not use DNS to look up additional DOMAIN REALMs
dns_lookup_realm = false

# Do not use DNS to look up additional Kerberos Key Distribution Centers (KDCs)
dns_lookup_kdc = false

# Specify the default cached credential ticket lifetime
ticket_lifetime = 10m

# Permit cached credential tickets to be used by other services (CIFS)
forwardable = yes

[realms]
REALM (domain fqdn, must be capitalized) = {

kdc = ipOfDomainController1
kdc = ipOfDomainController2
default_realm = fqdn

}
[domain_realm]
# Define some aliases that may be used for the realm
.hostfqdn = REALM (must be capitalized)
.domainfqdn = REALM (must be capitalized)
domainfqdn = REALM (must be capitalized)
.DOMAIN = REALM (must be capitalized)
DOMAIN = REALM (must be capitalized)

/etc/sysconfig/samba

# Options to smbd
SMBDOPTIONS=”-D”

# Options to nmbd
NMBDOPTIONS=”-D”

# Options for winbindd
WINBINDOPTIONS=”-d 6″

# chkconfig --levels 235 winbind on

Join the system to the AD domain

# net ads join -U Administrator
Password:

Start Winbind

# service winbind start

TESTING

 Test Kerberos with kinit/klist. Kinit should have no output if successful. Klist should show the default ticket belonging to the authenticated user

# kinit ADUSER@REALM
# klist

Test user info lookup

# wbinfo -n ADUSER

Test user authentication via Kerberos through Winbind

# wbinfo -K ADUSER
Password:

Note: You may need to create a keytab file for winbind:

# net ads -U Administrator keytab create

PAM

 PAM is a mechanism to load authentication modules during different stages and aspects of authentication. Modules return a pass/fail result, and the control option dictates what to do with the result. PAM is an extensive topic beyond the scope of this document, but the configuration below shows an example that uses the pam_winbind.so module to allow Windows users to log in and manage their passwords.

/etc/pam.d/password-auth

auth        required      pam_env.so debug
auth        sufficient    pam_unix.so nullok try_first_pass debug
auth        requisite     pam_succeed_if.so uid >= 500 quiet debug
auth        sufficient    pam_winbind.so use_first_pass debug
auth        required      pam_deny.so debug
account     required      pam_unix.so broken_shadow debug
account     sufficient    pam_localuser.so debug
account     sufficient    pam_succeed_if.so uid < 500 quiet debug
account     [default=bad success=ok user_unknown=ignore] pam_winbind.so debug
account     required      pam_permit.so debug
password    requisite     pam_cracklib.so try_first_pass retry=3 type= debug
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok debug
password    sufficient    pam_winbind.so use_authtok debug
password    required      pam_deny.so debug
session     optional      pam_keyinit.so revoke debug
session     required      pam_limits.so debug
session     required      pam_winbind.so debug
#session     required      pam_oddjob_mkhomedir.so skel=/export/ETA/skel umask=0022 debug
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid debug
session     required      pam_unix.so debug

/etc/pam.d/system-auth

auth        required      pam_env.so debug
auth        sufficient    pam_unix.so nullok try_first_pass debug
auth        requisite     pam_succeed_if.so uid >= 500 quiet debug
auth        sufficient    pam_winbind.so use_first_pass debug
auth        required      pam_deny.so debug
account     required      pam_unix.so broken_shadow debug
account     sufficient    pam_localuser.so debug
account     sufficient    pam_succeed_if.so uid < 500 quiet debug
account     [default=bad success=ok user_unknown=ignore] pam_winbind.so debug
account     required      pam_permit.so debug
password    requisite     pam_cracklib.so try_first_pass retry=3 type= debug
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok debug
password    sufficient    pam_winbind.so use_authtok debug
password    required      pam_deny.so debug
session     optional      pam_keyinit.so revoke debug
session     required      pam_limits.so debug
session     required      pam_winbind.so debug
#session     required      pam_oddjob_mkhomedir.so skel=/export/ETA/skel umask=0022 debug
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid debug
session     required      pam_unix.so debug

PAM_WINBIND CONFIGURATION

This is the configuration file for the pam_winbind.so module

/etc/security/pam_winbind.conf

# Enable debugging by default
debug = yes
debug_state = yes

# Enable Kerberos authentication
krb5_auth = yes

# Specify the cached credentials tickets should be stored in FILE form (the only option currently)
krb5_ccache_type = FILE
# Restrict logon to a specfic AD group
require_membership_of = DOMAIN_SFTP # may specify AD group name or SID here

# Direct the PAM module to create new home directories if they do not already exist
mkhomedir = no # not needed in this particular config, but it may be in other scenarios

TESTING

$ ssh ADUSER@localhost
Password:
$

 

and/or

$ su - ADUSER
Password:
$

NAS CONNECTION

 Windows users may have home directories available on a central NAS via the CIFS protocol. The following will mount a central SFTP directory from a CIFS file server onto any directory under the root defined in /etc/auto.master, using the stored Kerberos ticket to perform the mount as the user navigating the AutoFS directories.
The AutoFS configuration could also be used to mount user’s Windows home directory files from a CIFS file server, using the $USERNAME variable to mount different shares on the NAS depending on its value.

/etc/init.d/cifsDebugEnable (executable)

#!/bin/bash
echo 3 > /proc/fs/cifs
exit 0

# cd /etc/rc3.d
# ln -s ../init.d/cifsDebugEnable S99cifsDebugEnable

/etc/request-key.conf

create cifs.spnego * * /usr/sbin/cifs.upcall -l %k %d
create dns_resolver * * /usr/sbin/cifs.upcall -l %k %d

/etc/auto.master

/export/SFTP/home /etc/auto.SFTP

/etc/auto.SFTP

#!/bin/bash
USERNAME=$(/usr/bin/id -un $1)
USERID=$(/usr/bin/id -u ${USERNAME})
GROUPNAME=ETASFTP
GROUPID=$(/usr/bin/getent group ${GROUPNAME} | /bin/awk -F \: ‘{print $3}’)
echo “-fstype=cifs,sec=krb5,rw,user=$USERNAME,uid=$USERID,gid=$GROUPID,dir_mod=0770,file_mod=0660,dynperms,domain=NETBIOS_DOMAIN ://NAS/SFTPDIR”

# chmod a+x /etc/auto.SFTP
# chkconfig --levels 235 autofs on
# service autofs start

SFTP SERVER

Enable file transfer logging and chroot jail

/etc/ssh/sshd_config

# Enable transfer logging
Subsystem       sftp    /usr/libexec/openssh/sftp-server -l INFO -f LOCAL0
# Jail users in the SFTP group to a specific directory. %u can be used as a USER wildcard
Match Group SFTP
ChrootDirectory /export/SFTP/
ForceCommand /usr/libexec/openssh/sftp-server -l INFO -f LOCAL0
AllowTcpForwarding no

# mkdir /var/log/SFTP

/etc/rsyslog.conf

# Capture SFTP server transfer log to a file
local0.info                            /var/log/SFTP/transferlog
user.info                               /var/log/SFTP/sessionlog

NOTE: ensure tab characters are used in the rsyslog.conf file

TESTING

$ sftp ADUSER@localhost
sftp> pwd
/
sftp> ls
sftp> put someFile
sftp> quit
# tail /var/log/SFTP/transferlog

EMAIL ALERTS

/etc/postfix/sasl_passwd

mailserver.subdomain.domain       emailAccount@domain:password

/etc/postfix/generic

root@domain    emailAccount@domain
root@HOST.REALM emailAccount@domain

/etc/postfix/main.cf

# enable SASL for authentication
smtp_sasl_auth_enable = yes
# force AUTH LOGIN mechanism, else Postfix might try something else
smtp_sasl_mechanism_filter = login
# override Postfix default disallowing of plaintext AUTH LOGIN
smtp_sasl_security_options =
# use our password database for authentication
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
# map machine email addresses to internet addresses
smtp_generic_maps = hash:/etc/postfix/generic
# send mail through our Exchange SMTP server
relayhost = mailserver.subdomain.domain

TESTING

$ su - windowsAccount1
$ echo "test email" | mailx -s "test subject" admin@example.com

LOGON SCRIPTS

/export/SFTP/temphome/.bash_login and
/export/SFTP/temphome/.bashrc

USERNAME=$(/usr/bin/id -un)
cd /export/SFTP/home/${USERNAME}
/export/SFTP/configuration/initialLogon.sh $USERNAME

/export/SFTP/configuration/initialLogon.sh

trap “” 2 3
# Identify whether the session is interactive
case $- in

*i*)    # interactive shell

logger -p info “User $1 logged in with interactive shell. Exiting.”
echo “This account is restricted to non-interactive SFTP connections only. Please reconnect with an SFTP client.”
echo “Exiting automatically in 10 seconds…”
for i in {1..10}; do echo “.”; sleep 1; done
exit 1
;;

*)      # non-interactive shell

logger -p info “User $1 logged in with SFTP client. Monitoring session for uploads”
/export/SFTP/configuration/fileCheck.sh
;;

exit 0

/export/SFTP/configuration/fileCheck.sh

Logic (full script coming soon):

Monitor the session PID and increase counter each second
If counter gets to 900 seconds (15 minutes), email recipients list of recently uploaded files and reset counter.
If session PID dies, email recipients list of recently uploaded file.

Output:

Append all output to /var/log/SFTP/sessionlog (via logger)

LOGS

/var/log/debug
/var/log/SFTP/*
/var/log/samba/*

Related Articles:


ABOUT US
Seeds of Genius, Inc. offers a full range of IT solutions including hardware and software products in addition to consulting, installation and support services. For more information, please visit our main web site at http://www.seedsofgenius.com or contact our Technical Sales department at (410) 312-9806.