Some checks failed
CI Pipeline / lint (push) Successful in 20s
CI Pipeline / build (push) Successful in 56s
CI Pipeline / test (push) Failing after 1m32s
CI Pipeline / security-scan (push) Successful in 1m21s
CI Pipeline / autotag (push) Has been skipped
CI Pipeline / push (push) Has been skipped
CI Pipeline / update-cd (push) Has been skipped
- Add syncprov module to init-config.sh - Create init-replication.sh for configuring N-way multi-master - Update entrypoint to handle replication configuration - Support LDAP_REPLICATION_ENABLED, LDAP_SERVER_ID, LDAP_REPLICATION_HOSTS - Replica servers can sync DIT from existing masters
160 lines
4.9 KiB
Bash
160 lines
4.9 KiB
Bash
#!/bin/sh
|
|
set -e
|
|
|
|
# Source utility functions
|
|
. /scripts/utils.sh
|
|
|
|
# LDAPI socket URL - must use URL-encoded path for Alpine
|
|
LDAPI_SOCKET="ldapi://%2Frun%2Fopenldap%2Fldapi"
|
|
export LDAPI_SOCKET
|
|
|
|
# Validate required environment variables
|
|
if [ -z "$LDAP_DOMAIN" ]; then
|
|
log_error "LDAP_DOMAIN is required"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$LDAP_ORGANISATION" ]; then
|
|
log_error "LDAP_ORGANISATION is required"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$LDAP_ADMIN_PASSWORD" ]; then
|
|
log_error "LDAP_ADMIN_PASSWORD is required"
|
|
exit 1
|
|
fi
|
|
|
|
# Generate base DN from domain if not provided
|
|
if [ -z "$LDAP_BASE_DN" ]; then
|
|
LDAP_BASE_DN=$(echo "$LDAP_DOMAIN" | sed 's/^/dc=/; s/\./,dc=/g')
|
|
fi
|
|
export LDAP_BASE_DN
|
|
|
|
# Extract DC component for base entry
|
|
LDAP_DC=$(echo "$LDAP_DOMAIN" | cut -d'.' -f1)
|
|
export LDAP_DC
|
|
|
|
# Set defaults for optional variables
|
|
export LDAP_CONFIG_PASSWORD="${LDAP_CONFIG_PASSWORD:-$(generate_password)}"
|
|
export LDAP_TLS_ENABLED="${LDAP_TLS_ENABLED:-true}"
|
|
export LDAP_TLS_CERT_FILE="${LDAP_TLS_CERT_FILE:-/certs/ldap.crt}"
|
|
export LDAP_TLS_KEY_FILE="${LDAP_TLS_KEY_FILE:-/certs/ldap.key}"
|
|
export LDAP_TLS_CA_FILE="${LDAP_TLS_CA_FILE:-/certs/ca.crt}"
|
|
export LDAP_TLS_VERIFY_CLIENT="${LDAP_TLS_VERIFY_CLIENT:-try}"
|
|
export LDAP_LOG_LEVEL="${LDAP_LOG_LEVEL:-256}"
|
|
export LDAP_READONLY="${LDAP_READONLY:-false}"
|
|
|
|
# Replication settings
|
|
export LDAP_REPLICATION_ENABLED="${LDAP_REPLICATION_ENABLED:-false}"
|
|
export LDAP_SERVER_ID="${LDAP_SERVER_ID:-1}"
|
|
export LDAP_REPLICATION_HOSTS="${LDAP_REPLICATION_HOSTS:-}"
|
|
export LDAP_BOOTSTRAP_PRIMARY="${LDAP_BOOTSTRAP_PRIMARY:-false}"
|
|
|
|
log_info "OpenLDAP Container Starting"
|
|
log_info "Domain: $LDAP_DOMAIN"
|
|
log_info "Base DN: $LDAP_BASE_DN"
|
|
log_info "Organisation: $LDAP_ORGANISATION"
|
|
|
|
# Check if already initialized
|
|
if [ ! -f /var/lib/openldap/openldap-data/data.mdb ]; then
|
|
log_info "First run - initializing OpenLDAP..."
|
|
|
|
# Initialize cn=config (always needed)
|
|
/scripts/init-config.sh
|
|
|
|
# Load schemas in order (always needed)
|
|
/scripts/init-schemas.sh
|
|
|
|
# Configure overlays (always needed)
|
|
/scripts/init-overlays.sh
|
|
|
|
# Determine if we should initialize DIT or replicate from peer
|
|
# If replication is enabled and we're not the bootstrap primary, skip DIT init
|
|
if [ "$LDAP_REPLICATION_ENABLED" = "true" ] && [ "$LDAP_BOOTSTRAP_PRIMARY" != "true" ]; then
|
|
log_info "Replication enabled - this server will sync DIT from peers"
|
|
log_info "Skipping local DIT initialization..."
|
|
else
|
|
# Create base DIT
|
|
/scripts/init-dit.sh
|
|
|
|
# Configure ACLs
|
|
/scripts/init-acls.sh
|
|
|
|
# Create service accounts if requested
|
|
if [ "$LDAP_CREATE_SERVICE_ACCOUNTS" = "true" ]; then
|
|
/scripts/init-services.sh
|
|
fi
|
|
|
|
# Process custom LDIF files if present
|
|
if [ -d /ldif/custom ] && [ "$(ls -A /ldif/custom 2>/dev/null)" ]; then
|
|
log_info "Processing custom LDIF files..."
|
|
for ldif in /ldif/custom/*.ldif; do
|
|
if [ -f "$ldif" ]; then
|
|
log_info "Loading: $ldif"
|
|
ldapadd -x -H "$LDAPI_SOCKET" -D "cn=admin,$LDAP_BASE_DN" -w "$LDAP_ADMIN_PASSWORD" -f "$ldif" || \
|
|
log_warn "Failed to load $ldif (may already exist)"
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
|
|
log_info "Initialization complete."
|
|
else
|
|
log_info "Database exists - starting normally."
|
|
fi
|
|
|
|
# Ensure proper ownership
|
|
chown -R ldap:ldap /var/lib/openldap
|
|
chown -R ldap:ldap /etc/openldap/slapd.d
|
|
chown -R ldap:ldap /run/openldap
|
|
|
|
# Build slapd arguments
|
|
SLAPD_URLS="ldap:/// $LDAPI_SOCKET"
|
|
if [ "$LDAP_TLS_ENABLED" = "true" ]; then
|
|
if [ -f "$LDAP_TLS_CERT_FILE" ] && [ -f "$LDAP_TLS_KEY_FILE" ]; then
|
|
SLAPD_URLS="ldap:/// ldaps:/// $LDAPI_SOCKET"
|
|
log_info "TLS enabled - listening on ldaps://"
|
|
else
|
|
log_warn "TLS enabled but certificates not found - skipping ldaps://"
|
|
fi
|
|
fi
|
|
|
|
log_info "Starting slapd with URLs: $SLAPD_URLS"
|
|
|
|
# If replication is enabled, start slapd in background first to configure replication
|
|
if [ "$LDAP_REPLICATION_ENABLED" = "true" ]; then
|
|
log_info "Starting slapd in background for replication configuration..."
|
|
|
|
/usr/sbin/slapd -h "$SLAPD_URLS" \
|
|
-F /etc/openldap/slapd.d \
|
|
-u ldap -g ldap &
|
|
|
|
SLAPD_PID=$!
|
|
|
|
# Wait for slapd to be ready
|
|
log_info "Waiting for slapd to be ready..."
|
|
sleep 2
|
|
for i in $(seq 1 30); do
|
|
if ldapsearch -x -H ldap://localhost -b "" -s base "objectClass=*" >/dev/null 2>&1; then
|
|
log_info "slapd is ready"
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# Configure replication
|
|
/scripts/init-replication.sh
|
|
|
|
# Stop background slapd gracefully
|
|
log_info "Restarting slapd in foreground mode..."
|
|
kill $SLAPD_PID 2>/dev/null || true
|
|
wait $SLAPD_PID 2>/dev/null || true
|
|
sleep 1
|
|
fi
|
|
|
|
# Start slapd in foreground (final)
|
|
exec /usr/sbin/slapd -h "$SLAPD_URLS" \
|
|
-F /etc/openldap/slapd.d \
|
|
-u ldap -g ldap \
|
|
-d "${LDAP_LOG_LEVEL}"
|