CentOS 7, Active Directory and Samba

After playing around with CentOS 7, I was amazed at how simple things that are traditionally annoying as heck are - if you get the config right, of course. One of these is getting a Linux share viewable on Windows clients, with Active Directory authentication and authorization, which I'm going to describe in this post.

I'm not going to assume anything other than a vanilla installation of CentOS 7 - so we'll be joining the domain first. If you Google around, you'll find tons of articles, with tons of configuration to do... thankfully that's all in the past now.

What you'll need to follow this guide:

  • Know your domain! Specifically,
    • the NetBIOS name (eg MYDOMAINLOCAL ),
    • the FQDN ( mydomain.local )
    • either the name or IP of a domain controller ( eg dc1.mydomain.local )
    • have an administrative account in the domain to enable computers to join it
  • You need to use the DC as your DNS! Obviously best setup when installing the system.
  • SELinux needs to be taken care of! (see notes inline, this causes most issues)
I'll be using some defaults across this guide - the domain is assumed to be mydomain.local (netbios MYDOMAINLOCAL, with the domain controller located at dc1.mydomain.local .

Joining Active Directory

And let the fun begin! First off, we need to get your server to join the domain. We'll start with some required packages:

$ yum install realmd samba samba-common oddjob oddjob-mkhomedir sssd ntpdate ntp

This will cause half a ton of packages to come your way, just let them in. Most of them are under the hood, and you'll never even notice they're there.

First thing we need to do is make sure the time is properly sync'd with your DC, otherwise most of the next steps fail (silently!).

$ systemctl enable ntpd.service
$ ntpdate dc1.mydomain.local
$ systemctl start ntpd.service 

Here, we first enable the ntp service on boot, manually sync the time to the DC, and start the service so it continually does that on its own.

It may be prudent to add your DC as the first server entry in /etc/ntp.conf, but at least in my case it was not necessary.

Now that the time is right, just type in this simple one-liner to join the domain:

$ realm join --user=adminuser@mydomain.local mydomain.local

and wait for the magic to happen. Unless something has gone terribly wrong, typing

$ realm list

should return an output similar to the following:

$ realm list
   mydomain.local
   type: kerberos
   realm-name: MYDOMAIN.LOCAL
   domain-name: mydomain.local
   configured: kerberos-member
   server-software: active-directory
   client-software: sssd
   required-package: oddjob
   required-package: oddjob-mkhomedir
   required-package: sssd
   required-package: adcli
   required-package: samba-common
   login-formats: %U@mydomain.local
   login-policy: allow-realm-logins
NOTE: It has been brought to my attention that in some (yet unknown) cases, if the above has not worked you can try adding the parameter --client-software=winbind to the realm join command - making it $ realm join --client-software=winbind --user=adminuser@mydomain.local mydomain.local

If you got this far, it means that you can now login to your server via SSH, using your AD credentials. Assuming you're using PuTTY, leave out the username and just SSH to the host. Your username should have the form myuser@mydomain.local, and your prompt will be .... myuser@mydomain.local@hostname (yes, with TWO @s! )

And with that, you're all set to proceed to the next step, which is...

Setting up Samba

As you might imagine, all you need to do is properly configure /etc/samba/smb.conf , so I'll dive right into it:

[global]
        workgroup = MYDOMAINLOCAL
        server string = Samba Server Version %v

        # Add the IPs / subnets allowed acces to the server in general.
        # The following allows local and 10.0.*.* access
        hosts allow = 127. 10.0.

        # log files split per-machine:
        log file = /var/log/samba/log.%m
        # enable the following line to debug:
        # log level =3
        # maximum size of 50KB per log file, then rotate:
        max log size = 50

        # Here comes the juicy part!
        security = ads
        encrypt passwords = yes
        passdb backend = tdbsam
        realm = MYDOMAIN.LOCAL

        # Not interested in printers
        load printers = no
        cups options = raw

        # This stops an annoying message from appearing in logs
        printcap name = /dev/null

[myshare]
  comment = My shared folder
  path = /var/myshare
  public = no
  writable = yes
  guest ok = no
  valid users = @"adgroup@mydomain.local"

Most of the above is self-explanatory, so I'll just highlight a couple of lines:

  • security = ads: because domain for some reason doesn't play nice
  • log level=3: if you find trouble, it will dump tons of log info in /var/log/samba/*
  • printcap name= /dev/null: avoids an error message everytime samba starts/stops about failing to get a list of printers from AD
  • valid users: This is the key here. The first character ( "@" ) denotes that this is a group. AD groups are inherited in the system as adgroup@mydomain.local, hence the quotes to escape the second @. Make sure it's all lowercase!
    Do note that the percentage character and recommended patterns ( "%", "%S", "MYDOMAINLOCAL\%S" ) which is shown in the documentation don't work in our method, since we're not using winbind!!

One more little tidbit - AD user groups are now system groups as well. Samba requires that users actually have system rights to the directory shared, so we'll make the directory as an example now, and assign proper permissions to it

$ mkdir /var/myshare
$ chown root:adgroup@mydomain.local /var/myshare
$ chmod 775 /var/myshare

Note the AD group there? Didn't even think that user groups can actually contain @s! After this step, you have a directory that is correctly setup for Samba to use.

Note about SELinux:
You either need to
  • disable it completely (by setting SELINUX=disabled in /etc/sysconfig/selinux ) or
  • enter the following command for each share you make:
    
    $ chcon -t samba_share_t /var/myshare
    
    
    (thanks B Packard!)

And even though this is mighty simple, we still need yet another little step: allowing the traffic through the firewall. Long gone are iptables though, and in the new and shiny syntax that is done via:

$ firewall-cmd --permanent --add-service=samba
$ firewall-cmd --reload

And you're thus in the position to fire it up:

$ systemctl enable smb.service
$ systemctl start smb.service

ensuring that the service is up, running, and will remain so after you reboot. Assuming you're sitting in your Windows client, just open a Windows Explorer ... window to \\linuxbox.domain.local , and you should see myshare listed there. Click on that and you should find yourself in that directory without a password ever being asked!

I'm dumbfounded at how simple this is, compared to the process in previous versions... which probably means I've omitted something. If you find it, let me know in the comments (expressions of pure joy are also accepted)!