#!/usr/bin/env bash # Samba AD DC for CI. Provisions PSTEST.LOCAL on first start, makes the TLS certificates, # seeds the OU tree, groups and users once, refreshes /export, then runs samba in the foreground. # Never prints a password. Run as root (Samba needs it). tini is PID 1. set -euo pipefail REALM=PSTEST.LOCAL DOMAIN=PSTEST HOST=dc1 FQDN=dc1.pstest.local STATE=/var/lib/samba PRIVATE=$STATE/private TLS=$PRIVATE/tls CONF_DIR=$STATE/etc # smb.conf lives on the volume so it survives a recreated container CONF=$CONF_DIR/smb.conf EXPORT=/export ADMIN_SECRET=/run/secrets/samba_admin_password log() { echo "samba-dc: $*"; } read_secret() { # One line, CR stripped. Never echoed. local f=$1 if [ ! -s "$f" ]; then log "missing or empty secret file $f" >&2 exit 1 fi head -n 1 "$f" | tr -d '\r\n' } make_tls() { log "making the CI CA and the server certificate" mkdir -p "$TLS" local tmp tmp=$(mktemp -d) openssl req -x509 -new -nodes -newkey rsa:3072 -sha256 -days 3650 \ -keyout "$TLS/ca.key" -out "$TLS/ca.pem" -subj "/CN=PSTEST CI CA" \ -addext "basicConstraints=critical,CA:TRUE" \ -addext "keyUsage=critical,keyCertSign,cRLSign" \ -addext "subjectKeyIdentifier=hash" 2>/dev/null openssl req -new -nodes -newkey rsa:3072 -sha256 \ -keyout "$TLS/key.pem" -out "$tmp/server.csr" -subj "/CN=$FQDN" 2>/dev/null cat > "$tmp/server.ext" </dev/null rm -rf "$tmp" # Samba refuses a private key that others can read. chmod 0600 "$TLS/key.pem" "$TLS/ca.key" chmod 0644 "$TLS/ca.pem" "$TLS/cert.pem" openssl verify -CAfile "$TLS/ca.pem" "$TLS/cert.pem" >/dev/null } set_global() { # Add lines right after [global] in smb.conf. local line for line in "$@"; do sed -i "/^\[global\]/a $line" "$CONF" done } provision() { log "provisioning $REALM (first start)" local adminpass adminpass=$(read_secret "$ADMIN_SECRET") rm -f /etc/samba/smb.conf mkdir -p "$CONF_DIR" # The sysvol ACL step needs security.* xattrs, so the container runs with CAP_SYS_ADMIN # (compose.ci.yaml). Samba 4.17 has no --use-xattrs option. --dns-backend=NONE: the stack # resolves names itself. samba-tool domain provision \ --use-rfc2307 \ --realm="$REALM" \ --domain="$DOMAIN" \ --host-name="$HOST" \ --server-role=dc \ --dns-backend=NONE \ --adminpass="$adminpass" >/var/log/samba-provision.log 2>&1 || { log "provision failed; last lines of the log follow" >&2 tail -n 40 /var/log/samba-provision.log >&2 exit 1 } unset adminpass mv /etc/samba/smb.conf "$CONF" ln -sf "$CONF" /etc/samba/smb.conf make_tls # Simple binds only over TLS (LDAPS or STARTTLS), like PESCO's DCs. Plain LDAP simple binds fail. set_global \ "ldap server require strong auth = allow_sasl_over_tls" \ "tls keyfile = $TLS/key.pem" \ "tls certfile = $TLS/cert.pem" \ "tls cafile = $TLS/ca.pem" \ "tls enabled = yes" # Relaxed policy: CI passwords are random per run and never change. samba-tool domain passwordsettings set \ --complexity=off --min-pwd-age=0 --max-pwd-age=0 --history-length=0 >/dev/null cp "$PRIVATE/krb5.conf" /etc/krb5.conf 2>/dev/null || true log "provisioned" } if [ ! -f "$PRIVATE/sam.ldb" ]; then provision else log "already provisioned; skipping" ln -sf "$CONF" /etc/samba/smb.conf cp "$PRIVATE/krb5.conf" /etc/krb5.conf 2>/dev/null || true fi # Seed once, offline, before samba starts. samba-tool writes sam.ldb directly. if [ ! -f "$PRIVATE/.seeded" ]; then /usr/local/bin/seed.sh date -u +%Y-%m-%dT%H:%M:%SZ > "$PRIVATE/.seeded" else log "already seeded; skipping" fi # Refresh the export on every start: the CA, the users file and the seeded marker. mkdir -p "$EXPORT" chmod 0755 "$EXPORT" rm -f "$EXPORT/seeded" install -m 0444 "$TLS/ca.pem" "$EXPORT/ca.pem" install -m 0444 "$PRIVATE/users.json" "$EXPORT/users.json" cp "$PRIVATE/.seeded" "$EXPORT/seeded" chmod 0444 "$EXPORT/seeded" log "exported ca.pem and users.json to $EXPORT" log "starting samba" exec samba -i -F --no-process-group