Samba Active Directory Domain Controller on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and operation of a Samba Active Directory Domain Controller on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Samba is the standard open source implementation of the SMB protocol and of Active Directory. In AD DC mode a single service provides a Kerberos KDC, an LDAP directory, SMB file services and the internal DNS that Active Directory depends on.
The image installs Samba 4.19.5 from the Ubuntu 24.04 archive, main component, with no third party repository. That choice is deliberate and it is the foundation of this listing: packages in main are security maintained by Ubuntu for the life of the LTS release, and Samba security fixes are published to the noble-security pocket. Your VM receives them automatically through unattended upgrades.
A note on version numbers. Upstream Samba has released newer feature branches than 4.19.5. This does not mean the image is unpatched. Ubuntu backports security fixes onto the 4.19.5 base and publishes them as revisions such as 2:4.19.5+dfsg-4ubuntu9.6. Being behind on the upstream feature number only means unpatched where a distribution does not backport, and Ubuntu does. The most recent upstream advisory covered six CVEs; Ubuntu shipped fixes for five of them on the embargo date itself, including a CVSS 10.0 unauthenticated remote code execution flaw in the printing subsystem, and Ubuntu is not affected by the sixth because that flaw was introduced in a later Samba branch than the one Ubuntu ships.
The image contains no domain. This is the single most important thing to understand about this appliance. An Active Directory domain is an identity, not just a daemon: provisioning mints the realm, the machine SID, the krbtgt key and the Administrator password in one shot. If a provisioned domain were baked into the image, every customer would receive the same krbtgt key, and anyone holding the image could forge Kerberos golden tickets into every other customer's domain. So this image ships with no realm, no machine SID, no krbtgt key, no Administrator password and no directory databases at all. The samba-ad-dc service is installed but disabled and unprovisioned. Your domain is created on first boot of your own VM, with secrets generated on that machine.
This is a private network appliance. A domain controller must never be exposed to the internet. Every port below should be reachable only from your own VNet and subnets.
What is included:
-
Samba 4.19.5 in Active Directory Domain Controller mode from the Ubuntu 24.04 archive (main), security maintained through the
noble-securitypocket -
A complete per VM domain minted on first boot: realm
AD.CLOUDIMG.INTERNAL, NetBIOS domainCLOUDIMG, a 144 bit random Administrator password, and a machine SID and krbtgt key unique to your VM -
Kerberos KDC, LDAP directory (with LDAPS and StartTLS), SMB file services and Active Directory internal DNS in one systemd unit
-
Credentials written to
/root/samba-ad-dc-credentials.txt(mode 0600, root only) and summarised in the message of the day -
Two independent fail closed safety levers: the domain controller will not serve if first boot provisioning genuinely failed, and a preflight check re validates the directory on every start
-
Unattended security upgrades left enabled exactly as stock Ubuntu, so Samba fixes land on your VM automatically
Prerequisites
-
Active Azure subscription, SSH public key, VNet and subnet in the target region
-
Subscription to the Samba Active Directory Domain Controller listing on Azure Marketplace
-
A static private IP for the VM. A domain controller's clients resolve the domain through the controller itself, so an IP that changes on restart breaks the domain.
-
Network Security Group rules allowing the Active Directory ports from your own VNet only (see Step 3)
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for a small directory. Larger directories and busy authentication loads should use Standard_D2s_v5 or larger.
Step 1: Deploy from the Azure Portal
Search Samba Active Directory Domain Controller in Marketplace, select the cloudimg publisher, and click Create.
Two settings matter more than anything else on the create blade:
-
Assign a static private IP. Under Networking, set the private IP allocation to Static. The domain controller registers its own address in Active Directory DNS at first boot.
-
Do not give the VM a public IP unless you genuinely need one for administration, and if you do, restrict SSH to your management address only. A domain controller belongs on a private network.
The VM name becomes the domain controller's hostname. NetBIOS computer names are limited to 15 characters, so a VM name longer than that is truncated in the NetBIOS name (a VM named samba-ad-dc-build registers the NetBIOS name SAMBA-AD-DC-BUI). Both names are registered in DNS, so the domain still resolves, but keeping the VM name to 15 characters or fewer avoids the surprise.
Step 2: Deploy from the Azure CLI
Note the --private-ip-address argument: it pins the static private IP the domain controller will register in its own DNS.
RG="ad-prod"; LOCATION="eastus"; VM_NAME="samba-ad-dc"; DC_IP="10.0.0.4"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/samba-ad-dc-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--vnet-name ad-vnet --subnet ad-subnet \
--private-ip-address "$DC_IP" \
--public-ip-address ""
Step 3: Open the Active Directory ports to your VNet only
Active Directory needs a wide set of ports. Open them from your VNet address space only, never from the internet.
Note the ephemeral RPC range 49152 to 65535. Active Directory's RPC services (replication, and many management operations) negotiate a dynamic high port, so domain joins and administration fail in confusing ways without it. It is a range of 16,384 ports, so it is opened as a single range rule rather than as individual port entries.
RG="ad-prod"; NSG="ad-nsg"; VNET_CIDR="10.0.0.0/16"
# Core AD: DNS 53, Kerberos 88, RPC endpoint mapper 135, NetBIOS 139,
# LDAP 389, SMB 445, kpasswd 464, LDAPS 636, Global Catalog 3268/3269
az network nsg rule create --resource-group "$RG" --nsg-name "$NSG" \
--name allow-ad-core --priority 1001 \
--source-address-prefixes "$VNET_CIDR" --destination-port-ranges 53 88 135 139 389 445 464 636 3268 3269 \
--protocol '*' --access Allow --direction Inbound
# Ephemeral RPC high ports — required for domain joins and replication
az network nsg rule create --resource-group "$RG" --nsg-name "$NSG" \
--name allow-ad-rpc-ephemeral --priority 1002 \
--source-address-prefixes "$VNET_CIDR" --destination-port-ranges 49152-65535 \
--protocol Tcp --access Allow --direction Inbound
# SSH for administration — restrict to your management network
az network nsg rule create --resource-group "$RG" --nsg-name "$NSG" \
--name allow-ssh-mgmt --priority 1003 \
--source-address-prefixes "$VNET_CIDR" --destination-port-ranges 22 \
--protocol Tcp --access Allow --direction Inbound
Step 4: First boot
On first boot the image reads the VM's private IP and hostname, provisions a brand new Active Directory domain with a 144 bit random Administrator password, proves that Kerberos issues a ticket and that the domain's DNS SRV records resolve, takes over DNS on port 53 for the realm, and writes the credentials file. This completes in well under a minute.
The built in Administrator password is pinned to never expire. Active Directory's default maximum password age is 42 days, which would otherwise silently break a working domain six weeks after deployment for no security benefit.
SSH in as azureuser and read the details:
sudo cat /root/samba-ad-dc-credentials.txt
Step 5: Confirm the domain your VM minted
samba-tool domain info reports the realm, the NetBIOS domain and this controller's own name. The unified samba-ad-dc service provides every AD role; the standalone smbd, nmbd and winbind units are deliberately disabled because they would fight the unified service for the same sockets.
sudo samba-tool domain info 127.0.0.1
systemctl is-active samba-ad-dc
ss -tln | awk '/:53 |:88 |:389 |:445 |:636 |:3268 /{print $1, $4}' | sort -u

