-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #25144: Add a command to help splitting virtualhosts
- Loading branch information
Showing
2 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
#!/bin/bash | ||
|
||
usage() { | ||
echo "Usage: split-vhost.sh [-b|-c <certificate_path> -k <key_path>] [-l] <agent_vhost> <user_vhost>" | ||
echo " <xx_vhost>: virtualhost definition to use, must be one of:" | ||
echo " <ip>, <ip>:<port>, <hostname>, <hostname>:<port>" | ||
echo " - if <port> is not provided, it defaults to 443" | ||
echo " - if <ip> is provided, the IP address must be assigned to this host" | ||
echo " - if <ip> is an IPv6, it must be surrounded by square brackets (eg: [2001::1])" | ||
echo " - if <hostname> is provided, dns entry must already point to this host" | ||
echo " -b: use certbot to issue certificate (only available if <vhost2> is of the form <hostname>)" | ||
echo " -c: provide an already issued certificate path (full certificate chain is accepted)" | ||
echo " -k: provide an already issued certificate key path" | ||
echo " -l: force apache to listen only on provided IP (only available for vhost of the form <ip> and <ip>:<port>)" | ||
echo " The certificate will only be used for user (browser) communication, since Rudder provides" | ||
echo " its own certificate for agent communication" | ||
# -t <test_file> is undocumented, it uses test_file to test configuration replacement but does not run other commands | ||
# CERTBOT_OPTS is available as an environment variable ex | ||
# CERTBOT_OPTS="--register-unsafely-without-email --agree-tos" | ||
} | ||
|
||
CERT_BOT="no" | ||
CERT_PATH="" | ||
KEY_PATH="" | ||
STRICT_LISTEN="no" | ||
TEST="" | ||
ORIGINAL_CONF="/opt/rudder/share/apache.conf" | ||
|
||
# Detect one of the main Server base OS : RHEL, SUSE, Debian | ||
if command -vp apt-get > /dev/null; then | ||
APACHE_CONF="/etc/apache2/sites-enabled/rudder.conf" | ||
SERVICE="apache2" | ||
elif command -vp zypper > /dev/null; then | ||
APACHE_CONF="/etc/apache2/vhosts.d/rudder.conf" | ||
SERVICE="apache2" | ||
elif command -vp dnf > /dev/null; then | ||
APACHE_CONF="/etc/httpd/conf.d/rudder.conf" | ||
SERVICE="httpd" | ||
else | ||
echo "Unknown base OS, aborting" | ||
exit 1 | ||
fi | ||
|
||
# Parameters | ||
############ | ||
while getopts "bc:k:lt:" opt; do | ||
case ${opt} in | ||
b) | ||
CERT_BOT="yes" | ||
;; | ||
c) | ||
CERT_PATH="${OPTARG}" | ||
;; | ||
k) | ||
KEY_PATH="${OPTARG}" | ||
;; | ||
l) | ||
STRICT_LISTEN="yes" | ||
;; | ||
t) | ||
TEST="yes" | ||
APACHE_CONF="${OPTARG}" | ||
;; | ||
h) | ||
usage | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
|
||
shift $(($OPTIND-1)) | ||
if [ $# -ne 2 ] | ||
then | ||
usage | ||
echo "ERROR: provide exactly 2 vhost" | ||
exit 1 | ||
fi | ||
|
||
AGENT_HOST=${1%:[[:digit:]]*} | ||
AGENT_PORT=$(echo "$1" | perl -pe 's/^(.*?)(?::(\d+))?$/$2/') | ||
USER_HOST=${2%:[[:digit:]]*} | ||
USER_PORT=$(echo "$2" | perl -pe 's/^(.*?)(?::(\d+))?$/$2/') | ||
|
||
# Sanity checks | ||
############### | ||
|
||
is_ip() { | ||
RE='((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))' | ||
echo "${1//[][]}" | grep -qE "${RE}" | ||
} | ||
|
||
# -b -c -k compatibility | ||
if [ "${CERT_BOT}" = "yes" ] | ||
then | ||
if [ "${CERT_PATH}" != "" ] || [ "${KEY_PATH}" != "" ]; then | ||
echo "Option -b is not compatible with -c and -k" | ||
exit 1 | ||
fi | ||
else | ||
if [ "${CERT_PATH}" = "" ] || [ "${KEY_PATH}" = "" ]; then | ||
echo "You must provide both a Certificate path (-c) and a key path (-k)" | ||
exit 1 | ||
fi | ||
fi | ||
|
||
# -l means IP only | ||
if is_ip "${AGENT_HOST}"; then | ||
AGENT_HOST_IS_IP=yes | ||
elif [ "${STRICT_LISTEN}" = "yes" ]; then | ||
echo "Option -l only works IP based vhost split" | ||
exit 1 | ||
fi | ||
|
||
if is_ip "${USER_HOST}"; then | ||
USER_HOST_IS_IP=yes | ||
elif [ "${STRICT_LISTEN}" = "yes" ]; then | ||
echo "Option -l only works IP based vhost split" | ||
exit 1 | ||
fi | ||
|
||
echo "Creating a backup of ${APACHE_CONF} in ${APACHE_CONF}.backup" | ||
cp "${APACHE_CONF}" "${APACHE_CONF}.backup" | ||
|
||
if ! grep -q "^#SINGLE_VHOST_START" "${APACHE_CONF}" | ||
then | ||
echo "Your apache configuration ${APACHE_CONF} cannot be split, either because it is too old or beacause it has already been customized" | ||
echo "Continuing will reset your current configuration to original one" | ||
echo -n "Please type 'yes' to start again with a default configuration: " | ||
read a | ||
if [ "${a}" != "yes" ]; then | ||
echo "Aborting" | ||
exit 1 | ||
fi | ||
cp "${ORIGINAL_CONF}" "${APACHE_CONF}" | ||
fi | ||
|
||
# Preparation | ||
############# | ||
|
||
if [ "${TEST}" = "" ] | ||
then | ||
rudder agent disable -s | ||
systemctl stop ${SERVICE} | ||
fi | ||
|
||
# run certbot if required | ||
######################### | ||
|
||
if [ "${CERT_BOT}" = "yes" ] | ||
then | ||
if [ "${TEST}" = "" ]; then | ||
apt install -y certbot python3-certbot-apache | ||
certbot certonly --standalone ${CERTBOT_OPTS} -d "${USER_HOST}" | ||
fi | ||
CERT_PATH="/etc/letsencrypt/live/${USER_HOST}/fullchain.pem" | ||
KEY_PATH="/etc/letsencrypt/live/${USER_HOST}/privkey.pem" | ||
fi | ||
|
||
# Replacements | ||
############## | ||
|
||
# comment original vhost and uncomment splitted one | ||
sed -i '/#SINGLE_VHOST_START/,/#SINGLE_VHOST_END/s/^/# /' "${APACHE_CONF}" | ||
sed -i '/#MULTI_VHOST_START/,/#MULTI_VHOST_END/s/^#\( \|$\)//' "${APACHE_CONF}" | ||
|
||
# Append Listen directives | ||
AGENT_PORT=${AGENT_PORT:-443} | ||
USER_PORT=${USER_PORT:-443} | ||
if [ "${STRICT_LISTEN}" = "yes" ] | ||
then | ||
sed -i '/# Listen <PORT>/aListen '${AGENT_HOST}:${AGENT_PORT} "${APACHE_CONF}" | ||
sed -i '/# Listen <PORT>/aListen '${USER_HOST}:${USER_PORT} "${APACHE_CONF}" | ||
else | ||
if [ "${AGENT_PORT}" != "443" ]; then | ||
sed -i '/# Listen <PORT>/aListen '${AGENT_PORT} "${APACHE_CONF}" | ||
fi | ||
if [ "${USER_PORT}" != "443" ]; then | ||
sed -i '/# Listen <PORT>/aListen '${USER_PORT} "${APACHE_CONF}" | ||
fi | ||
fi | ||
|
||
# Edit Virtualhost directives | ||
if [ "${AGENT_HOST_IS_IP}" = "yes" ]; then | ||
AGENT_IP="${AGENT_HOST}" | ||
sed -i 's/.*\(ServerName <AGENT_HOST>\)/#\1/' "${APACHE_CONF}" | ||
else | ||
AGENT_IP="*" | ||
fi | ||
if [ "${USER_HOST_IS_IP}" = "yes" ]; then | ||
USER_IP="${USER_HOST}" | ||
sed -i 's/.*\(ServerName <USER_HOST>\)/#\1/' "${APACHE_CONF}" | ||
else | ||
USER_IP="*" | ||
fi | ||
sed -i '/#AGENT_VHOST/,/#USER_VHOST/s/<VirtualHost .*>/<VirtualHost '${AGENT_IP}:${AGENT_PORT}'>/' "${APACHE_CONF}" | ||
sed -i '/#USER_VHOST/,$s/<VirtualHost .*>/<VirtualHost '${USER_IP}:${USER_PORT}'>/' "${APACHE_CONF}" | ||
|
||
# Generic variable replacement | ||
sed -i 's/<AGENT_HOST>/'${AGENT_HOST}'/' "${APACHE_CONF}" | ||
sed -i 's/<USER_HOST>/'${USER_HOST}'/' "${APACHE_CONF}" | ||
sed -i 's|<CERT_PATH>|'${CERT_PATH}'|' "${APACHE_CONF}" | ||
sed -i 's|<KEY_PATH>|'${KEY_PATH}'|' "${APACHE_CONF}" | ||
|
||
|
||
# End | ||
##### | ||
|
||
if [ "${TEST}" = "" ]; then | ||
systemctl start ${SERVICE} | ||
rudder agent enable | ||
fi |