Skip to content

Authentication Servers, the Next Generation

I’m mildly embarrassed by my previous setup authentication servers, but this one should be a vast improvement. A reminder of the existing constraints and conditions:

  • Lots of Linux systems and a few Solaris systems, some of which dual-boot and aren’t accessible as *nix systems during normal hours of the day
  • An Active Directory already in place
  • An overworked administration team that has lots of other stuff to do besides create user accounts

As I had indicated at the end of the previous authentication server post, my experience with winbind has gotten decidedly more positive lately. My previous experience with it in 2001-2002 was entirely negative, since either due to design limitations or my own incompetence, I was unable to get multiple systems running winbind to agree on what the users’ UIDs and GIDs were, which made NFS unworkable. As of 2007, things have improved vastly.

So what do I need the authentication server structure to do for me?

  1. keep a canonical mapping of usernames and groups to UIDs and GIDs
  2. keep a list of which users are allowed to access particular hosts or services
  3. keep a canonical list of passwords for those users

NSS and Winbind will handle the first goal. PAM and the pam_listfile module will handle the second goal. And PAM and Kerberos will handle the third. Winbind and Kerberos will both verify everything against the existing Active Directory. The gold server will generate a master list of allowed users via puppet and file fragments, and all the clients will use that list by default.

The puppet manifest for an Active Directory member system looks like:

# For our purposes, an Active Directory member should:

# 1. Run winbind to enumerate users and groups beyond what's already in
#    /etc/passwd and /etc/group (requires working machine account in
#    domain)

# 2. Keep a list of valid users for the local system, since not all
#    domain users should get automatic shell access

# 3. Check passwords via Kerberos