Step 6: Prove Kerberos issues a real ticket
The domain controller runs a Kerberos KDC. Requesting a ticket granting ticket for the Administrator account proves the KDC is genuinely authenticating, not merely listening.
This command reads the generated password straight from the root only credentials file, so nothing is typed or echoed:
sudo bash -c 'PW=$(grep "^samba.admin.password=" /root/samba-ad-dc-credentials.txt | cut -d= -f2-); printf "%s" "$PW" | kinit Administrator@AD.CLOUDIMG.INTERNAL && klist'
klist shows a real krbtgt/AD.CLOUDIMG.INTERNAL@AD.CLOUDIMG.INTERNAL ticket. A deliberately wrong password is rejected with a preauthentication failure, which is what confirms the check is real.

Step 7: Browse and manage the directory
samba-tool manages users and groups. The freshly minted domain contains only the built in accounts (Administrator, Guest and the krbtgt service account) and the standard Active Directory groups.
sudo samba-tool user list
sudo samba-tool group list | head -14
Creating a user and reading it back proves the directory is writable:
sudo samba-tool user create demo.user 'Dem0-Passw0rd!2026' --given-name=Demo --surname=User
sudo samba-tool user show demo.user | grep -E '^(dn|sAMAccountName|userPrincipalName):'
sudo samba-tool user delete demo.user

