[POSTFIX] first progress
This commit is contained in:
11
.env.example
11
.env.example
@@ -1,9 +1,12 @@
|
|||||||
REALM=EXAMPLE.COM
|
REALM=EXAMPLE.COM
|
||||||
WORKGROUP=EXAMPLE
|
WORKGROUP=EXAMPLE
|
||||||
DOMAIN=example.com
|
DOMAIN=example.com
|
||||||
JOIN_USER=administrator
|
JOIN_USER=FileShare_ServiceAccount
|
||||||
JOIN_PASSWORD=ChangeMe
|
JOIN_PASSWORD=ReplaceWithLongRandomPassword
|
||||||
PUBLIC_GROUP=Domain Users
|
DOMAIN_USERS_SID=S-1-5-21-1111111111-2222222222-3333333333-513
|
||||||
# SAMBA_HOSTNAME=ad-samba-file-server
|
DOMAIN_ADMINS_SID=S-1-5-21-1111111111-2222222222-3333333333-512
|
||||||
|
PUBLIC_GROUP_SID=S-1-5-21-1111111111-2222222222-3333333333-513
|
||||||
|
# SAMBA_HOSTNAME=adsambafsrv
|
||||||
|
# NETBIOS_NAME=ADSAMBAFSRV
|
||||||
# LDAP_URI=ldaps://example.com
|
# LDAP_URI=ldaps://example.com
|
||||||
# LDAP_BASE_DN=DC=example,DC=com
|
# LDAP_BASE_DN=DC=example,DC=com
|
||||||
|
|||||||
33
README.md
33
README.md
@@ -14,6 +14,8 @@ This repository provides a production-oriented Samba file server container that
|
|||||||
- `/data/groups/<objectGUID>`
|
- `/data/groups/<objectGUID>`
|
||||||
- Samba machine trust/key material is persisted in `/var/lib/samba` to survive container recreation.
|
- Samba machine trust/key material is persisted in `/var/lib/samba` to survive container recreation.
|
||||||
- Container hostname is fixed (`SAMBA_HOSTNAME`) to keep AD computer identity stable.
|
- Container hostname is fixed (`SAMBA_HOSTNAME`) to keep AD computer identity stable.
|
||||||
|
- NetBIOS name defaults to `ADSAMBAFSRV` and is clamped to 15 characters (`NETBIOS_NAME` override supported).
|
||||||
|
- Setup prompts for well-known authorization groups by SID (`DOMAIN_USERS_SID`, `DOMAIN_ADMINS_SID`) to avoid localized group names.
|
||||||
- Reconciliation is executed:
|
- Reconciliation is executed:
|
||||||
- once on startup
|
- once on startup
|
||||||
- every 5 minutes via cron
|
- every 5 minutes via cron
|
||||||
@@ -48,7 +50,8 @@ CREATE TABLE shares (
|
|||||||
## AD Requirements
|
## AD Requirements
|
||||||
|
|
||||||
- Existing AD DS domain reachable from the Docker host.
|
- Existing AD DS domain reachable from the Docker host.
|
||||||
- A service account with rights to join computers to the domain (`net ads join`).
|
- Initial admin credentials with rights to create/reset `FileShare_ServiceAccount` during `./setup`.
|
||||||
|
- `FileShare_ServiceAccount` must be allowed to join computers to the domain (`net ads join`) in your AD policy.
|
||||||
- Dynamic group discovery primarily uses machine-account LDAP (`net ads search -P`); join credentials are only used as a fallback LDAP bind path.
|
- Dynamic group discovery primarily uses machine-account LDAP (`net ads search -P`); join credentials are only used as a fallback LDAP bind path.
|
||||||
- Group naming convention for dynamic shares:
|
- Group naming convention for dynamic shares:
|
||||||
- `FileShare_<ShareName>`
|
- `FileShare_<ShareName>`
|
||||||
@@ -91,16 +94,27 @@ Kerberos requires close time alignment.
|
|||||||
- `REALM`
|
- `REALM`
|
||||||
- `WORKGROUP`
|
- `WORKGROUP`
|
||||||
- `DOMAIN`
|
- `DOMAIN`
|
||||||
- `JOIN_USER`
|
- initial admin credentials (used once for provisioning)
|
||||||
- `JOIN_PASSWORD`
|
- `DOMAIN_USERS_SID`
|
||||||
|
- `DOMAIN_ADMINS_SID`
|
||||||
|
- optional `PUBLIC_GROUP_SID` (defaults to `DOMAIN_USERS_SID`)
|
||||||
|
|
||||||
3. The setup script writes `.env` and starts the service with:
|
Optional:
|
||||||
|
- `SAMBA_HOSTNAME` (defaults to `adsambafsrv`)
|
||||||
|
- `NETBIOS_NAME` (defaults to `ADSAMBAFSRV`, max 15 chars)
|
||||||
|
|
||||||
|
3. Setup behavior:
|
||||||
|
- creates or updates AD account `FileShare_ServiceAccount`
|
||||||
|
- always sets a long random password
|
||||||
|
- writes only service-account credentials to `.env` (initial admin credentials are not stored)
|
||||||
|
|
||||||
|
4. The setup script then starts the service with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
4. After startup:
|
5. After startup:
|
||||||
- container joins AD (idempotent)
|
- container joins AD (idempotent)
|
||||||
- startup reconciliation runs
|
- startup reconciliation runs
|
||||||
- cron runs reconciliation every 5 minutes
|
- cron runs reconciliation every 5 minutes
|
||||||
@@ -123,7 +137,7 @@ Kerberos requires close time alignment.
|
|||||||
|
|
||||||
- Share: `\\server\Public`
|
- Share: `\\server\Public`
|
||||||
- Path: `/data/public`
|
- Path: `/data/public`
|
||||||
- Read/write for authenticated users in configurable `PUBLIC_GROUP` (default `Domain Users`).
|
- Read/write for authenticated users in configurable `PUBLIC_GROUP_SID` (default: `DOMAIN_USERS_SID`, resolved through winbind).
|
||||||
- No guest access.
|
- No guest access.
|
||||||
|
|
||||||
### Dynamic Group Shares
|
### Dynamic Group Shares
|
||||||
@@ -147,7 +161,7 @@ docker compose exec samba testparm -s
|
|||||||
|
|
||||||
### Domain join fails
|
### Domain join fails
|
||||||
|
|
||||||
- Verify credentials in `.env`.
|
- Verify service account credentials in `.env`.
|
||||||
- Verify DNS resolution from container:
|
- Verify DNS resolution from container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -155,6 +169,11 @@ docker compose exec samba testparm -s
|
|||||||
```
|
```
|
||||||
|
|
||||||
- Verify time sync on host and AD DCs.
|
- Verify time sync on host and AD DCs.
|
||||||
|
- Verify NetBIOS name length is <= 15:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec samba testparm -s | grep -i 'netbios name'
|
||||||
|
```
|
||||||
|
|
||||||
### Winbind user/group resolution fails
|
### Winbind user/group resolution fails
|
||||||
|
|
||||||
|
|||||||
70
app/init.sh
70
app/init.sh
@@ -18,6 +18,55 @@ append_winbind_to_nss() {
|
|||||||
sed -ri '/^group:/ { /winbind/! s/$/ winbind/ }' /etc/nsswitch.conf
|
sed -ri '/^group:/ { /winbind/! s/$/ winbind/ }' /etc/nsswitch.conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
derive_netbios_name() {
|
||||||
|
local raw_name="${NETBIOS_NAME:-ADSAMBAFSRV}"
|
||||||
|
local upper_name="${raw_name^^}"
|
||||||
|
local cleaned_name
|
||||||
|
cleaned_name="$(printf '%s' "$upper_name" | tr -cd 'A-Z0-9')"
|
||||||
|
|
||||||
|
if [[ -z "$cleaned_name" ]]; then
|
||||||
|
cleaned_name="SAMBAFS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#cleaned_name} -gt 15 ]]; then
|
||||||
|
log "NETBIOS_NAME derived from '${raw_name}' exceeds 15 chars, truncating."
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NETBIOS_NAME="${cleaned_name:0:15}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_sid_to_group() {
|
||||||
|
local sid="$1"
|
||||||
|
local group_name=""
|
||||||
|
local sid_output=""
|
||||||
|
|
||||||
|
if sid_output="$(wbinfo --sid-to-fullname "$sid" 2>/dev/null)"; then
|
||||||
|
group_name="${sid_output%%$'\t'*}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$group_name" ]] && sid_output="$(wbinfo -s "$sid" 2>/dev/null)"; then
|
||||||
|
group_name="$(printf '%s' "$sid_output" | sed -E 's/[[:space:]]+[0-9]+$//')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$group_name" ]]; then
|
||||||
|
printf '[init] ERROR: unable to resolve SID %s via winbind\n' "$sid" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "$group_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_share_groups_from_sids() {
|
||||||
|
export DOMAIN_USERS_GROUP
|
||||||
|
DOMAIN_USERS_GROUP="$(resolve_sid_to_group "$DOMAIN_USERS_SID")"
|
||||||
|
|
||||||
|
export DOMAIN_ADMINS_GROUP
|
||||||
|
DOMAIN_ADMINS_GROUP="$(resolve_sid_to_group "$DOMAIN_ADMINS_SID")"
|
||||||
|
|
||||||
|
export PUBLIC_GROUP
|
||||||
|
PUBLIC_GROUP="$(resolve_sid_to_group "$PUBLIC_GROUP_SID")"
|
||||||
|
}
|
||||||
|
|
||||||
render_krb5_conf() {
|
render_krb5_conf() {
|
||||||
cat > /etc/krb5.conf <<EOF
|
cat > /etc/krb5.conf <<EOF
|
||||||
[libdefaults]
|
[libdefaults]
|
||||||
@@ -50,13 +99,19 @@ write_runtime_env_file() {
|
|||||||
printf 'export REALM=%q\n' "$REALM"
|
printf 'export REALM=%q\n' "$REALM"
|
||||||
printf 'export WORKGROUP=%q\n' "$WORKGROUP"
|
printf 'export WORKGROUP=%q\n' "$WORKGROUP"
|
||||||
printf 'export DOMAIN=%q\n' "$DOMAIN"
|
printf 'export DOMAIN=%q\n' "$DOMAIN"
|
||||||
|
printf 'export NETBIOS_NAME=%q\n' "$NETBIOS_NAME"
|
||||||
|
printf 'export DOMAIN_USERS_SID=%q\n' "$DOMAIN_USERS_SID"
|
||||||
|
printf 'export DOMAIN_ADMINS_SID=%q\n' "$DOMAIN_ADMINS_SID"
|
||||||
|
printf 'export PUBLIC_GROUP_SID=%q\n' "$PUBLIC_GROUP_SID"
|
||||||
|
printf 'export DOMAIN_USERS_GROUP=%q\n' "$DOMAIN_USERS_GROUP"
|
||||||
|
printf 'export DOMAIN_ADMINS_GROUP=%q\n' "$DOMAIN_ADMINS_GROUP"
|
||||||
|
printf 'export PUBLIC_GROUP=%q\n' "$PUBLIC_GROUP"
|
||||||
if [[ -n "${JOIN_USER:-}" ]]; then
|
if [[ -n "${JOIN_USER:-}" ]]; then
|
||||||
printf 'export JOIN_USER=%q\n' "$JOIN_USER"
|
printf 'export JOIN_USER=%q\n' "$JOIN_USER"
|
||||||
fi
|
fi
|
||||||
if [[ -n "${JOIN_PASSWORD:-}" ]]; then
|
if [[ -n "${JOIN_PASSWORD:-}" ]]; then
|
||||||
printf 'export JOIN_PASSWORD=%q\n' "$JOIN_PASSWORD"
|
printf 'export JOIN_PASSWORD=%q\n' "$JOIN_PASSWORD"
|
||||||
fi
|
fi
|
||||||
printf 'export PUBLIC_GROUP=%q\n' "$PUBLIC_GROUP"
|
|
||||||
if [[ -n "${LDAP_URI:-}" ]]; then
|
if [[ -n "${LDAP_URI:-}" ]]; then
|
||||||
printf 'export LDAP_URI=%q\n' "$LDAP_URI"
|
printf 'export LDAP_URI=%q\n' "$LDAP_URI"
|
||||||
fi
|
fi
|
||||||
@@ -109,9 +164,14 @@ EOF
|
|||||||
require_env REALM
|
require_env REALM
|
||||||
require_env WORKGROUP
|
require_env WORKGROUP
|
||||||
require_env DOMAIN
|
require_env DOMAIN
|
||||||
|
require_env DOMAIN_USERS_SID
|
||||||
|
require_env DOMAIN_ADMINS_SID
|
||||||
|
|
||||||
export REALM WORKGROUP DOMAIN
|
export REALM WORKGROUP DOMAIN
|
||||||
export PUBLIC_GROUP="${PUBLIC_GROUP:-Domain Users}"
|
export PUBLIC_GROUP_SID="${PUBLIC_GROUP_SID:-${DOMAIN_USERS_SID}}"
|
||||||
|
export DOMAIN_USERS_GROUP="${DOMAIN_USERS_SID}"
|
||||||
|
export DOMAIN_ADMINS_GROUP="${DOMAIN_ADMINS_SID}"
|
||||||
|
export PUBLIC_GROUP="${PUBLIC_GROUP_SID}"
|
||||||
if [[ -n "${JOIN_USER:-}" ]]; then
|
if [[ -n "${JOIN_USER:-}" ]]; then
|
||||||
export JOIN_USER
|
export JOIN_USER
|
||||||
fi
|
fi
|
||||||
@@ -123,7 +183,7 @@ mkdir -p /data/private /data/public /data/groups /state /etc/samba/generated /va
|
|||||||
touch /etc/samba/generated/shares.conf /var/log/reconcile.log
|
touch /etc/samba/generated/shares.conf /var/log/reconcile.log
|
||||||
|
|
||||||
append_winbind_to_nss
|
append_winbind_to_nss
|
||||||
write_runtime_env_file
|
derive_netbios_name
|
||||||
render_krb5_conf
|
render_krb5_conf
|
||||||
render_smb_conf
|
render_smb_conf
|
||||||
join_domain_if_needed
|
join_domain_if_needed
|
||||||
@@ -133,6 +193,10 @@ winbindd -F --no-process-group &
|
|||||||
|
|
||||||
wait_for_winbind
|
wait_for_winbind
|
||||||
|
|
||||||
|
resolve_share_groups_from_sids
|
||||||
|
render_smb_conf
|
||||||
|
write_runtime_env_file
|
||||||
|
|
||||||
log 'Running startup reconciliation'
|
log 'Running startup reconciliation'
|
||||||
python3 /app/reconcile_shares.py
|
python3 /app/reconcile_shares.py
|
||||||
|
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ def render_dynamic_shares(conn: sqlite3.Connection) -> None:
|
|||||||
"create mask = 0660",
|
"create mask = 0660",
|
||||||
"directory mask = 2770",
|
"directory mask = 2770",
|
||||||
"inherit permissions = yes",
|
"inherit permissions = yes",
|
||||||
"access based share enumeration = yes",
|
"access based share enum = yes",
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -433,7 +433,9 @@ def list_domain_users() -> List[str]:
|
|||||||
def sync_public_directory() -> None:
|
def sync_public_directory() -> None:
|
||||||
workgroup = os.environ["WORKGROUP"]
|
workgroup = os.environ["WORKGROUP"]
|
||||||
public_group = os.getenv("PUBLIC_GROUP", "Domain Users")
|
public_group = os.getenv("PUBLIC_GROUP", "Domain Users")
|
||||||
qualified_group = f"{workgroup}\\{public_group}"
|
qualified_group = (
|
||||||
|
public_group if "\\" in public_group else f"{workgroup}\\{public_group}"
|
||||||
|
)
|
||||||
|
|
||||||
os.makedirs(PUBLIC_ROOT, exist_ok=True)
|
os.makedirs(PUBLIC_ROOT, exist_ok=True)
|
||||||
gid = resolve_group_gid(qualified_group)
|
gid = resolve_group_gid(qualified_group)
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
container_name: ad-samba-file-server
|
container_name: ad-samba-file-server
|
||||||
hostname: ${SAMBA_HOSTNAME:-ad-samba-file-server}
|
hostname: ${SAMBA_HOSTNAME:-adsambafsrv}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
environment:
|
||||||
|
NETBIOS_NAME: ${NETBIOS_NAME:-ADSAMBAFSRV}
|
||||||
ports:
|
ports:
|
||||||
- "445:445"
|
- "445:445"
|
||||||
- "139:139"
|
- "139:139"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
kerberos method = secrets and keytab
|
kerberos method = secrets and keytab
|
||||||
realm = ${REALM}
|
realm = ${REALM}
|
||||||
workgroup = ${WORKGROUP}
|
workgroup = ${WORKGROUP}
|
||||||
|
netbios name = ${NETBIOS_NAME}
|
||||||
|
|
||||||
idmap config * : backend = tdb
|
idmap config * : backend = tdb
|
||||||
idmap config * : range = 3000-7999
|
idmap config * : range = 3000-7999
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
server min protocol = SMB2
|
server min protocol = SMB2
|
||||||
client min protocol = SMB2
|
client min protocol = SMB2
|
||||||
|
|
||||||
access based share enumeration = yes
|
access based share enum = yes
|
||||||
|
|
||||||
dedicated keytab file = /var/lib/samba/private/krb5.keytab
|
dedicated keytab file = /var/lib/samba/private/krb5.keytab
|
||||||
kerberos encryption types = all
|
kerberos encryption types = all
|
||||||
@@ -41,10 +42,10 @@
|
|||||||
read only = no
|
read only = no
|
||||||
browseable = yes
|
browseable = yes
|
||||||
guest ok = no
|
guest ok = no
|
||||||
valid users = @"${WORKGROUP}\\Domain Users"
|
valid users = @"${DOMAIN_USERS_GROUP}"
|
||||||
admin users = @"${WORKGROUP}\\Domain Admins"
|
admin users = @"${DOMAIN_ADMINS_GROUP}"
|
||||||
hide unreadable = yes
|
hide unreadable = yes
|
||||||
access based share enumeration = yes
|
access based share enum = yes
|
||||||
ea support = yes
|
ea support = yes
|
||||||
|
|
||||||
[Public]
|
[Public]
|
||||||
@@ -52,9 +53,9 @@
|
|||||||
read only = no
|
read only = no
|
||||||
browseable = yes
|
browseable = yes
|
||||||
guest ok = no
|
guest ok = no
|
||||||
valid users = @"${WORKGROUP}\\${PUBLIC_GROUP}"
|
valid users = @"${PUBLIC_GROUP}"
|
||||||
force group = "${WORKGROUP}\\${PUBLIC_GROUP}"
|
force group = "${PUBLIC_GROUP}"
|
||||||
create mask = 0660
|
create mask = 0660
|
||||||
directory mask = 2770
|
directory mask = 2770
|
||||||
inherit permissions = yes
|
inherit permissions = yes
|
||||||
access based share enumeration = yes
|
access based share enum = yes
|
||||||
|
|||||||
119
setup
119
setup
@@ -2,6 +2,26 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ENV_FILE=".env"
|
ENV_FILE=".env"
|
||||||
|
SERVICE_ACCOUNT_NAME="FileShare_ServiceAccount"
|
||||||
|
|
||||||
|
BOOTSTRAP_ENV_FILE=""
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "$BOOTSTRAP_ENV_FILE" && -f "$BOOTSTRAP_ENV_FILE" ]]; then
|
||||||
|
rm -f "$BOOTSTRAP_ENV_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
sanitize_netbios_name() {
|
||||||
|
local raw_name="$1"
|
||||||
|
local upper_name="${raw_name^^}"
|
||||||
|
local cleaned_name
|
||||||
|
cleaned_name="$(printf '%s' "$upper_name" | tr -cd 'A-Z0-9')"
|
||||||
|
if [[ -z "$cleaned_name" ]]; then
|
||||||
|
cleaned_name="ADSAMBAFSRV"
|
||||||
|
fi
|
||||||
|
printf '%s' "${cleaned_name:0:15}"
|
||||||
|
}
|
||||||
|
|
||||||
prompt_value() {
|
prompt_value() {
|
||||||
local var_name="$1"
|
local var_name="$1"
|
||||||
@@ -25,23 +45,106 @@ write_env_file() {
|
|||||||
local realm=""
|
local realm=""
|
||||||
local workgroup=""
|
local workgroup=""
|
||||||
local domain=""
|
local domain=""
|
||||||
local join_user=""
|
local admin_user=""
|
||||||
local join_password=""
|
local admin_password=""
|
||||||
|
local domain_users_sid=""
|
||||||
|
local domain_admins_sid=""
|
||||||
|
local public_group_sid=""
|
||||||
|
local samba_hostname="adsambafsrv"
|
||||||
|
local netbios_name="ADSAMBAFSRV"
|
||||||
|
local service_password=""
|
||||||
|
local public_group_prompt=""
|
||||||
|
local samba_hostname_input=""
|
||||||
|
local netbios_name_input=""
|
||||||
|
local sanitized_netbios_name=""
|
||||||
|
|
||||||
prompt_value realm "REALM (e.g. EXAMPLE.COM)"
|
prompt_value realm "REALM (e.g. EXAMPLE.COM)"
|
||||||
prompt_value workgroup "WORKGROUP (NetBIOS, e.g. EXAMPLE)"
|
prompt_value workgroup "WORKGROUP (NetBIOS, e.g. EXAMPLE)"
|
||||||
prompt_value domain "DOMAIN (AD DNS name or reachable DC FQDN)"
|
prompt_value domain "DOMAIN (AD DNS name or reachable DC FQDN)"
|
||||||
prompt_value join_user "JOIN_USER (AD account with join rights)"
|
prompt_value admin_user "Initial admin user (for provisioning service account)"
|
||||||
prompt_value join_password "JOIN_PASSWORD" true
|
prompt_value admin_password "Initial admin password" true
|
||||||
|
prompt_value domain_users_sid "DOMAIN_USERS_SID (e.g. ...-513)"
|
||||||
|
prompt_value domain_admins_sid "DOMAIN_ADMINS_SID (e.g. ...-512)"
|
||||||
|
|
||||||
|
public_group_prompt="PUBLIC_GROUP_SID (press Enter to reuse DOMAIN_USERS_SID)"
|
||||||
|
read -r -p "${public_group_prompt}: " public_group_sid
|
||||||
|
if [[ -z "$public_group_sid" ]]; then
|
||||||
|
public_group_sid="$domain_users_sid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -r -p "SAMBA_HOSTNAME [adsambafsrv]: " samba_hostname_input
|
||||||
|
if [[ -n "${samba_hostname_input:-}" ]]; then
|
||||||
|
samba_hostname="$samba_hostname_input"
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -r -p "NETBIOS_NAME [ADSAMBAFSRV]: " netbios_name_input
|
||||||
|
if [[ -n "${netbios_name_input:-}" ]]; then
|
||||||
|
netbios_name="$netbios_name_input"
|
||||||
|
fi
|
||||||
|
sanitized_netbios_name="$(sanitize_netbios_name "$netbios_name")"
|
||||||
|
if [[ "$sanitized_netbios_name" != "$netbios_name" ]]; then
|
||||||
|
printf "Using sanitized NETBIOS_NAME: %s\n" "$sanitized_netbios_name"
|
||||||
|
fi
|
||||||
|
netbios_name="$sanitized_netbios_name"
|
||||||
|
|
||||||
|
service_password="$(tr -dc 'A-Za-z0-9@#%+=:_-' </dev/urandom | head -c 48)"
|
||||||
|
|
||||||
|
BOOTSTRAP_ENV_FILE="$(mktemp)"
|
||||||
|
chmod 600 "$BOOTSTRAP_ENV_FILE"
|
||||||
|
|
||||||
|
cat > "$BOOTSTRAP_ENV_FILE" <<EOF
|
||||||
|
REALM=${realm}
|
||||||
|
WORKGROUP=${workgroup}
|
||||||
|
DOMAIN=${domain}
|
||||||
|
JOIN_USER=${admin_user}
|
||||||
|
JOIN_PASSWORD=${admin_password}
|
||||||
|
SERVICE_ACCOUNT_NAME=${SERVICE_ACCOUNT_NAME}
|
||||||
|
SERVICE_ACCOUNT_PASSWORD=${service_password}
|
||||||
|
DOMAIN_USERS_SID=${domain_users_sid}
|
||||||
|
DOMAIN_ADMINS_SID=${domain_admins_sid}
|
||||||
|
PUBLIC_GROUP_SID=${public_group_sid}
|
||||||
|
SAMBA_HOSTNAME=${samba_hostname}
|
||||||
|
NETBIOS_NAME=${netbios_name}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "Building image...\n"
|
||||||
|
docker compose build samba
|
||||||
|
|
||||||
|
printf "Provisioning service account %s...\n" "$SERVICE_ACCOUNT_NAME"
|
||||||
|
docker compose --env-file "$BOOTSTRAP_ENV_FILE" run --rm --entrypoint /bin/bash samba -lc '
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cat > /tmp/bootstrap-smb.conf <<EOF
|
||||||
|
[global]
|
||||||
|
security = ADS
|
||||||
|
kerberos method = secrets and keytab
|
||||||
|
realm = ${REALM}
|
||||||
|
workgroup = ${WORKGROUP}
|
||||||
|
netbios name = ${NETBIOS_NAME}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run_net() {
|
||||||
|
printf "%s\n" "$JOIN_PASSWORD" | net -s /tmp/bootstrap-smb.conf -U "$JOIN_USER" -S "$DOMAIN" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
if run_net ads search "(&(objectClass=user)(sAMAccountName=${SERVICE_ACCOUNT_NAME}))" sAMAccountName | grep -q "^sAMAccountName: ${SERVICE_ACCOUNT_NAME}$"; then
|
||||||
|
run_net ads password "${SERVICE_ACCOUNT_NAME}" "${SERVICE_ACCOUNT_PASSWORD}"
|
||||||
|
else
|
||||||
|
run_net ads user add "${SERVICE_ACCOUNT_NAME}" "${SERVICE_ACCOUNT_PASSWORD}"
|
||||||
|
fi
|
||||||
|
'
|
||||||
|
|
||||||
cat > "$ENV_FILE" <<EOF
|
cat > "$ENV_FILE" <<EOF
|
||||||
REALM=${realm}
|
REALM=${realm}
|
||||||
WORKGROUP=${workgroup}
|
WORKGROUP=${workgroup}
|
||||||
DOMAIN=${domain}
|
DOMAIN=${domain}
|
||||||
JOIN_USER=${join_user}
|
JOIN_USER=${SERVICE_ACCOUNT_NAME}
|
||||||
JOIN_PASSWORD=${join_password}
|
JOIN_PASSWORD=${service_password}
|
||||||
PUBLIC_GROUP=Domain Users
|
DOMAIN_USERS_SID=${domain_users_sid}
|
||||||
# SAMBA_HOSTNAME=ad-samba-file-server
|
DOMAIN_ADMINS_SID=${domain_admins_sid}
|
||||||
|
PUBLIC_GROUP_SID=${public_group_sid}
|
||||||
|
SAMBA_HOSTNAME=${samba_hostname}
|
||||||
|
NETBIOS_NAME=${netbios_name}
|
||||||
# Optional overrides:
|
# Optional overrides:
|
||||||
# LDAP_URI=ldaps://${domain}
|
# LDAP_URI=ldaps://${domain}
|
||||||
# LDAP_BASE_DN=DC=example,DC=com
|
# LDAP_BASE_DN=DC=example,DC=com
|
||||||
|
|||||||
Reference in New Issue
Block a user