138 lines
4.4 KiB
Bash
138 lines
4.4 KiB
Bash
#!/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" <<EXT
|
||
|
|
basicConstraints=critical,CA:FALSE
|
||
|
|
keyUsage=critical,digitalSignature,keyEncipherment
|
||
|
|
extendedKeyUsage=serverAuth
|
||
|
|
subjectAltName=DNS:$FQDN,DNS:$HOST
|
||
|
|
subjectKeyIdentifier=hash
|
||
|
|
authorityKeyIdentifier=keyid,issuer
|
||
|
|
EXT
|
||
|
|
openssl x509 -req -sha256 -days 3650 -in "$tmp/server.csr" \
|
||
|
|
-CA "$TLS/ca.pem" -CAkey "$TLS/ca.key" -CAcreateserial -CAserial "$tmp/ca.srl" \
|
||
|
|
-extfile "$tmp/server.ext" -out "$TLS/cert.pem" 2>/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
|