Step 8: LDAP access is encrypted or it is refused
The directory is an LDAP server. You can read the naming context anonymously, but any authenticated bind must be encrypted. Samba enforces ldap server require strong auth, so a simple bind over plain ldap:// is refused before the password can cross the wire. Use StartTLS (-ZZ) or ldaps:// on port 636.
sudo bash -c 'IP=$(grep "^samba.dc.ip=" /root/samba-ad-dc-credentials.txt | cut -d= -f2-); ldapsearch -x -LLL -H "ldap://$IP" -s base -b "" namingContexts'
The image uses a self signed certificate generated at provisioning time, so LDAPTLS_REQCERT=never is used here for a local check. Distribute your own CA and drop that override for production clients.
sudo bash -c 'set -e
CREDS=/root/samba-ad-dc-credentials.txt
PW=$(grep "^samba.admin.password=" $CREDS | cut -d= -f2-)
REALM=$(grep "^samba.realm=" $CREDS | cut -d= -f2-)
FQDN=$(grep "^samba.dc.fqdn=" $CREDS | cut -d= -f2-)
BASE=$(grep "^samba.realm=" $CREDS | cut -d= -f2- | tr "A-Z" "a-z" | sed "s/^/DC=/; s/\./,DC=/g")
LDAPTLS_REQCERT=never ldapsearch -x -ZZ -LLL -o ldif-wrap=no -H "ldap://$FQDN" \
-D "Administrator@$REALM" -w "$PW" -b "$BASE" "(sAMAccountName=Administrator)" dn | grep "^dn:"'

