168 lines
6.1 KiB
Bash
168 lines
6.1 KiB
Bash
#!/usr/bin/env bash
|
|||
|
|
# Seed the CI domain: the OU tree, the service account, the PS-* groups and the test users.
|
||
|
|
# Runs once from entrypoint.sh, before samba starts, against the local sam.ldb.
|
||
|
|
# Safe to rerun: "already exists" is ignored and every user gets a new random password.
|
||
|
|
# Never prints a password. Writes $PRIVATE/users.json (0600); the entrypoint exports it.
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
BASE="DC=pstest,DC=local"
|
||
|
|
PRIVATE=/var/lib/samba/private
|
||
|
|
SAM=$PRIVATE/sam.ldb
|
||
|
|
GROUPS_FILE=/usr/local/share/pstest/groups.txt
|
||
|
|
BIND_SECRET=/run/secrets/ldap_bind_password
|
||
|
|
PS_OU="OU=PacketStation,OU=Groups,OU=PESCO_FARMINGTON"
|
||
|
|
USERS_OU="OU=Users,OU=PESCO_FARMINGTON"
|
||
|
|
MISSING_GROUP="PS-14-Electrical-Lead" # left out on purpose: the reconcile report must flag it
|
||
|
|
EXTRA_GROUP="PS-Extra-Legacy" # added on purpose: the reconcile report must list it
|
||
|
|
NESTED_GROUP="Shop-Welders-Nested"
|
||
|
|
|
||
|
|
log() { echo "samba-dc seed: $*"; }
|
||
|
|
|
||
|
|
# Run a command. Ignore "already exists". On any other failure show its output and stop.
|
||
|
|
# Callers never pass a password in a way that ends up in this output.
|
||
|
|
try() {
|
||
|
|
local out
|
||
|
|
if out=$("$@" 2>&1); then
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
if printf '%s' "$out" | grep -qiE 'already exists|ENTRY_ALREADY_EXISTS|already a member'; then
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
log "failed: $1 $2 $3" >&2
|
||
|
|
printf '%s\n' "$out" | sed 's/^/ /' >&2
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
|
||
|
|
add_ou() {
|
||
|
|
local dn="$1,$BASE"
|
||
|
|
local ldif
|
||
|
|
ldif=$(mktemp)
|
||
|
|
printf 'dn: %s\nobjectClass: top\nobjectClass: organizationalUnit\n' "$dn" > "$ldif"
|
||
|
|
try ldbadd -H "$SAM" "$ldif"
|
||
|
|
rm -f "$ldif"
|
||
|
|
}
|
||
|
|
|
||
|
|
random_password() {
|
||
|
|
# 24 random base64 characters plus a fixed tail with upper, lower, digit and symbol.
|
||
|
|
printf '%s-Pa9' "$(openssl rand -base64 18 | tr -d '\n')"
|
||
|
|
}
|
||
|
|
|
||
|
|
set_password() {
|
||
|
|
# $1 sam, $2 password. Not logged. Visible only inside this container's process list.
|
||
|
|
try samba-tool user setpassword "$1" --newpassword="$2"
|
||
|
|
}
|
||
|
|
|
||
|
|
set_attrs() {
|
||
|
|
# $1 dn, $2 display name, $3 employeeID or empty.
|
||
|
|
local ldif
|
||
|
|
ldif=$(mktemp)
|
||
|
|
{
|
||
|
|
printf 'dn: %s\nchangetype: modify\n' "$1"
|
||
|
|
printf 'replace: displayName\ndisplayName: %s\n-\n' "$2"
|
||
|
|
if [ -n "$3" ]; then
|
||
|
|
printf 'replace: employeeID\nemployeeID: %s\n-\n' "$3"
|
||
|
|
fi
|
||
|
|
} > "$ldif"
|
||
|
|
try ldbmodify -H "$SAM" "$ldif"
|
||
|
|
rm -f "$ldif"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ---- OU tree, mirroring PESCO ----
|
||
|
|
log "OU tree"
|
||
|
|
add_ou "OU=PESCO_FARMINGTON"
|
||
|
|
add_ou "OU=Groups,OU=PESCO_FARMINGTON"
|
||
|
|
add_ou "$PS_OU"
|
||
|
|
add_ou "$USERS_OU"
|
||
|
|
add_ou "OU=Admin"
|
||
|
|
add_ou "OU=System_Accounts,OU=Admin"
|
||
|
|
|
||
|
|
# ---- Service account (password = the app's ldap_bind_password secret) ----
|
||
|
|
log "service account svc-packetstation"
|
||
|
|
if [ ! -s "$BIND_SECRET" ]; then
|
||
|
|
log "missing or empty secret file $BIND_SECRET" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
try samba-tool user create svc-packetstation --random-password --use-username-as-cn \
|
||
|
|
--userou="OU=System_Accounts,OU=Admin" --description="Packet Station service account (CI)"
|
||
|
|
set_password svc-packetstation "$(head -n 1 "$BIND_SECRET" | tr -d '\r\n')"
|
||
|
|
try samba-tool user setexpiry svc-packetstation --noexpiry
|
||
|
|
|
||
|
|
# ---- Groups ----
|
||
|
|
log "PacketStation groups"
|
||
|
|
count=0
|
||
|
|
while IFS= read -r name || [ -n "$name" ]; do
|
||
|
|
name=$(printf '%s' "$name" | tr -d '\r' | sed 's/[[:space:]]*$//')
|
||
|
|
[ -z "$name" ] && continue
|
||
|
|
[ "$name" = "$MISSING_GROUP" ] && continue
|
||
|
|
try samba-tool group add "$name" --groupou="$PS_OU" \
|
||
|
|
--group-scope=Global --group-type=Security --description="Packet Station: $name"
|
||
|
|
count=$((count + 1))
|
||
|
|
done < "$GROUPS_FILE"
|
||
|
|
try samba-tool group add "$EXTRA_GROUP" --groupou="$PS_OU" \
|
||
|
|
--group-scope=Global --group-type=Security --description="Packet Station: $EXTRA_GROUP"
|
||
|
|
try samba-tool group add "$NESTED_GROUP" --groupou="OU=Groups,OU=PESCO_FARMINGTON" \
|
||
|
|
--group-scope=Global --group-type=Security --description="Helper group for the nested membership test"
|
||
|
|
try samba-tool group addmembers PS-10-WeldAssembly-Worker "$NESTED_GROUP"
|
||
|
|
log "created $count mapped groups (without $MISSING_GROUP), plus $EXTRA_GROUP and $NESTED_GROUP"
|
||
|
|
|
||
|
|
# ---- Users: sam|given|surname|employeeID|groups (comma separated) ----
|
||
|
|
ROSTER='admin.ann|Ann|Admin|1001|PS-Admins
|
||
|
|
clerk.clara|Clara|Clerk|4001|PS-Clerical
|
||
|
|
clerk.leo|Leo|Lead|4002|PS-Clerical-Supervisor
|
||
|
|
wh.wade|Wade|Warehouse|6001|PS-Warehouse
|
||
|
|
qc.quinn|Quinn|QC|5001|PS-QC
|
||
|
|
pm.paula|Paula|PM|7001|PS-ProjectMgmt
|
||
|
|
weld.andy|Andy|Welder|3003|PS-03-WeldParts-Worker
|
||
|
|
lead.lou|Lou|Lead|3002|PS-03-WeldParts-Lead
|
||
|
|
sup.wes|Wes|Super|2003|PS-03-WeldParts-Supervisor
|
||
|
|
multi.mia|Mia|Multi|2006|PS-Clerical,PS-06-CodeBldg2-Supervisor
|
||
|
|
nested.ned|Ned|Nested|3010|Shop-Welders-Nested
|
||
|
|
both.bo|Bo|Both|3011|PS-03-WeldParts-Worker,PS-03-WeldParts-Supervisor
|
||
|
|
disabled.dan|Dan|Disabled|3004|PS-03-WeldParts-Worker
|
||
|
|
noemp.nora|Nora|NoEmp||PS-Warehouse
|
||
|
|
dup.dave|Dave|Dup|9001|PS-03-WeldParts-Worker
|
||
|
|
dup.dina|Dina|Dup|9001|PS-Warehouse
|
||
|
|
norole.nick|Nick|NoRole|8001|'
|
||
|
|
|
||
|
|
umask 077
|
||
|
|
rows=$(mktemp) # sam, password, emp, display; tab separated; 0600; removed below
|
||
|
|
log "users"
|
||
|
|
while IFS='|' read -r sam given surname emp groups; do
|
||
|
|
[ -z "$sam" ] && continue
|
||
|
|
display="$given $surname"
|
||
|
|
dn="CN=$sam,$USERS_OU,$BASE"
|
||
|
|
try samba-tool user create "$sam" --random-password --use-username-as-cn \
|
||
|
|
--userou="$USERS_OU" --given-name="$given" --surname="$surname" \
|
||
|
|
--mail-address="$sam@pstest.local"
|
||
|
|
pw=$(random_password)
|
||
|
|
set_password "$sam" "$pw"
|
||
|
|
set_attrs "$dn" "$display" "$emp"
|
||
|
|
if [ -n "$groups" ]; then
|
||
|
|
IFS=',' read -r -a list <<< "$groups"
|
||
|
|
for g in "${list[@]}"; do
|
||
|
|
try samba-tool group addmembers "$g" "$sam"
|
||
|
|
done
|
||
|
|
fi
|
||
|
|
printf '%s\t%s\t%s\t%s\n' "$sam" "$pw" "$emp" "$display" >> "$rows"
|
||
|
|
unset pw
|
||
|
|
log " $sam"
|
||
|
|
done <<< "$ROSTER"
|
||
|
|
|
||
|
|
try samba-tool user disable disabled.dan
|
||
|
|
|
||
|
|
# ---- users.json, the format in the phase 1 contract ----
|
||
|
|
python3 - "$rows" "$PRIVATE/users.json" <<'PY'
|
||
|
|
import json, sys
|
||
|
|
users = {}
|
||
|
|
with open(sys.argv[1], encoding="utf-8") as f:
|
||
|
|
for line in f:
|
||
|
|
sam, password, emp, display = line.rstrip("\n").split("\t")
|
||
|
|
users[sam] = {"password": password, "emp_no": emp or None, "display_name": display}
|
||
|
|
with open(sys.argv[2], "w", encoding="utf-8") as f:
|
||
|
|
json.dump({"domain": "pstest.local", "users": users}, f, indent=2, sort_keys=True)
|
||
|
|
f.write("\n")
|
||
|
|
PY
|
||
|
|
rm -f "$rows"
|
||
|
|
chmod 0600 "$PRIVATE/users.json"
|
||
|
|
log "done: $(grep -c '"password"' "$PRIVATE/users.json") users written to users.json"
|