Friday, December 20, 2013

Part III - The Ultimate Linux Home Router - Active Directory on openSUSE using Samba 4.1

Compiling the Latest Version of Samba 4

Samba 4 is the first version of Samba to adequately host Active Directory without the need for an expensive Windows Server. Though it's been in the wild for a while now, it's still got some rough points. I've been using it for a few months now and the only issues I've run into have been centered purely around Microsoft applications that require schema updates to function. I'm running it with a single domain controller, so I've not tried to get replication functional (this is, after all, just a home network).
There are samba packages in the Tumbleweed repository, but at this point in time they are not at the version I needed, so we'll be compiling from the source. Parts of this entry were adapted from Conrad Jones blog. Much thanks to him for publishing that. Run the following commands (make, gcc and binutils will already be present if you opted to install fish):
# zypper install make gcc binutils autogen krb5-devel krb5-client nano libacl-devel acl attr python python-devel
You may get a message indicating that python conflicts with patterns-openSUSE-minimal_base-conflicts, select to deinstall if this pops up.
# reboot
We need to reboot to ensure that the filesystem is mounted with ACL support. After reboot, login:
$ su
(Enter your password)
# cd ~
# wget http://www.samba.org/samba/ftp/stable/samba-4.1.3.tar.gz
# tar -xvf samba-4.1.3.tar.gz
# cd samba-4.1.3/
# ./configure; and make; and make install
You may want to visit Samba's Website to find the latest version rather than using 4.1.3. They move pretty quickly over there (a samba server I just installed two weeks ago was 4.1.1).
After about ten minutes, you should be compiled and ready to start configuring Samba and creating your new Active Directory domain.
Note: If you're wondering why the compile command issued was ./configure; and... instead of ./configure &&..., && is one of a handful of things fish shell doesn't support. If you're going to switch your shell to fish long-term, keep that in mind when viewing articles that have linux commands embedded. The syntax above will work in fish and bash.

Creating Samba Service Definition

# nano /usr/lib/systemd/system/samba.service
Copy and paste the following into the editor:
[Unit]
Description=Samba AD Daemon
After=syslog.target network.target
 
[Service]
Type=forking
PIDFile=/usr/local/samba/var/run/samba.pid
LimitNOFILE=16384
EnvironmentFile=-/etc/sysconfig/samba
ExecStart=/usr/local/samba/sbin/samba $SAMBAOPTIONS
ExecReload=/usr/bin/kill -HUP $MAINPID
 
[Install]
WantedBy=multi-user.target
Hit Ctrl+O (Write Out) and Ctrl+X (Exit).
Now we'll create a symbolic link to the service and configure it to run at startup
# ln -s /usr/lib/systemd/system/samba.service /etc/systemd/system/samba.service
# systemctl enable samba

Installing BIND 9 (Optional, use BIND 9 backend)

Personally, I prefer to stick with BIND over the default SAMBA DNS. It's rock solid, configurable, and there's a ton of information on how to tweak it because it's so widely used. You can stick with the internal DNS implementation if you want (and it's certainly a lot fewer steps), but I elected to use BIND.
# zypper in bind

Edit the configuration files

