Samba DC in a Linux Container (or Incus VM)
In this how-to I will be installing Samba as an Active Directory Domain Controller for a new domain. I learned a few things while I was getting setup and attempting to join a Samba DC to an existing domain. I aborted when I found Do not use .local for the TLD, this is used by Avahi.
in the Setting up Samba Document and decided to setup a new Domain. Here’s a few other tidbits that might be helpful.
- Debian Bookworm includes Samba 4.17 and so supports AD functional level 2008_r2, which might be why I had trouble joining my existing AD Domain.
- Samba 4.2 supports AD functional level 2016.
- Samba DC provisioning failed in an unprivileged container
Build a VM or privileged container
I received an error after running samba-tool domain provision
on an unprivileged container. Provisioning was successful in a VM, and a privileged container.
set_nt_acl_conn: fset_nt_acl returned NT_STATUS_ACCESS_DENIED.
ERROR(runtime): uncaught exception – (3221225506, ‘{Access Denied}
I will be using Incus on my Raspberry Pi 4 to build a VM, but a privileged container is just as easy to build. I’d prefer a VM because, even though it uses more resources, it doesn’t share the kernel like a container, so will be more secure.
incus launch images:debian/trixie sambadc01 --vm
If you prefer to use a privileged container:
incus launch images:debian/trixie sambadc01 --config security.privileged=true
To access a shell inside your container or VM:
incus exec sambadc01 -- bash
Prepare for Samba DC Install
First make sure your hostname is set, and your hosts file is accurate. Samba documents are very specific about using the following format for /etc/hosts.
127.0.0.1 localhost
172.16.1.2 sambadc01.example.lan sambadc01
The script at the bottom of this how-to attempts to get the IP address if you don’t provide one, but it will fail if there are multiple UP interfaces. The IP for the server should be static or manual because if the DHCP address changes later your server will break. You can set a static IP with an incus profile
Next turn off anything that messes with DNS, the most common culprit being resolvconf.
systemctl disable systemd-resolved
systemctl stop systemd-resolved
If you were running resolved, you need to replace the symlink at /etc/resolv.conf with an actual file. Chose a DNS server that will resolve internet addresses. The example below uses Google.
echo "nameserver 8.8.8.8" > /etc/resolv.conf
Install Samba DC in Debian Trixie
You will be prompted for information when you install krb5. Use your domain name in all caps as the default realm, EXAMPLE.LAN, and your server’s name for kdc and admin server, sambadc01.example.lan. Remember not to use the .local TLD.
apt install acl attr samba winbind libpam-winbind libnss-winbind dnsutils python3-setproctitle krb5-config krb5-user
Provision Samba Domain Controller
You can specify provisioning options at the command line or run provisioning interactively. Running interactively will prompt for information. See the script below for more details.
samba-tool domain provision
Test It
That’s it. You can now join computers to this domain. Computers that you want to join to this domain need to be able to resolve the domain name so set your workstation DNS to the domain controller and join using the Administrator account and password.
Script to Build a Samba Domain Controller for a new Domain
#!/bin/bash
if [ ! "$1" ]; then
echo "Usage: ./install_sambadc.sh DOMAIN-CONTROLLER-FQDN [SERVERIP]"
echo "If you do not specify an IP address the ip will be determined by the command:"
echo "ip -br -4 addr |grep "UP""
exit 1
fi
echo "Set the fqdn"
fqdn="$1"
hostnamectl set-hostname "$fqdn"
defaultRealm="$(echo $1|cut -d . -f 2-|tr [:lower:] [:upper:])"
domain="$(echo $defaultRealm|tr [:upper:] [:lower:])"
kdc="$1"
adminServer="$1"
friendlyName="$(echo $1|cut -d . -f 1)"
domainName="$(echo $defaultRealm|cut -d . -f 1)"
echo "Get the active IP"
if [ "$2" ]; then
activeIP="$2"
else
activeIP="$(ip -br -4 addr |grep "UP" \
|grep -Eo '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])')"
fi
echo "Rewrite /etc/host with fqdn"
mv /etc/hosts /etc/hosts.bak
cat << EOF > /etc/hosts
127.0.0.1 localhost
$activeIP $fqdn $friendlyName
EOF
echo "Disable resolvconf"
systemctl disable systemd-resolved
systemctl stop systemd-resolved
echo "Rewrite /etc/resolv.conf google dns"
mv /etc/resolv.conf /etc/resolv.conf.bak
echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "Install samba"
apt update -yq
apt upgrade -yq
apt install acl attr samba winbind libpam-winbind libnss-winbind dnsutils python3-setproctitle -yq
echo "Install krb5"
export DEBIAN_FRONTEND=noninteractive
apt install krb5-config krb5-user -yq
export DEBIAN_FRONTEND=""
echo "Remove smb.conf before provisioning"
rm /etc/samba/smb.conf
echo "Stop samba services and disable"
systemctl stop smbd nmbd winbind
systemctl mask smbd nmbd winbind
systemctl disable smbd nmbd winbind
echo "Generate Password"
adminPass="$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32;echo;)"
#echo "$adminPass"
echo "$adminPass" > /root/samba.pass
chmod 400 /root/samba.pass
echo "Rewrite /etc/resolv.conf self"
mv /etc/resolv.conf /etc/resolv.conf.bak
echo "search $domain" > /etc/resolv.conf
echo "nameserver $activeIP" >> /etc/resolv.conf
echo "Provision"
samba-tool domain provision --use-rfc2307 \
--realm="$defaultRealm" \
--domain="$domainName" \
--server-role=dc \
--dns-backend=SAMBA_INTERNAL \
--adminpass="$adminPass"
echo "Copy krb5.conf"
cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
echo "Setup dns forwarder"
grep "dns forwarder" /etc/samba/smb.conf > /dev/null
sed -i 's/dns forwarder.*$/dns forwarder = 8.8.8.8/g' /etc/samba/smb.conf
echo "Restart ad service"
killall samba
systemctl start samba-ad-dc.service