Step 9: Point your VNet DNS at the domain controller
Active Directory clients find the domain through its DNS SRV records, which only this controller serves. Set your VNet's DNS server to the controller's static private IP, then restart the client VMs so they pick up the change.
In the Portal: Virtual network > DNS servers > Custom, and enter the controller's private IP.
Or from the Azure CLI on your own workstation:
RG="ad-prod"; VNET="ad-vnet"; DC_IP="10.0.0.4"
az network vnet update --resource-group "$RG" --name "$VNET" --dns-servers "$DC_IP"
Verify from a client VM in the same VNet that the domain's SRV record resolves:
host -t SRV _ldap._tcp.ad.cloudimg.internal
Step 10: Use your own realm (optional, do this before anything else)
The realm AD.CLOUDIMG.INTERNAL is a documented default namespace, not a secret. It is the DNS equivalent of a default base DN. Many deployments keep it. If you want your own realm, re provision now, before you join any machine or create any user, because the realm cannot be changed afterwards without rebuilding the domain.
On a freshly deployed VM this is free and takes about 30 seconds. Choose a realm you control, and never use a .local suffix (it is reserved for mDNS and it will cause resolution problems). A subdomain of a domain you own, or a .internal name, is the right choice.
The following block is destructive. It permanently deletes the domain the VM minted on first boot, including its Administrator password and every account in it. Run it only on a VM you have just deployed and do not paste it into a working domain controller.
# DESTRUCTIVE — this DELETES the existing domain. Fresh VMs only.
REALM="AD.EXAMPLE.COM" # your realm, uppercase
NETBIOS="EXAMPLE" # <= 15 chars, no dots
ADMIN_PW='ChangeMe-Str0ng!2026' # your Administrator password
sudo systemctl stop samba-ad-dc
sudo rm -rf /var/lib/samba/private /var/lib/samba/sysvol /var/lib/samba/bind-dns
sudo rm -f /etc/krb5.conf /etc/samba/smb.conf
sudo install -d -m 0700 /var/lib/samba/private
sudo samba-tool domain provision \
--use-rfc2307 --realm="$REALM" --domain="$NETBIOS" \
--server-role=dc --dns-backend=SAMBA_INTERNAL \
--adminpass="$ADMIN_PW"
sudo cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
sudo samba-tool user setexpiry Administrator --noexpiry
sudo systemctl start samba-ad-dc
# Point the VM at its own DNS and confirm the new realm:
sudo samba-tool domain info 127.0.0.1
kinit "Administrator@$REALM"
After re provisioning, update /root/samba-ad-dc-credentials.txt (or your own secret store) so the recorded realm and password match reality.
Step 11: Join a machine to the domain
Point the client's DNS at the domain controller first; every join failure that is not a firewall problem is a DNS problem.
On a Windows client, join from an elevated PowerShell prompt and enter the Administrator credentials when prompted:
Add-Computer -DomainName ad.cloudimg.internal -Restart
On an Ubuntu client, realmd performs the join:
sudo apt-get install -y realmd sssd sssd-tools adcli krb5-user
sudo realm join --user=Administrator ad.cloudimg.internal
If a join fails, confirm in this order: the client resolves _ldap._tcp.ad.cloudimg.internal; the NSG allows the core AD ports and the ephemeral RPC range 49152 to 65535; and the client's clock is within five minutes of the controller's, because Kerberos rejects tickets outside that skew.
Step 12: Security recommendations
-
Never expose this VM to the internet. Keep every Active Directory port reachable only from your own VNet, and prefer a VM with no public IP at all.
-
Keep the static private IP. The controller registers its address in its own DNS; changing it breaks the domain for every client.
-
Rotate the generated Administrator password into your own secret store after deployment, then remove
/root/samba-ad-dc-credentials.txt. It is mode 0600 and root only, but it is still a password on disk. -
Replace the self signed LDAPS certificate with one from your own CA and distribute the CA to clients, so that clients can verify the controller rather than trusting it blindly.
-
Leave unattended upgrades enabled. Samba security fixes reach this VM through the
noble-securitypocket automatically. Confirm withsystemctl is-enabled unattended-upgrades. -
Back up the directory, not just the disk.
samba-tool domain backup offline --targetdir=/var/backups/sambaproduces a restorable copy of the domain. -
A single domain controller is a single point of failure. For production, join a second controller to the domain so authentication survives losing one VM.
Step 13: Support and Licensing
Samba is developed by the Samba Team and distributed under the GNU General Public License version 3 or later (GPL-3.0-or-later). This cloudimg image bundles the unmodified Samba packages from the Ubuntu 24.04 archive. In accordance with GPL-3 section 6, the complete corresponding source is available from the Ubuntu archive with apt-get source samba (the image ships with source repositories already enabled), and a three year written offer for the source code is included on the image at /usr/share/doc/cloudimg/SAMBA-GPL-3-WRITTEN-OFFER.txt, valid for anyone in possession of the object code.
The Active Directory schema files bundled with Samba are distributed under the Microsoft Active Directory Schema License (MS-ADSL) and were accepted into the Debian and Ubuntu main archive under that licence.
cloudimg provides the packaging, the per VM domain provisioning automation, the fail closed safety levers, the Azure specific hardening and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with, endorsed by, or sponsored by the Samba Team. Samba is a trademark of its respective owner and is used here only to identify the software this image packages.
Deploy on Azure
Find Samba Active Directory Domain Controller on Ubuntu 24.04 LTS on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.