Now we need to add some parameters to the existing named.conf.
# nano /etc/named.conf
Directly beneath options {, put the following lines:
        # BEGIN ---- Configuration Modifications
        auth-nxdomain yes;
        # NOTE: These are the opendns.org DNS servers. I choose to use them instead
        #       of the ones provided by my ISP. They're available globally so they
        #       should work fine, however, if your ISP or router adds their own split-brain
        #       DNS (U-Verse typically does this to make it easy to connect to your
        #       router information page), you will not be able to connect to their
        #       custom DNS entries.
        forwarders { 208.67.222.222; 208.67.220.220; };
        allow-transfer { none; };

        # IMPORTANT: Change the below to point to values appropriate for YOUR home network.
        #            I used 192.168.0.0 for my wired internal network and 192.168.2.0 for
        #            my guest wireless restricted internal network.
        allow-query {
                127.0.0.0/24;
                192.168.0.0/24;
                192.168.2.0/24;
        };

        # IMPORTANT: You should only EVER let hosts sitting on the non-internet side
        #            of your router allow recursion even if you allow queries from
        #            external networks!
        allow-recursion {
                127.0.0.0/24;
                192.168.0.0/24;
                192.168.2.0/24;
        };

        pid-file "/var/run/named/named.pid";
        empty-zones-enable no;
        # END   ---- Configuration Modifications
A note about some ISP networks: I have an ISP that provides me with an actual router. Ideally, we want to set up that router to pass all traffic to this router and do nothing else with it (disabling all firewall features). Sometimes this is done in a way that results in your external network card receiving your actual public routable IP. Sometimes this is done by setting the external interface as a DMZ host. The difference between them is negligible. With my ISP, if I want to have this box actually get the public IP address, I have to pay for a static IP. So I opted to use the DMZ method. This matters for only one reason NEVER include the network that is internal to your ISP provided router in the allow-query or allow-recursion section.. If you do that, you're actually allowing the entire internet to query and recurse on your DNS server. If you want to allow querying, simply add the external network zone to the allow-query section, but definitely do not add it to the allow-recursion section.

Modify the localhost Zone Files

# rm /var/lib/named/localhost.zone
# rm /var/lib/named/127.0.0.zone
# nano /var/lib/named/localhost.zone
Paste the following into localhost.zone:
$TTL 1W

$ORIGIN localhost.

@       1D      IN      SOA     @   root (
                        42              ; serial (d. adams)
                        8H              ; refresh
                        2H              ; retry
                        4W              ; expiry
                        1D              ; minimum
                        )

@       IN      NS      @
        IN      A       127.0.0.1
        IN      AAAA    ::1
# nano /var/lib/named/127.0.0.zone
Paste the following into 127.0.0.zone:
$TTL 1W

@       IN      SOA             localhost.   root.localhost. (
                                42              ; serial (d. adams)
                                8H              ; refresh
                                2H              ; retry
                                4W              ; expiry
                                1D              ; minimum
                                )

                IN NS           localhost.

1               IN PTR          localhost.
Fix permissions:
# chown named:named /var/lib/named/*.zone
# chmod 640 /var/lib/named/*.zone
Let's test the configuration:
# named -u named
Did you see nothing? Good. Otherwise, if you got an error, run through the configuration parts of this section again and make sure you set it up correctly.

Configuring for hosting services on our Internal network

Now that we're actually going to HOST something and we have DNS setup, we need to stop requesting DHCP addresses. We're going to ignore wireless for now. I currently have only one network adapter plugged in since my other is USB based and I don't need it quite yet, so I'll be referring to the only adapter that I have. If you're following along with this from Part I, you should only have one cable plugged in and that should be your plugged into your internal network.
# yast
Select Network Devices and then Network Settings.

You're on the Overview screen. Select the network adapter that represents your plugged-in Ethernet adapter and choose Edit.
Put an X next to Statically assigned IP Address and hit TAB
Set your IP address to the desired value and hit TAB. I'm using 192.168.0.1 since .1 is commonly the router IP address.
Set your Subnet Mask and hit TAB. I'm using 255.255.255.0.
Set your fully qualified host name. This will be the computer hostname and the domain name that corresponds with your DNS and Active Directory domain. Example: host.somedomain.com
Go to the General tab.
Make sure Assigned Interface to Firewall Zone is set to Internal Zone (unprotected)
Hit F10
Go to Hostname/DNS and select Name server 1
Set it to the IP address you assigned above.
Go to Routing and select Default IPv4 Gateway and set it to your current, functioning router's IP. Do the same for IPv6 if applicable.
Hit F10 and once.
... and ... it hangs (or disconnects)! You just changed your IP address. Reconnect, but use the IP address you just set.
$ su
(enter your password)
# chkconfig -s named on
# rcnamed start
# rcnamed status
You should see the status as active (running). Now we'll test localhost lookup:
# host localhost. 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:

localhost has address 127.0.0.1
And reverse lookup:
# host 127.0.0.1 127.0.0.1
You should see:
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases: 

1.0.0.127.in-addr.arpa domain name pointer localhost.
And let's nslookup something.
# nslookup google.com
You should get back results. If you do not, "nano /etc/resolv.conf" and make sure the line that says "nameserver" reads "nameserver 192.168.0.1" or whatever the IP address that you used for your server. Yast failed to update it when I updated the network settings. If it's different, change it, save it and try nslookup again

Provisioning our Active Directory Domain

We'll use samba-tool to provision the domain.
# /usr/local/samba/bin/samba-tool domain provision --use-rfc2307 --interactive
You'll be prompted for values. Most should be the defaults if you've been following the configuration since Part 1.
Realm [YOURDOMAIN.NET]:
 Domain [YOURDOMAIN]:
 Server Role (dc, member, standalone) [dc]:
 DNS backend (SAMBA_INTERNAL, BIND9_FLATFILE, BIND9_DLZ, NONE) [SAMBA_INTERNAL]: BIND9_DLZ
Administrator password:
Retype password:
Make sure to set the DNS backend to BIND9_DLZ

Updating BIND configuration to include samba entries

# nano /usr/local/samba/private/named.conf
Put a "#" in front of the 'database "dlopen /usr/local/samba/lib/bind9/dlz_bind9.so"' and remove the "#" from 'database "dlopen /usr/local/samba/lib/bind9/dlz_bind9_9.so"'.
Save and exit.
# nano /etc/named.conf
Add the following to the top of the file:
include "/usr/local/samba/private/named.conf";
Save and Exit.
And finally, we have to prevent BIND from running chrooted so that it can find the dlz_bind9_9.so file.
nano /etc/sysconfig/named
Change the line that reads NAMED_RUN_CHROOTED="yes" to NAMED_RUN_CHROOTED="no".
# systemctl start samba
# rcnamed restart
# rcnamed status
You should see that the server is running. Now let's check that the samba entries have been created:
# host -t SRV _ldap._tcp.yourdomain.net
You should see:
_ldap._tcp.diagonactic.net has SRV record 0 100 389 yourdomaincontroller.yourdomain.net.

Configuring Kerberos and testing your new domain

We need to be able to get kerberos tickets, so we're going to configure the kerberos client and give it a test.
# cp /usr/local/samba/private/krb5.conf /etc/krb5.conf
# kinit administrator@YOURDOMAIN.NET
(enter the password you provided in the samba-tool step above
The capital letters are not optional. You should see a message about your password expiring in several days. Now, let's see if you have a ticket.
# klist
You should see a ticket in the list with a start date, expiration date and a renew until date that corresponds with the user you entered in the kinit statement above.

Configuring your server to backup your Active Directory environment

Especially since Active Directory support in Samba is relatively new and has bugs being fixed constantly, it's a good idea to have a backup because you'll probably be applying updates. And the fact that an AD domain is something that's usually in a state of flux, it's a good idea to get that started now.
# cp ~/samba-4.1.3/source4/scripting/bin/samba_backup /usr/sbin
# chown root:root /usr/sbin/samba_backup
# chmod 750 /usr/sbin/samba_backup
# mkdir /usr/local/backups
# chmod 750 /usr/local/backups
# ln -s /usr/sbin/samba_backup /etc/cron.daily/samba_backup
# nano /usr/sbin/samba_backup
Find the part of the script that looks like this:
                for ldb in `find $relativedirname -name "*.ldb"`; do
                        tdbbackup $ldb
                        if [ $? -ne 0 ]; then
                                echo "Error while backuping $ldb"
                                exit 1
                        fi
                done
Change the "tdbbackup $ldb" line to this (you can also add samba to your path, however, this guarantees the script will execute properly without the path variable set).
/usr/local/samba/bin/tdbbackup $ldb
Test the backup:
# /usr/sbin/samba_backup
# ls /usr/local/backups
samba_backup should return silently after running for a second and you should see files "etc..tar.bz2", "samba4_private..tar.bz2", and "sysvol..tar.bz2". If you ever need to restore, follow the instructions on the Samba Wiki.

No comments: