213 lines
7.8 KiB
Bash
Executable File
213 lines
7.8 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Warn if the DOCKER_HOST socket does not exist
|
|
if [[ $DOCKER_HOST = unix://* ]]; then
|
|
socket_file=${DOCKER_HOST#unix://}
|
|
if ! [ -S $socket_file ]; then
|
|
cat >&2 <<-EOT
|
|
ERROR: you need to share your Docker host socket with a volume at $socket_file
|
|
Typically you should run your container with: \`-v /var/run/docker.sock:$socket_file:ro\`
|
|
See the jwilder/nginx-proxy documentation at http://git.io/vZaGJ
|
|
EOT
|
|
socketMissing=1
|
|
fi
|
|
fi
|
|
|
|
# Compute the DNS resolvers for use in the templates - if the IP contains ":", it's IPv6 and must be enclosed in []
|
|
export RESOLVERS=$(awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g')
|
|
if [ "x$RESOLVERS" = "x" ]; then
|
|
echo "Warning: unable to determine DNS resolvers for nginx" >&2
|
|
unset RESOLVERS
|
|
fi
|
|
|
|
# If the user has run the default command and the socket doesn't exist, fail
|
|
if [ "$socketMissing" = 1 -a "$1" = 'supervisord' -a "$2" = '-c' -a "$3" = '/etc/supervisord.conf' ]; then
|
|
exit 1
|
|
fi
|
|
|
|
# set up for NGINX HTTP basic vs. LDAP/LDAPS/LDAP+StartTLS auth
|
|
|
|
# a blank file just to use as an "include" placeholder for the nginx's LDAP config when LDAP is not used
|
|
NGINX_BLANK_CONF=/etc/nginx/nginx_blank.conf
|
|
|
|
# "include" file for auth_basic, prompt, and .htpasswd location
|
|
NGINX_BASIC_AUTH_CONF=/etc/nginx/nginx_auth_basic.conf
|
|
|
|
# "include" file for auth_ldap, prompt, and "auth_ldap_servers" name
|
|
NGINX_LDAP_AUTH_CONF=/etc/nginx/nginx_auth_ldap.conf
|
|
|
|
# volume-mounted user configuration containing "ldap_server ad_server" section with URL, binddn, etc.
|
|
NGINX_LDAP_USER_CONF=/etc/nginx/nginx_ldap.conf
|
|
|
|
# runtime "include" file for auth method (link to either NGINX_BASIC_AUTH_CONF or NGINX_LDAP_AUTH_CONF)
|
|
NGINX_RUNTIME_AUTH_CONF=/etc/nginx/nginx_auth_rt.conf
|
|
|
|
# runtime "include" file for ldap config (link to either NGINX_BLANK_CONF or (possibly modified) NGINX_LDAP_USER_CONF)
|
|
NGINX_RUNTIME_LDAP_CONF=/etc/nginx/nginx_ldap_rt.conf
|
|
|
|
# config file for stunnel if using stunnel to issue LDAP StartTLS function
|
|
STUNNEL_CONF=/etc/stunnel/stunnel.conf
|
|
|
|
CA_TRUST_HOST_DIR=/etc/nginx/ca-trust
|
|
CA_TRUST_RUN_DIR=/var/run/ca-trust
|
|
|
|
# copy trusted CA certs to runtime directory and c_rehash them to create symlinks
|
|
STUNNEL_CA_PATH_LINE=""
|
|
STUNNEL_VERIFY_LINE=""
|
|
STUNNEL_CHECK_HOST_LINE=""
|
|
STUNNEL_CHECK_IP_LINE=""
|
|
NGINX_LDAP_CA_PATH_LINE=""
|
|
NGINX_LDAP_CHECK_REMOTE_CERT_LINE=""
|
|
mkdir -p "$CA_TRUST_RUN_DIR"
|
|
# attempt to make sure trusted CA certs dir is readable by unprivileged nginx worker
|
|
chmod 755 "$CA_TRUST_RUN_DIR" || true
|
|
CA_FILES=$(shopt -s nullglob dotglob; echo "$CA_TRUST_HOST_DIR"/*)
|
|
if (( ${#CA_FILES} )) ; then
|
|
rm -f "$CA_TRUST_RUN_DIR"/*
|
|
pushd "$CA_TRUST_RUN_DIR" >/dev/null 2>&1
|
|
if cp "$CA_TRUST_HOST_DIR"/* ./ ; then
|
|
|
|
# attempt to make sure trusted CA certs are readable by unprivileged nginx worker
|
|
chmod 644 * || true
|
|
|
|
# create hash symlinks
|
|
c_rehash -compat .
|
|
|
|
# variables for stunnel config
|
|
STUNNEL_CA_PATH_LINE="CApath = $CA_TRUST_RUN_DIR"
|
|
[[ -n $NGINX_LDAP_TLS_STUNNEL_VERIFY_LEVEL ]] && STUNNEL_VERIFY_LINE="verify = $NGINX_LDAP_TLS_STUNNEL_VERIFY_LEVEL" || STUNNEL_VERIFY_LINE="verify = 2"
|
|
[[ -n $NGINX_LDAP_TLS_STUNNEL_CHECK_HOST ]] && STUNNEL_CHECK_HOST_LINE="checkHost = $NGINX_LDAP_TLS_STUNNEL_CHECK_HOST"
|
|
[[ -n $NGINX_LDAP_TLS_STUNNEL_CHECK_IP ]] && STUNNEL_CHECK_IP_LINE="checkIP = $NGINX_LDAP_TLS_STUNNEL_CHECK_IP"
|
|
|
|
# variables for nginx config
|
|
NGINX_LDAP_CA_PATH_LINE=" ssl_ca_dir $CA_TRUST_RUN_DIR;"
|
|
( [[ -n $NGINX_LDAP_TLS_STUNNEL_CHECK_HOST ]] || [[ -n $NGINX_LDAP_TLS_STUNNEL_CHECK_IP ]] ) && NGINX_LDAP_CHECK_REMOTE_CERT_LINE=" ssl_check_cert on;" || NGINX_LDAP_CHECK_REMOTE_CERT_LINE=" ssl_check_cert chain;"
|
|
fi
|
|
popd >/dev/null 2>&1
|
|
fi
|
|
|
|
if [[ -z $NGINX_BASIC_AUTH ]] || [[ "$NGINX_BASIC_AUTH" == "true" ]]; then
|
|
# doing HTTP basic auth instead of ldap
|
|
|
|
# point nginx_auth_rt.conf to nginx_auth_basic.conf
|
|
ln -sf "$NGINX_BASIC_AUTH_CONF" "$NGINX_RUNTIME_AUTH_CONF"
|
|
|
|
# ldap configuration is empty
|
|
ln -sf "$NGINX_BLANK_CONF" "$NGINX_RUNTIME_LDAP_CONF"
|
|
|
|
else
|
|
# point nginx_auth_rt.conf to nginx_auth_ldap.conf
|
|
ln -sf "$NGINX_LDAP_AUTH_CONF" "$NGINX_RUNTIME_AUTH_CONF"
|
|
|
|
# parse URL information out of user ldap configuration
|
|
# example:
|
|
# url "ldap://localhost:3268/DC=ds,DC=example,DC=com?sAMAccountName?sub?(objectClass=person)";
|
|
# "url" quote protocol h/p uri
|
|
# ↓ ↓ ↓ ↓ ↓
|
|
PATTERN='^(\s*url\s+)([''"]?)(\w+)://([^/]+)(/.*)$'
|
|
|
|
unset HEADER
|
|
unset OPEN_QUOTE
|
|
unset PROTOCOL
|
|
unset REMOTE_HOST
|
|
unset REMOTE_PORT
|
|
unset URI_TO_END
|
|
|
|
URL_LINE_NUM=0
|
|
READ_LINE_NUM=0
|
|
while IFS= read -r LINE; do
|
|
READ_LINE_NUM=$((READ_LINE_NUM+1))
|
|
if [[ $LINE =~ $PATTERN ]]; then
|
|
URL_LINE_NUM=$READ_LINE_NUM
|
|
HEADER=${BASH_REMATCH[1]}
|
|
OPEN_QUOTE=${BASH_REMATCH[2]}
|
|
PROTOCOL=${BASH_REMATCH[3]}
|
|
REMOTE=${BASH_REMATCH[4]}
|
|
REMOTE_ARR=(${REMOTE//:/ })
|
|
[[ -n ${REMOTE_ARR[0]} ]] && REMOTE_HOST=${REMOTE_ARR[0]}
|
|
[[ -n ${REMOTE_ARR[1]} ]] && REMOTE_PORT=${REMOTE_ARR[1]} || REMOTE_PORT=3268
|
|
URI_TO_END=${BASH_REMATCH[5]}
|
|
break
|
|
fi
|
|
done < "$NGINX_LDAP_USER_CONF"
|
|
|
|
if [[ "$NGINX_LDAP_TLS_STUNNEL" == "true" ]]; then
|
|
# user provided LDAP configuration, but we need to tweak it and set up stunnel to issue StartTLS
|
|
|
|
if [[ -z $REMOTE_HOST ]]; then
|
|
# missing LDAP info needed to configure tunnel, abort
|
|
exit 1
|
|
fi
|
|
|
|
# pick a random local port to listen on for the client side of the tunnel
|
|
read PORT_LOWER POWER_UPPER < /proc/sys/net/ipv4/ip_local_port_range
|
|
LOCAL_PORT=$(shuf -i $PORT_LOWER-$POWER_UPPER -n 1)
|
|
|
|
# create PEM key for stunnel (this key doesn't matter as we're only using stunnel in client mode)
|
|
pushd /tmp >/dev/null 2>&1
|
|
openssl genrsa -out key.pem 2048
|
|
openssl req -new -x509 -key key.pem -out cert.pem -days 3650 -subj "/CN=$(hostname)/O=Malcolm/C=US"
|
|
cat key.pem cert.pem > /etc/stunnel/stunnel.pem
|
|
chmod 600 /etc/stunnel/stunnel.pem
|
|
rm -f key.pem cert.pem
|
|
popd >/dev/null 2>&1
|
|
|
|
# configure stunnel
|
|
cat <<EOF > "$STUNNEL_CONF"
|
|
setuid = nginx
|
|
setgid = nginx
|
|
pid = /tmp/stunnel.pid
|
|
socket = l:TCP_NODELAY=1
|
|
socket = r:TCP_NODELAY=1
|
|
client = yes
|
|
foreground = yes
|
|
cert = /etc/stunnel/stunnel.pem
|
|
$STUNNEL_CA_PATH_LINE
|
|
$STUNNEL_VERIFY_LINE
|
|
$STUNNEL_CHECK_HOST_LINE
|
|
$STUNNEL_CHECK_IP_LINE
|
|
|
|
[stunnel.ldap_start_tls]
|
|
accept = localhost:$LOCAL_PORT
|
|
connect = $REMOTE_HOST:$REMOTE_PORT
|
|
protocol = ldap
|
|
EOF
|
|
|
|
# rewrite modified copy of user ldap configuration to point to local end of tunnel instead of remote
|
|
rm -f "$NGINX_RUNTIME_LDAP_CONF"
|
|
touch "$NGINX_RUNTIME_LDAP_CONF"
|
|
chmod 600 "$NGINX_RUNTIME_LDAP_CONF"
|
|
READ_LINE_NUM=0
|
|
while IFS= read -r LINE; do
|
|
READ_LINE_NUM=$((READ_LINE_NUM+1))
|
|
if (( $URL_LINE_NUM == $READ_LINE_NUM )); then
|
|
echo "${HEADER}${OPEN_QUOTE}ldap://localhost:${LOCAL_PORT}${URI_TO_END}" >> "$NGINX_RUNTIME_LDAP_CONF"
|
|
else
|
|
echo "$LINE" >> "$NGINX_RUNTIME_LDAP_CONF"
|
|
fi
|
|
done < "$NGINX_LDAP_USER_CONF"
|
|
|
|
else
|
|
# we're doing either LDAP or LDAPS, but not StartTLS, so we don't need to use stunnel.
|
|
# however, we do want to set SSL CA trust stuff if specified, so do that
|
|
rm -f "$NGINX_RUNTIME_LDAP_CONF"
|
|
touch "$NGINX_RUNTIME_LDAP_CONF"
|
|
chmod 600 "$NGINX_RUNTIME_LDAP_CONF"
|
|
READ_LINE_NUM=0
|
|
while IFS= read -r LINE; do
|
|
READ_LINE_NUM=$((READ_LINE_NUM+1))
|
|
echo "$LINE" >> "$NGINX_RUNTIME_LDAP_CONF"
|
|
if (( $URL_LINE_NUM == $READ_LINE_NUM )); then
|
|
echo "$NGINX_LDAP_CHECK_REMOTE_CERT_LINE" >> "$NGINX_RUNTIME_LDAP_CONF"
|
|
echo "$NGINX_LDAP_CA_PATH_LINE" >> "$NGINX_RUNTIME_LDAP_CONF"
|
|
fi
|
|
done < "$NGINX_LDAP_USER_CONF"
|
|
|
|
fi # stunnel/starttls vs. ldap/ldaps
|
|
|
|
fi # basic vs. ldap
|
|
|
|
# start supervisor (which will spawn nginx, stunnel, etc.) or whatever the default command is
|
|
exec "$@"
|