class active-directory-member {
    package {
        [ "winbind", "krb5-config", "libpam-krb5" ]:
            ensure    => installed;
    service { [ "winbind" ]:
        pattern   => "/usr/sbin/winbindd",
        ensure    => running,
        subscribe => [ File["/etc/samba/smb.conf"],
                       File["/var/lib/samba/secrets.tdb"] ];
    file {
            source => "puppet:///files/apps/samba/smb.conf";

            ensure => directory,
            owner  => root,
            group  => root,
            mode   => 755;

            source => "puppet:///private/secrets.tdb",
            owner  => root,
            group  => root,
            mode   => 600;

            source => "puppet:///files/apps/active-directory-member/nsswitch.conf";

            source => "puppet:///files/apps/active-directory-member/common-account";

            source => "puppet:///files/apps/active-directory-member/krb5.conf";

            source => "puppet:///files/apps/active-directory-member/common-auth";

            source => "puppet:///files/apps/pam_listfile/users.conf.default";

Most of this is pretty straightforward Puppet management (“I need winbind, libpam-krb5, and krb5-config installed.” “Make sure winbind is running, and restart it if the machine account file or the Samba configuration file changes.” “Grab these Kerberos config files from the puppet server.”) A few things that might be non-obvious:

I’ve got a private fileserver area on the puppet server. I use this to store system-specific security information, such as ssh keys and the Samba machine account (secrets.tdb) for Active Directory. Barring a puppet-level breakin on the gold server or a root-level breakin on the CVS server, this is safe. Only systems with properly signed keys get access to their specific private folder, and they don’t get access to any other system’s private folder.

The Samba configuration I use for systems that only need winbind running is pretty minimal:

   netbios name = %h-linux
   workgroup = CAE
   log file = /var/log/samba/log.%m
   max log size = 1000
   syslog = 0
   panic action = /usr/share/samba/panic-action %d
   security = ADS
   realm = CAE.TNTECH.EDU
   allow trusted domains = No
   idmap backend = idmap_rid:CAE=5000-100000000
   idmap uid = 5000-100000000
   idmap gid = 5000-100000000
   template shell = /bin/bash
   winbind use default domain = Yes
   winbind nested groups = Yes
; The following was the default behaviour in sarge
; but samba upstream reverted the default because it might induce
; performance issues in large organizations
; See #368251 for some of the consequences of *not* having
; this setting and smb.conf(5) for all details
;   winbind enum groups = yes
;   winbind enum users = yes
   winbind enum users = No
   winbind enum groups = No

but it’s good enough to tell winbind where to look for username, UID, and GID information. netbios name is set differently from the default to ensure that we don’t have a conflict on dual-boot systems between their Windows machine account and their Linux machine account. On Linux-only systems, I could get away with using the default, but this setting works in both cases, so I’ll likely keep it as-is.

Since all my winbind systems use the same idmap backend and read the same RIDs from Active Directory (added in Samba 3.0.8, November 2004), they all calculate the same UIDs and GIDs. No NFS problems there any more. One step that’s not yet automated is the initial creation of an Active Directory machine account. On larger rollouts, I expect I’ll ssh into each system and run that part by hand. Eventually, I plan to either put this into a puppet manifest or into my preseed configuration. I’ll also need to make sure that I periodically sync the machine accounts from the local systems to the gold server, since Active Directory machine accounts change their own passwords from time to time.

nsswitch.conf has added entries for winbind on the passwd, group, and shadow databases:

# /etc/nsswitch.conf
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         compat winbind
group:          compat winbind
shadow:         compat winbind

hosts:          files dns
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis

common-account and common-auth are where most Debian PAM-aware applications look for account and authentication information, respectively.

# /etc/pam.d/common-account - authorization settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authorization modules that define
# the central access policy for use on the system.  The default is to
# only deny service to users whose accounts are expired in /etc/shadow.
account sufficient
account required onerr=fail sense=allow file=/etc/security/users.conf item=user
account required

If we’re looking up an account entry (not a password):

  1. If they’re in the local passwd file, they’re allowed.
  2. If they’re in the list of allowed users, they’re allowed. Otherwise, they’re not, so don’t go any further.
  3. If you’ve gotten this far, and they’re in the Active Directory, they’re allowed.
# /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.
auth    sufficient nullok_secure
auth    required use_first_pass

If we’re looking up a password entry:

  1. If you can verify them from the local shadow file, they’re allowed. No need to look any further.
  2. If you can verify them from the Active Directory via Kerberos, they’re allowed.

krb5.conf is set the same way as I noted in the previous post. Mostly, it just needs to have kdc entries for each Active Directory server, and admin_server set to the Active Directory master, and default_realm set to the Active Directory domain name.

users.conf is generated on the puppetmaster by concatenating one file per user from a users.conf.d directory. Each file contains one line: the user’s username. Eventually, we may modify things to make each file a group of users (one faculty’s advisees, all the members of an advanced class, etc.), but for now, echo bob > /etc/puppet/files/apps/pam_listfile/users.conf.d/bob works ok for us. The puppetmaster’s manifest now includes:

    concatenated_file {
            dir => "/etc/puppet/files/apps/pam_listfile/users.conf.d"

using David Schmitt’s /etc/puppet/manifests/definitions/concatenated_file.pp — at one point, I had the client systems running concatenated_file themselves, but the latency and md5 load for 270+ one-line files on the puppetmaster was ridiculous.

{ 4 } Comments

  1. Lindsay Holmwood | December 4, 2007 at 7:23 pm | Permalink

    Fantastic guide. It’s great to see this sort of quality documentation for Puppet appearing. :-)

  2. Charlie Redditt | February 23, 2008 at 1:19 pm | Permalink

    Attaching a prefix to the hostname (%h) avoids the Jekyll and Hyde issue of both installs trying to both join the domain using the same netbios name.

    But consider my situation where a dual boot box (XP/Ubuntu) has a shared printer and shared drives. I would like it so that other users on the network don’t have to know what OS the dual boot box is currently running in order to access that machine’s printer or shared drives.

    I’ve tried getting both to use the same machine account name, SID, and password, (using things like NETDOM.exe and “net -f CHANGESECRETPW” but so far not much luck.

    I know it’s possible for two different OS installs to share the same machine account, as M$ actually makes provisions for this, due to the necessity of disabling automatic machine acct password changes if it’s going to work over time.


    But getting Linux and Windows to share, I don’t know…

    There may be an easier way, however, using netbios aliases instead of actually using the same machine account. After all, I’m mostly concerned with how things appear on the network than the actual accts.


  3. Mike Renfro | February 23, 2008 at 3:43 pm | Permalink

    I agree that the netbios alias is about the only way to accomplish exactly what you’re after. In my case, none of our dual-boot systems offer print or file services to anyone — all that is handled primarily by dedicated servers, and occasionally by systems that don’t dual-boot. Long term, you may decide to do similarly — you don’t necessarily want to risk rebooting during someone’s print job or other use of the SMB share.

    EDIT: oh, and I guess I didn’t explicitly mention that I use the above smb.conf exclusively on regular workstations that just need winbind and Active Directory authentication. The fileserver, webserver, etc. all get different configurations.

  4. oes tsetnoc | September 27, 2009 at 9:10 pm | Permalink

    Fantastic, straight to the point and very usable … wish all documentation was the same . 😉

{ 3 } Trackbacks

  1. […] an entire followup artcle for my authentication notes, I’ll hold off on that part for now which can be found here. But the Amanda configuration code, that’s worth talking about […]

  2. Mike Renfro’s Blog : Directory Servers | October 31, 2007 at 10:38 am | Permalink

    […] I don’t use automount, and the vast majority of UID/GID mappings I already covered in the Authentication Servers post, though it may technically belong here. One other thing at the bottom of the […]

  3. […] Mike Renfro’s Blog : Authentication Servers, the Next Generation – July 7th ( tags: samba puppet kerberos linux activedirectory ad windows deploy tips tricks ) […]

Post a Comment

Your email is never published nor shared. Required fields are marked *