Redesign install-keycloak.sh and rename to install-keycloak-pgsql.sh.
This commit is contained in:
Executable
+536
@@ -0,0 +1,536 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Fresh Keycloak installation with PostgreSQL and nginx TLS termination.
|
||||
# Refuses to upgrade or overwrite an existing installation.
|
||||
|
||||
set -Eeuo pipefail
|
||||
umask 077
|
||||
|
||||
script_name="$(basename "$(realpath "$0")")"
|
||||
working_dir="$(dirname "$(realpath "$0")")"
|
||||
conf_dir="${working_dir}/conf"
|
||||
conf_file="${conf_dir}/keycloak.conf"
|
||||
lock_dir="/tmp/${script_name}.$$.LOCK"
|
||||
log_file="${lock_dir}/${script_name%.sh}.log"
|
||||
terminal=false
|
||||
[[ -t 1 ]] && terminal=true
|
||||
|
||||
cleanup() {
|
||||
rm -rf "${lock_dir}"
|
||||
}
|
||||
|
||||
fatal() {
|
||||
echo ""
|
||||
if ${terminal}; then
|
||||
echo -e " [ \033[31m\033[1mFatal\033[m ] $*" >&2
|
||||
echo ""
|
||||
echo -e " \033[1mScript is canceled\033[m.." >&2
|
||||
else
|
||||
echo " [ Fatal ] $*" >&2
|
||||
echo ""
|
||||
echo " Script is canceled.." >&2
|
||||
fi
|
||||
echo ""
|
||||
exit 1
|
||||
}
|
||||
|
||||
on_exit() {
|
||||
local status=$?
|
||||
cleanup
|
||||
exit "${status}"
|
||||
}
|
||||
trap on_exit EXIT
|
||||
trap 'fatal "Interrupted by signal."' HUP INT TERM
|
||||
mkdir "${lock_dir}" || exit 1
|
||||
|
||||
echononl() {
|
||||
if ${terminal}; then
|
||||
echo -e -n " $*" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
echo_ok() {
|
||||
if ${terminal}; then
|
||||
echo -e "\033[85G[ \033[32mok\033[m ]"
|
||||
else
|
||||
echo " [ ok ]"
|
||||
fi
|
||||
}
|
||||
|
||||
echo_failed() {
|
||||
if ${terminal}; then
|
||||
echo -e "\033[85G[ \033[1;31mfailed\033[m ]"
|
||||
else
|
||||
echo " [ failed ]"
|
||||
fi
|
||||
}
|
||||
|
||||
echo_skipped() {
|
||||
if ${terminal}; then
|
||||
echo -e "\033[85G[ \033[33m\033[1mskipped\033[m ]"
|
||||
else
|
||||
echo " [ skipped ]"
|
||||
fi
|
||||
}
|
||||
|
||||
blank_line() {
|
||||
echo ""
|
||||
}
|
||||
|
||||
section() {
|
||||
blank_line
|
||||
echo -e "\033[37m\033[1m$*\033[m"
|
||||
blank_line
|
||||
}
|
||||
|
||||
info() {
|
||||
blank_line
|
||||
if ${terminal}; then
|
||||
echo -e " [ \033[32m\033[1mInfo\033[m ] $*"
|
||||
else
|
||||
echo " [ Info ] $*"
|
||||
fi
|
||||
blank_line
|
||||
}
|
||||
|
||||
require_command() {
|
||||
command -v "$1" >/dev/null 2>&1 || \
|
||||
fatal "Required command '$1' is not installed."
|
||||
}
|
||||
|
||||
validate_identifier() {
|
||||
[[ "$1" =~ ^[a-z_][a-z0-9_]*$ ]]
|
||||
}
|
||||
|
||||
validate_fqdn() {
|
||||
[[ "$1" =~ ^([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$ ]]
|
||||
}
|
||||
|
||||
generate_password() {
|
||||
printf 'A9_%s' "$(openssl rand -hex 16)"
|
||||
}
|
||||
|
||||
read_default() {
|
||||
local variable_name=$1
|
||||
local label=$2
|
||||
local default_value=$3
|
||||
local value
|
||||
|
||||
echononl "${label} [${default_value}]: "
|
||||
IFS= read -r value
|
||||
printf -v "${variable_name}" '%s' "${value:-${default_value}}"
|
||||
}
|
||||
|
||||
[[ ${EUID} -eq 0 ]] || fatal "This script must be run as root."
|
||||
${terminal} || fatal "Script must run in a terminal."
|
||||
for cmd in \
|
||||
createdb curl dropuser getent groupadd gzip id java nginx openssl \
|
||||
pg_isready psql runuser sha256sum systemctl tar useradd wget; do
|
||||
require_command "${cmd}"
|
||||
done
|
||||
|
||||
DEFAULT_FQHN_HOSTNAME="$(hostname -f)"
|
||||
DEFAULT_KEYCLOAK_USER="keycloak"
|
||||
DEFAULT_KEYCLOAK_GROUP="keycloak"
|
||||
DEFAULT_KEYCLOAK_BASE_INSTALL_PATH="/opt"
|
||||
DEFAULT_DB_NAME="keycloak"
|
||||
DEFAULT_DB_USER="keycloak"
|
||||
DEFAULT_DB_PASS="$(generate_password)"
|
||||
DEFAULT_ADMIN_USER="temp-admin"
|
||||
|
||||
if [[ -f "${conf_file}" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${conf_file}" >"${log_file}" 2>&1 || fatal "Cannot read '${conf_file}'."
|
||||
[[ -n ${FQHN_HOSTNAME:-} ]] && DEFAULT_FQHN_HOSTNAME="${FQHN_HOSTNAME}"
|
||||
[[ -n ${KEYCLOAK_USER:-} ]] && DEFAULT_KEYCLOAK_USER="${KEYCLOAK_USER}"
|
||||
[[ -n ${KEYCLOAK_GROUP:-} ]] && DEFAULT_KEYCLOAK_GROUP="${KEYCLOAK_GROUP}"
|
||||
[[ -n ${KEYCLOAK_BASE_INSTALL_PATH:-} ]] && DEFAULT_KEYCLOAK_BASE_INSTALL_PATH="${KEYCLOAK_BASE_INSTALL_PATH}"
|
||||
[[ -n ${DB_NAME:-} ]] && DEFAULT_DB_NAME="${DB_NAME}"
|
||||
[[ -n ${DB_USER:-} ]] && DEFAULT_DB_USER="${DB_USER}"
|
||||
[[ -n ${DB_PASS:-} ]] && DEFAULT_DB_PASS="${DB_PASS}"
|
||||
fi
|
||||
|
||||
blank_line
|
||||
echo -e "\033[1m----------\033[m"
|
||||
echo -e "\033[32m\033[1mRunning script \033[m\033[1m${script_name}\033[32m .. \033[m"
|
||||
echo -e "\033[1m----------\033[m"
|
||||
|
||||
blank_line
|
||||
echo -e "\033[32m--\033[m"
|
||||
blank_line
|
||||
echo "Version Number of Keycloak Server to install"
|
||||
blank_line
|
||||
echo " see: https://keycloak.org/downloads"
|
||||
blank_line
|
||||
echononl "KEYCLOAK Server Version: "
|
||||
IFS= read -r KEYCLOAK_VERSION
|
||||
[[ ${KEYCLOAK_VERSION} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fatal "Invalid version. Expected format: 26.7.3"
|
||||
|
||||
blank_line
|
||||
echo -e "\033[32m--\033[m"
|
||||
blank_line
|
||||
echo "Specify the base directory in which Keycloak is to be installed."
|
||||
blank_line
|
||||
read_default KEYCLOAK_BASE_INSTALL_PATH "Base installation directory" "${DEFAULT_KEYCLOAK_BASE_INSTALL_PATH}"
|
||||
[[ -d ${KEYCLOAK_BASE_INSTALL_PATH} ]] || fatal "Directory '${KEYCLOAK_BASE_INSTALL_PATH}' does not exist."
|
||||
KEYCLOAK_INSTALL_DIR="${KEYCLOAK_BASE_INSTALL_PATH}/keycloak-${KEYCLOAK_VERSION}"
|
||||
KEYCLOAK_LINK="${KEYCLOAK_BASE_INSTALL_PATH}/keycloak"
|
||||
|
||||
blank_line
|
||||
echo -e "\033[32m--\033[m"
|
||||
blank_line
|
||||
echo "Enter user and group for Keycloak Service."
|
||||
blank_line
|
||||
read_default KEYCLOAK_USER "Keycloak system user" "${DEFAULT_KEYCLOAK_USER}"
|
||||
read_default KEYCLOAK_GROUP "Keycloak system group" "${DEFAULT_KEYCLOAK_GROUP}"
|
||||
|
||||
blank_line
|
||||
echo -e "\033[32m--\033[m"
|
||||
blank_line
|
||||
echo "Insert full qualified hostname for Keycloak Service"
|
||||
blank_line
|
||||
read_default FQHN_HOSTNAME "Public Keycloak hostname" "${DEFAULT_FQHN_HOSTNAME}"
|
||||
validate_fqdn "${FQHN_HOSTNAME}" || fatal "Invalid FQDN '${FQHN_HOSTNAME}'."
|
||||
|
||||
blank_line
|
||||
echo -e "\033[32m--\033[m"
|
||||
blank_line
|
||||
echo "Enter PostgreSQL database name and user for Keycloak Service"
|
||||
blank_line
|
||||
read_default DB_NAME "PostgreSQL database" "${DEFAULT_DB_NAME}"
|
||||
read_default DB_USER "PostgreSQL user" "${DEFAULT_DB_USER}"
|
||||
validate_identifier "${DB_NAME}" || fatal "Invalid PostgreSQL database name '${DB_NAME}'."
|
||||
validate_identifier "${DB_USER}" || fatal "Invalid PostgreSQL role name '${DB_USER}'."
|
||||
|
||||
blank_line
|
||||
echo -e "\033[32m--\033[m"
|
||||
blank_line
|
||||
echo "Enter Database Password used by Keycloak Service"
|
||||
blank_line
|
||||
echononl "Database Password [generated/configured value]: "
|
||||
IFS= read -r -s DB_PASS_INPUT
|
||||
printf '\n'
|
||||
DB_PASS="${DB_PASS_INPUT:-${DEFAULT_DB_PASS}}"
|
||||
[[ ${#DB_PASS} -ge 12 ]] || fatal "Database password must contain at least 12 characters."
|
||||
unset DB_PASS_INPUT
|
||||
read_default ADMIN_USER "Temporary bootstrap administrator" "${DEFAULT_ADMIN_USER}"
|
||||
[[ ${ADMIN_USER} =~ ^[A-Za-z0-9._-]+$ ]] || fatal "Invalid administrator username."
|
||||
ADMIN_PASS="$(generate_password)"
|
||||
|
||||
DOWNLOAD_ARCHIVE="keycloak-${KEYCLOAK_VERSION}.tar.gz"
|
||||
DOWNLOAD_URL="https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/${DOWNLOAD_ARCHIVE}"
|
||||
DOWNLOAD_PATH="${working_dir}/${DOWNLOAD_ARCHIVE}"
|
||||
NGINX_AVAILABLE="/etc/nginx/sites-available/${FQHN_HOSTNAME}.conf"
|
||||
NGINX_ENABLED="/etc/nginx/sites-enabled/${FQHN_HOSTNAME}.conf"
|
||||
CERT_DIR="/var/lib/dehydrated/certs/${FQHN_HOSTNAME}"
|
||||
|
||||
blank_line
|
||||
blank_line
|
||||
echo -e "\t\033[32mStart install script for Keycloak Service with the following parameters\033[m"
|
||||
blank_line
|
||||
echo -e "\tKeycloak Server Version........: \033[33m\033[1m${KEYCLOAK_VERSION}\033[m"
|
||||
blank_line
|
||||
echo -e "\tFull qualified Hostname.......: ${FQHN_HOSTNAME}"
|
||||
echo -e "\tKeycloak user.................: ${KEYCLOAK_USER}"
|
||||
echo -e "\tKeycloak group................: ${KEYCLOAK_GROUP}"
|
||||
blank_line
|
||||
echo -e "\tKeycloak base install dir.....: ${KEYCLOAK_BASE_INSTALL_PATH}"
|
||||
echo -e "\tKeycloak install dir..........: ${KEYCLOAK_INSTALL_DIR}"
|
||||
blank_line
|
||||
echo -e "\tDatabase Type.................: PostgreSQL"
|
||||
echo -e "\tDatabase Name.................: ${DB_NAME}"
|
||||
echo -e "\tDatabase User.................: ${DB_USER}"
|
||||
echo -e "\tDatabase Password.............: ********"
|
||||
blank_line
|
||||
echo -e "\tTemporary administrator......: ${ADMIN_USER}"
|
||||
blank_line
|
||||
echononl "einverstanden (yes/no): "
|
||||
IFS= read -r answer
|
||||
[[ ${answer,,} == yes ]] || fatal "Installation cancelled."
|
||||
|
||||
# A fresh installer must never become an accidental upgrade or reinstall.
|
||||
[[ ! -e ${KEYCLOAK_LINK} && ! -L ${KEYCLOAK_LINK} ]] || fatal "'${KEYCLOAK_LINK}' exists. Use the upgrade script."
|
||||
[[ ! -e ${KEYCLOAK_INSTALL_DIR} ]] || fatal "'${KEYCLOAK_INSTALL_DIR}' already exists."
|
||||
[[ ! -e /etc/systemd/system/keycloak.service ]] || fatal "Keycloak systemd unit already exists."
|
||||
if systemctl cat keycloak.service >/dev/null 2>&1; then
|
||||
fatal "A Keycloak systemd unit is already installed."
|
||||
fi
|
||||
[[ ! -e ${NGINX_AVAILABLE} && ! -L ${NGINX_ENABLED} ]] || fatal "nginx vHost for '${FQHN_HOSTNAME}' already exists."
|
||||
pg_isready -q || fatal "PostgreSQL is not ready."
|
||||
if runuser -u postgres -- psql -Atqc \
|
||||
"SELECT 1 FROM pg_database WHERE datname = '${DB_NAME}'" | grep -qx 1; then
|
||||
fatal "Database '${DB_NAME}' already exists. Nothing was changed."
|
||||
fi
|
||||
|
||||
if runuser -u postgres -- psql -Atqc \
|
||||
"SELECT 1 FROM pg_roles WHERE rolname = '${DB_USER}'" | grep -qx 1; then
|
||||
fatal "Role '${DB_USER}' already exists. Nothing was changed."
|
||||
fi
|
||||
|
||||
for file in fullchain.pem privkey.pem chain.pem; do
|
||||
[[ -r ${CERT_DIR}/${file} ]] || \
|
||||
fatal "Certificate file '${CERT_DIR}/${file}' is missing."
|
||||
done
|
||||
openssl x509 -in "${CERT_DIR}/fullchain.pem" -noout -checkend 86400 >/dev/null || fatal "TLS certificate is invalid or expires within 24 hours."
|
||||
openssl x509 -in "${CERT_DIR}/fullchain.pem" -noout -ext subjectAltName | grep -Fq "DNS:${FQHN_HOSTNAME}" || fatal "Certificate does not cover '${FQHN_HOSTNAME}'."
|
||||
cert_hash="$(openssl x509 -in "${CERT_DIR}/fullchain.pem" -pubkey -noout | openssl pkey -pubin -outform DER | sha256sum | awk '{print $1}')"
|
||||
key_hash="$(openssl pkey -in "${CERT_DIR}/privkey.pem" -pubout -outform DER | sha256sum | awk '{print $1}')"
|
||||
[[ ${cert_hash} == "${key_hash}" ]] || \
|
||||
fatal "TLS certificate and private key do not match."
|
||||
|
||||
section "Some checks...."
|
||||
echononl "Check prerequisites, existing installation, database and certificate.."
|
||||
echo_ok
|
||||
|
||||
section "Download Keycloak Service.."
|
||||
echononl "Download version ${KEYCLOAK_VERSION} of the Keycloak Server.."
|
||||
if [[ ! -f ${DOWNLOAD_PATH} ]]; then
|
||||
wget -O "${DOWNLOAD_PATH}.part" "${DOWNLOAD_URL}" >"${log_file}" 2>&1 || fatal "Download failed: $(cat "${log_file}")"
|
||||
mv "${DOWNLOAD_PATH}.part" "${DOWNLOAD_PATH}"
|
||||
echo_ok
|
||||
else
|
||||
echo_skipped
|
||||
fi
|
||||
|
||||
echononl "Verify downloaded archive.."
|
||||
tar -tzf "${DOWNLOAD_PATH}" >/dev/null 2>"${log_file}" || fatal "Invalid archive: $(cat "${log_file}")"
|
||||
echo_ok
|
||||
|
||||
section "Create Keycloak system user and group.."
|
||||
|
||||
echononl "Create the Keycloak system group '${KEYCLOAK_GROUP}'.."
|
||||
if ! getent group "${KEYCLOAK_GROUP}" >/dev/null; then
|
||||
groupadd --system "${KEYCLOAK_GROUP}" || fatal "Cannot create group."
|
||||
echo_ok
|
||||
else
|
||||
echo_skipped
|
||||
fi
|
||||
|
||||
echononl "Create the Keycloak system user '${KEYCLOAK_USER}'.."
|
||||
if ! id "${KEYCLOAK_USER}" >/dev/null 2>&1; then
|
||||
useradd --system --no-create-home --home-dir "${KEYCLOAK_LINK}" --shell /usr/sbin/nologin --gid "${KEYCLOAK_GROUP}" "${KEYCLOAK_USER}" || fatal "Cannot create user."
|
||||
echo_ok
|
||||
else
|
||||
echo_skipped
|
||||
fi
|
||||
[[ $(id -gn "${KEYCLOAK_USER}") == "${KEYCLOAK_GROUP}" ]] || fatal "User '${KEYCLOAK_USER}' has a different primary group."
|
||||
|
||||
section "Installing Keycloak Service.."
|
||||
|
||||
echononl "Extract the Keycloak Service files.."
|
||||
tar -C "${KEYCLOAK_BASE_INSTALL_PATH}" -xzf "${DOWNLOAD_PATH}" >"${log_file}" 2>&1 || fatal "Extraction failed: $(cat "${log_file}")"
|
||||
[[ -x ${KEYCLOAK_INSTALL_DIR}/bin/kc.sh ]] || fatal "Extracted installation is incomplete."
|
||||
echo_ok
|
||||
|
||||
echononl "Backup original Keycloak configuration file.."
|
||||
cp -a "${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf" "${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf.ORIG"
|
||||
echo_ok
|
||||
|
||||
echononl "Create new Keycloak configuration.."
|
||||
cat >"${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf" <<EOF
|
||||
# Keycloak behind an nginx TLS-terminating reverse proxy
|
||||
db=postgres
|
||||
db-url=jdbc:postgresql://localhost/${DB_NAME}
|
||||
db-username=${DB_USER}
|
||||
db-password=${DB_PASS}
|
||||
|
||||
hostname=${FQHN_HOSTNAME}
|
||||
hostname-strict=true
|
||||
http-enabled=true
|
||||
http-host=127.0.0.1
|
||||
http-port=8080
|
||||
proxy-headers=xforwarded
|
||||
health-enabled=true
|
||||
EOF
|
||||
chmod 0640 "${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf"
|
||||
echo_ok
|
||||
|
||||
echononl "Create a new and optimized Keycloak server image.."
|
||||
"${KEYCLOAK_INSTALL_DIR}/bin/kc.sh" build >"${log_file}" 2>&1 || fatal "Keycloak build failed: $(cat "${log_file}")"
|
||||
echo_ok
|
||||
|
||||
echononl "Set ownership of installation directory '${KEYCLOAK_INSTALL_DIR}'.."
|
||||
chown -R "${KEYCLOAK_USER}:${KEYCLOAK_GROUP}" "${KEYCLOAK_INSTALL_DIR}"
|
||||
echo_ok
|
||||
|
||||
section "Create PostgreSQL database and role.."
|
||||
|
||||
echononl "Create PostgreSQL role '${DB_USER}'.."
|
||||
runuser -u postgres -- psql --set=db_user="${DB_USER}" --set=db_pass="${DB_PASS}" --no-psqlrc --set=ON_ERROR_STOP=1 postgres >"${log_file}" 2>&1 <<'SQL' || fatal "Creating PostgreSQL role failed: $(cat "${log_file}")"
|
||||
SELECT format('CREATE ROLE %I LOGIN PASSWORD %L', :'db_user', :'db_pass') \gexec
|
||||
SQL
|
||||
echo_ok
|
||||
|
||||
echononl "Create PostgreSQL database '${DB_NAME}'.."
|
||||
if ! runuser -u postgres -- createdb --owner="${DB_USER}" "${DB_NAME}" >"${log_file}" 2>&1; then
|
||||
runuser -u postgres -- dropuser "${DB_USER}" >/dev/null 2>&1 || true
|
||||
fatal "Creating PostgreSQL database failed: $(cat "${log_file}")"
|
||||
fi
|
||||
echo_ok
|
||||
|
||||
new_link="${KEYCLOAK_BASE_INSTALL_PATH}/.keycloak.new.$$"
|
||||
|
||||
echononl "Create symlink keycloak -> keycloak-${KEYCLOAK_VERSION} .."
|
||||
ln -s "keycloak-${KEYCLOAK_VERSION}" "${new_link}" || fatal "Cannot create temporary symlink."
|
||||
mv -Tf "${new_link}" "${KEYCLOAK_LINK}" || fatal "Cannot activate Keycloak symlink."
|
||||
echo_ok
|
||||
|
||||
section "Setup Keycloak to use systemd for starting and stopping.."
|
||||
|
||||
echononl "Create systemd unit file.."
|
||||
cat >/etc/systemd/system/keycloak.service <<EOF
|
||||
[Unit]
|
||||
Description=Keycloak Server
|
||||
After=network.target postgresql.service
|
||||
Requires=postgresql.service
|
||||
|
||||
[Service]
|
||||
User=${KEYCLOAK_USER}
|
||||
Group=${KEYCLOAK_GROUP}
|
||||
ExecStart=${KEYCLOAK_LINK}/bin/kc.sh start --optimized
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
SuccessExitStatus=143
|
||||
LimitNOFILE=102400
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
echo_ok
|
||||
|
||||
echononl "Make systemd load the new unit.."
|
||||
systemctl daemon-reload
|
||||
echo_ok
|
||||
|
||||
echononl "Set Keycloak Service to start on machine startup.."
|
||||
systemctl enable keycloak.service >"${log_file}" 2>&1 || fatal "Enabling Keycloak failed: $(cat "${log_file}")"
|
||||
echo_ok
|
||||
|
||||
section "Create temporary Keycloak administrator.."
|
||||
|
||||
echononl "Generate temporary bootstrap administrator '${ADMIN_USER}'.."
|
||||
export KC_BOOTSTRAP_ADMIN_PASSWORD="${ADMIN_PASS}"
|
||||
runuser -u "${KEYCLOAK_USER}" --preserve-environment -- "${KEYCLOAK_LINK}/bin/kc.sh" bootstrap-admin user \
|
||||
--username "${ADMIN_USER}" --password:env KC_BOOTSTRAP_ADMIN_PASSWORD --no-prompt >"${log_file}" 2>&1 || fatal "Creating bootstrap administrator failed: $(cat "${log_file}")"
|
||||
unset KC_BOOTSTRAP_ADMIN_PASSWORD
|
||||
echo_ok
|
||||
|
||||
section "Configuring NGINX with SSL and HTTP/2.."
|
||||
|
||||
echononl "Create NGINX virtual host configuration for '${FQHN_HOSTNAME}'.."
|
||||
cat >"${NGINX_AVAILABLE}" <<EOF
|
||||
# -- ${FQHN_HOSTNAME} --
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${FQHN_HOSTNAME};
|
||||
include snippets/letsencrypt-acme-challenge.conf;
|
||||
return 301 https://\$host\$request_uri;
|
||||
}
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
server_name ${FQHN_HOSTNAME};
|
||||
include snippets/letsencrypt-acme-challenge.conf;
|
||||
ssl_certificate ${CERT_DIR}/fullchain.pem;
|
||||
ssl_certificate_key ${CERT_DIR}/privkey.pem;
|
||||
ssl_trusted_certificate ${CERT_DIR}/chain.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_session_tickets off;
|
||||
add_header Strict-Transport-Security "max-age=15768000" always;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Host \$host;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
chmod 0644 "${NGINX_AVAILABLE}"
|
||||
echo_ok
|
||||
|
||||
echononl "Enable created NGINX configuration.."
|
||||
ln -s "../sites-available/${FQHN_HOSTNAME}.conf" "${NGINX_ENABLED}"
|
||||
echo_ok
|
||||
|
||||
echononl "Check NGINX configuration.."
|
||||
if ! nginx -t >"${log_file}" 2>&1; then
|
||||
rm -f "${NGINX_ENABLED}"
|
||||
echo_failed
|
||||
fatal "nginx test failed; vHost was disabled: $(cat "${log_file}")"
|
||||
fi
|
||||
echo_ok
|
||||
|
||||
echononl "Reload NGINX Service.."
|
||||
systemctl reload nginx >"${log_file}" 2>&1 || fatal "Reloading nginx failed: $(cat "${log_file}")"
|
||||
echo_ok
|
||||
|
||||
section "Start and check Keycloak Service.."
|
||||
|
||||
echononl "Start Keycloak Service.."
|
||||
systemctl start keycloak.service >"${log_file}" 2>&1 || fatal "Starting Keycloak failed: $(cat "${log_file}")"
|
||||
echo_ok
|
||||
|
||||
echononl "Wait until Keycloak answers with the expected OIDC issuer.."
|
||||
discovery_file="${lock_dir}/openid-configuration.json"
|
||||
healthy=false
|
||||
for ((second=0; second<90; second++)); do
|
||||
if systemctl is-active --quiet keycloak.service && curl --fail --silent --show-error \
|
||||
-H "Host: ${FQHN_HOSTNAME}" -H "X-Forwarded-Host: ${FQHN_HOSTNAME}" -H "X-Forwarded-Proto: https" \
|
||||
"http://127.0.0.1:8080/realms/master/.well-known/openid-configuration" -o "${discovery_file}" 2>"${log_file}" && \
|
||||
grep -Eq '"issuer"[[:space:]]*:[[:space:]]*"https://'"${FQHN_HOSTNAME//./\.}"'/realms/master"' "${discovery_file}"; then
|
||||
healthy=true
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! ${healthy}; then
|
||||
journalctl -u keycloak.service -n 80 --no-pager >"${log_file}" 2>&1 || true
|
||||
fatal "Keycloak did not become healthy within 90 seconds. Last logs:\n$(cat "${log_file}")"
|
||||
fi
|
||||
echo_ok
|
||||
|
||||
section "Some post-installation stuff.."
|
||||
|
||||
echononl "Save installation configuration to 'conf/keycloak.conf'.."
|
||||
mkdir -p "${conf_dir}"
|
||||
cat >"${conf_file}" <<EOF
|
||||
FQHN_HOSTNAME="${FQHN_HOSTNAME}"
|
||||
KEYCLOAK_USER="${KEYCLOAK_USER}"
|
||||
KEYCLOAK_GROUP="${KEYCLOAK_GROUP}"
|
||||
KEYCLOAK_BASE_INSTALL_PATH="${KEYCLOAK_BASE_INSTALL_PATH}"
|
||||
DB_TYPE="pgsql"
|
||||
DB_NAME="${DB_NAME}"
|
||||
DB_USER="${DB_USER}"
|
||||
DB_PASS="${DB_PASS}"
|
||||
EOF
|
||||
chmod 0600 "${conf_file}"
|
||||
echo_ok
|
||||
|
||||
echononl "Save temporary administrator credentials.."
|
||||
credentials_file="${working_dir}/login-credentials-temp-admin.txt"
|
||||
cat >"${credentials_file}" <<EOF
|
||||
Temporary Keycloak bootstrap administrator
|
||||
URL: https://${FQHN_HOSTNAME}
|
||||
Username: ${ADMIN_USER}
|
||||
Password: ${ADMIN_PASS}
|
||||
|
||||
Create a permanent administrator and remove this temporary account promptly.
|
||||
EOF
|
||||
chmod 0600 "${credentials_file}"
|
||||
echo_ok
|
||||
|
||||
echononl "Save effective Keycloak configuration to 'current-configuration.txt'.."
|
||||
"${KEYCLOAK_LINK}/bin/kc.sh" show-config >"${working_dir}/current-configuration.txt" 2>"${log_file}" || fatal "Saving effective configuration failed: $(cat "${log_file}")"
|
||||
chmod 0600 "${working_dir}/current-configuration.txt"
|
||||
echo_ok
|
||||
|
||||
info "Keycloak ${KEYCLOAK_VERSION} is running at https://${FQHN_HOSTNAME}
|
||||
Temporary administrator credentials: ${credentials_file}
|
||||
Create and test a permanent administrator, then delete the temporary account."
|
||||
Reference in New Issue
Block a user