Initial commit: MAAS-deployable Samba Active Directory domain controller

Builds a Debian image that MAAS deploys to bare metal as an Active Directory
domain controller, with first-boot automation that either creates a domain or
joins an existing one without anyone logging in. To a Windows client the result
is an AD domain: same Kerberos, same LDAP, same Group Policy, same domain join.

The request was for "primary and backup domain controllers", which is NT 4
terminology. Active Directory has no such split — every DC holds a writable copy
and any of them can service a logon. What lives on one DC at a time are the five
FSMO roles, one confusingly named "PDC Emulator". The image therefore offers
provision (create the domain) and join (add another equal DC), which is the
distinction that actually exists.

Contents:

  * customize-samba-ad.sh, run inside the packer-maas build VM: installs samba,
    winbind, Kerberos, chrony and rsync, swaps the cloud kernel for the generic
    one, and deletes every trace of a domain so one image can produce many DCs
  * adc-maas-init, a first-boot state machine covering /etc/hosts, node-unique
    identifiers, time, the resolver, provisioning or joining, the service
    switchover and a self-test that proves Kerberos issues a ticket
  * adc-sysvol-sync, a systemd timer implementing the SYSVOL workaround
  * a MAAS curtin preseed, cloud-init examples, and the release pipeline

Two findings shaped the design.

Debian builds Samba against its bundled Heimdal rather than system MIT Kerberos
— samba-ad-dc does not depend on krb5-kdc — so the AD DC role is in Samba's
supported configuration, not the experimental MIT one. The build asserts this
and fails if it ever changes.

Samba implements neither DFS-R nor FRS, so SYSVOL — where Group Policy lives —
does not replicate between DCs. Left alone, a policy created on one DC never
reaches the others and clients behave differently depending on which DC answered
them, with nothing reporting an error. adc-sysvol-sync applies the Samba wiki's
rsync workaround: sync idmap.ldb once so SID-to-uid mappings agree, rsync the
tree, then samba-tool ntacl sysvolreset because rsync carries POSIX bits while
the Windows ACLs live in AD. Without an SSH key to the source DC it exits with
an explanation rather than letting Group Policy diverge quietly.

Also carried over from maas-proxmox, where they were verified on real hardware:
the curtin-hooks that skip the kernel install and pin interface names by MAC,
Type=simple on the first-boot unit to avoid the systemd ordering cycle, and
shipping networking.service disabled so MAAS owns the network on first boot.
Specific to this image, the Debian cloud kernel is replaced with the generic one
— a bare-metal node booted with the cloud kernel can come up with no disk.

Nothing here has been built or deployed. The README says so at the top and in a
Verified status section that separates what was checked from what was not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-05 14:44:37 +02:00
commit cf07702535
25 changed files with 3158 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
# Copyright (C) 2026 Ilker Manap
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# /etc/adc-maas/adc-maas.conf
#
# Defaults for adc-maas-init. DO NOT EDIT THIS FILE. Put per-node settings in
# /etc/adc-maas/conf.d/*.conf, which cloud-init writes from the user-data MAAS
# passes at deploy time; those values override everything here.
#
# A note on terminology, because it trips people up. "Primary" and "backup"
# domain controllers are Windows NT 4 concepts. Active Directory, from Windows
# 2000 onwards, has no such split: every DC is a writable, equal peer and they
# replicate to each other. What does live on exactly one DC at a time are the
# five FSMO roles, one of which is confusingly named "PDC Emulator".
#
# So the real distinction is not primary versus backup, it is:
#
# AD_MODE=provision the FIRST DC, which creates the domain
# AD_MODE=join every DC after that, which joins the existing domain
#
# All of them then serve logons equally. Losing the first one costs you the FSMO
# roles, which you seize onto another DC — it does not cost you the domain.
# ---------------------------------------------------------------- general
AD_ENABLED=true
# none | provision | join
AD_MODE=none
# ---------------------------------------------------------------- identity
# The Kerberos realm: your DNS domain in UPPERCASE. Use a domain you control and
# that is not your public web domain — EXAMPLE.LAN, AD.EXAMPLE.COM, and so on.
# Never use a bare ".local", which collides with mDNS.
AD_REALM=
# The NetBIOS name: the short, legacy form. Uppercase, at most 15 characters,
# no dots. Conventionally the first label of the realm.
AD_DOMAIN=
# For AD_MODE=provision this becomes the domain Administrator password.
# For AD_MODE=join these are the credentials used to join.
#
# Active Directory enforces password complexity by default: at least 7
# characters and three of upper case, lower case, digit, symbol. A weak password
# makes provisioning fail with an error that does not say so clearly.
AD_ADMIN_PASSWORD=
AD_ADMIN_PASSWORD_FILE=
AD_JOIN_USER=Administrator
# An existing DC to join, by IP or FQDN. Empty means "find one via DNS", which
# only works if this host's resolver already points at the domain.
AD_JOIN_PEER=
# ---------------------------------------------------------------- DNS
# SAMBA_INTERNAL is the Samba-provided DNS server. It is the recommended default
# and needs no separate configuration. BIND9_DLZ hands DNS to BIND with an AD
# backend, which you only want if you need BIND features such as complex views
# or DNSSEC.
AD_DNS_BACKEND=SAMBA_INTERNAL
# Where the DC sends queries it is not authoritative for. Without this the DC
# resolves your domain but nothing else.
AD_DNS_FORWARDER=
# ---------------------------------------------------------------- domain shape
# 2008_R2 is the safe default and interoperates with everything current.
# Raise it only when every DC in the domain supports the higher level.
AD_FUNCTION_LEVEL=2008_R2
AD_SITE=Default-First-Site-Name
# Store POSIX uid/gid attributes in AD. Keep this on if Linux machines will also
# authenticate against the domain; it makes uids consistent across them.
AD_USE_RFC2307=true
# ---------------------------------------------------------------- networking
# Empty means the interface holding the default route.
AD_INTERFACE=
# Subnet allowed to use this DC as an NTP source, e.g. 192.0.2.0/24.
# Domain members need working time: Kerberos rejects a skew over five minutes,
# and the usual symptom is logins failing for no visible reason.
AD_NTP_ALLOW=
# ---------------------------------------------------------------- SYSVOL
# SYSVOL is the share holding Group Policy objects and logon scripts. Windows
# replicates it between DCs with DFS-R. Samba implements neither DFS-R nor its
# predecessor FRS, so without help a policy created on one DC never reaches the
# others and clients behave differently depending on which DC answered them.
#
# The workaround, straight from the Samba wiki, is to pull SYSVOL over rsync
# from the DC holding the PDC Emulator role and then reapply the ACLs from AD.
#
# auto replicate on nodes that joined, not on the one that provisioned
# on replicate here
# off do not replicate; you are handling it another way
#
# This needs a root SSH key on this host that is authorised on the source DC.
# Without one the sync exits with an explanation instead of failing quietly.
AD_SYSVOL_SYNC=auto
AD_SYSVOL_SOURCE=
AD_SYSVOL_INTERVAL=5min
# ---------------------------------------------------------------- misc
AD_WAIT=900
AD_RETRIES=5
# Scrub AD_ADMIN_PASSWORD from conf.d once the domain is up.
AD_WIPE_SECRETS=true

View File