#!/usr/bin/env bash script_name="$(basename $(realpath $0))" working_dir="$(dirname $(realpath $0))" #conf_file="${working_dir}/conf/${script_name%%.*}.conf" conf_file="${working_dir}/conf/keycloak.conf" LOCK_DIR="/tmp/$(basename $0).$$.LOCK" log_file="${LOCK_DIR}/${script_name%%.*}.log" backup_date="$(date +%Y-%m-%d-%H%M)" crontab_backup_file="${working_dir}/crontab-root-${backup_date}" # ---------- # Base Function(s) # ---------- clean_up() { # Perform program exit housekeeping rm -rf "$LOCK_DIR" blank_line exit $1 } echononl(){ if $terminal ; then echo X\\c > /tmp/shprompt$$ if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then echo -e -n " $*\\c" 1>&2 else echo -e -n " $*" 1>&2 fi rm /tmp/shprompt$$ fi } fatal(){ if $terminal ; then echo "" echo -e " [ \033[31m\033[1mFatal\033[m ] $*" echo "" echo -e " \033[1mScript is canceled\033[m.." echo "" else echo "" echo -e " [ Fatal ] $*" echo "" echo -e " Script is canceled.." echo "" fi if [[ -f "${crontab_backup_file}" ]]; then echononl "Reenable previously saved crontab from '$(basename "${crontab_backup_file}")'.." crontab ${crontab_backup_file} > /dev/null 2>&1 if [[ $? -eq 0 ]]; then echo_ok rm -f ${crontab_backup_file} > /dev/null 2>&11 else echo_failed error "$(cat $log_file)" fi fi rm -rf $LOCK_DIR exit 1 } error (){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mError\033[m ] $*" else echo " [ Error ] $*" fi echo "" } warn (){ echo "" if $terminal ; then echo -e " [ \033[33m\033[1mWarning\033[m ] $*" else echo " [ Error ] $*" fi echo "" } info (){ if $terminal ; then echo "" if $terminal ; then echo -e " [ \033[32m\033[1mInfo\033[m ] $*" else echo " [ Info ] $*" fi echo "" fi } echo_ok() { if $terminal ; then echo -e "\033[85G[ \033[32mok\033[m ]" fi } echo_failed(){ if $terminal ; then echo -e "\033[85G[ \033[1;31mfailed\033[m ]" fi } echo_skipped() { if $terminal ; then echo -e "\033[85G[ \033[33m\033[1mskipped\033[m ]" fi } echo_wait(){ if $terminal ; then echo -en "\033[85G[ \033[5m\033[1m..\033[m ]" fi } trim() { local var="$*" var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters echo -n "$var" } blank_line() { if $terminal ; then echo "" fi } detect_os () { if $(which lsb_release > /dev/null 2>&1) ; then DIST="$(lsb_release -i | awk '{print tolower($3)}')" DIST_VERSION="$(lsb_release -r | awk '{print tolower($2)}')" DIST_CODENAME="$(lsb_release -c | awk '{print tolower($2)}')" if [[ "$DIST" = "debian" ]]; then if $(echo "$DIST_VERSION" | grep -q '\.') ; then DIST_VERSION=$(echo "$DIST_VERSION" | cut --delimiter='.' -f1) fi fi elif [[ -e "/etc/os-release" ]]; then . /etc/os-release DIST=$ID DIST_VERSION=${VERSION_ID} fi # remove whitespace from DIST and DIST_VERSION DIST="${DIST// /}" DIST_VERSION="${DIST_VERSION// /}" } # Funktion zur Generierung eines zufälligen Zeichens aus einer gegebenen Zeichenmenge random_char() { local chars="$1" echo -n "${chars:RANDOM%${#chars}:1}" } # Funktion zur Generierung eines zufälligen Strings mit den angegebenen Anforderungen generate_random_string() { local length="$1" # Überprüfen, ob die Länge größer als 8 ist if [[ "$length" -le 8 ]]; then echo "Fehler: Die Länge muss größer als 8 Zeichen sein." return 1 fi # Zeichenmengen local lower="abcdefghijklmnopqrstuvwxyz" local upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" local digits="0123456789" #local special="!@#$%^&*()_+-=[]{}|;:,.<>?/" local special="_+--//...." # Generiere mindestens ein Zeichen aus jeder Kategorie local random_string=$(random_char "$lower") random_string+=$(random_char "$upper") random_string+=$(random_char "$digits") random_string+=$(random_char "$special") random_string+=$(random_char "$special") # Fülle den Rest der Zeichenkette mit zufälligen Zeichen aus allen Kategorien local all_chars="$lower$upper$digits$special" for (( i=${#random_string}; i ${log_file} 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped warn "No configuration file '$conf_file' present.\n Loading default values.." fi [[ -n "${FQHN_HOSTNAME}" ]] && DEFAULT_FQHN_HOSTNAME="${FQHN_HOSTNAME}" if [[ -n "$DB_TYPE" ]] ; then if [[ "${DB_TYPE,,}" = "postgres" ]] || [[ "${DB_TYPE,,}" = "postgresql" ]] || [[ "${DB_TYPE,,}" = "pgsql" ]] || [[ "${DB_TYPE,,}" = "psql" ]] ; then DEFAULT_DB_TYPE=pgsql elif [[ "${DB_TYPE,,}" = "mysql" ]] ; then DEFAULT_DB_TYPE=mysql else fatal "Wrong or empty Database Type (DB_TYPE) - must be 'mysql' or 'pgsql'." fi fi [[ -n "${DB_NAME}" ]] && DEFAULT_DB_NAME="${DB_NAME}" [[ -n "${DB_USER}" ]] && DEFAULT_DB_NAME="${DB_USER}" [[ -n "${DB_PASS}" ]] && DEFAULT_DB_PASS="${DB_PASS}" [[ -n "${KEYCLOAK_USER}" ]] && DEFAULT_KEYCLOAK_USER="${KEYCLOAK_USER}" if [[ -n "${KEYCLOAK_GROUP}" ]]; then DEFAULT_KEYCLOAK_GROUP="${KEYCLOAK_GROUP}" else DEFAULT_KEYCLOAK_GROUP="$DEFAULT_KEYCLOAK_USER" fi [[ -n "${KEYCLOAK_BASE_INSTALL_PATH}" ]] && DEFAULT_KEYCLOAK_BASE_INSTALL_PATH="${KEYCLOAK_BASE_INSTALL_PATH}" echo -e "\033[32m--\033[m" echo "" echo "Version Number of Keycloak Server to install" echo "" echo " see: https://keycloak.org/downloads" echo "" echo "" KEYCLOAK_VERSION= while [ "X$KEYCLOAK_VERSION" = "X" ] do echononl "KEYCLOAK Server Version: " read KEYCLOAK_VERSION if [ "X$KEYCLOAK_VERSION" = "X" ]; then echo -e "\n\t\033[33m\033[1mA Version number is required!\033[m\n" fi done DOWNLOAD_ARCHIVE="keycloak-${KEYCLOAK_VERSION}.tar.gz" DOWNLOAD_URL="https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/${DOWNLOAD_ARCHIVE}" KEYCLOAK_BASE_INSTALL_PATH= echo "" echo -e "\033[32m--\033[m" echo "" echo "Specify the base directory in which keycloak is to be installed." echo "" while [[ "X${KEYCLOAK_BASE_INSTALL_PATH}" = "X" ]]; do echononl "Base directory for keycloak installation [${DEFAULT_KEYCLOAK_BASE_INSTALL_PATH}]: " read KEYCLOAK_BASE_INSTALL_PATH if [[ "X${KEYCLOAK_BASE_INSTALL_PATH}" = "X" ]]; then KEYCLOAK_BASE_INSTALL_PATH="${DEFAULT_KEYCLOAK_BASE_INSTALL_PATH}" fi if [[ ! -d "${KEYCLOAK_BASE_INSTALL_PATH}" ]] ; then echo -e "\n\tGiven directory \033[33m\033[1m${KEYCLOAK_BASE_INSTALL_PATH}\033[m does not exist!.\n" KEYCLOAK_BASE_INSTALL_PATH="" fi done KEYCLOAK_INSTALL_DIR="${KEYCLOAK_BASE_INSTALL_PATH}/keycloak-${KEYCLOAK_VERSION}" if [[ -h "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak" ]] ; then OLD_INSTALL_DIR="$(realpath "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak")" OLD_VERSION="$(basename "${OLD_INSTALL_DIR}" | sed "s/^keycloak-//")" fi echo "" echo "--" echo "" echo "Enter user and group for Keycloak Service." echo "" KEYCLOAK_USER= while [ "X${KEYCLOAK_USER}" = "X" ] do echononl "KEYCLOAK user [${DEFAULT_KEYCLOAK_USER}]: " read KEYCLOAK_USER if [ "X${KEYCLOAK_USER}" = "X" ]; then KEYCLOAK_USER=$DEFAULT_KEYCLOAK_USER fi done KEYCLOAK_GROUP= while [ "X${KEYCLOAK_GROUP}" = "X" ] do echononl "KEYCLOAK group [$DEFAULT_KEYCLOAK_GROUP]: " read KEYCLOAK_GROUP if [ "X${KEYCLOAK_GROUP}" = "X" ]; then KEYCLOAK_GROUP=$DEFAULT_KEYCLOAK_GROUP fi done DB_TYPE="" echo "" echo -e "\033[32m--\033[m" echo "" echo "Choose Database Type" echo "" if [[ "$DEFAULT_DB_TYPE" = "mysql" ]]; then echo -e "\033[3G\033[37m\033[1m[1] MySQL\033[m" else echo -e "\033[3G[1] MySQL" fi if [[ "$DEFAULT_DB_TYPE" = "pgsql" ]] ; then echo -e "\033[3G[2] \033[37m\033[1mPostgeSQL\033[m" else echo -e "\033[3G[2] PostgeSQL" fi echo "" echo "Type a number or press to choose highlighted value" echo "" echononl "Eingabe: " while [ "$DB_TYPE" != "mysql" -a "$DB_TYPE" != "pgsql" ]; do read OPTION case $OPTION in 1) DB_TYPE="mysql" ;; 2) DB_TYPE="pgsql" ;; '') DB_TYPE=$DEFAULT_DB_TYPE ;; *) echo "" echo -e "\033[3GFalsche Eingabe ! [ 1 = MySQL ; 2 = PostgreSQL ] or type " echo "" echononl "Eingabe: " ;; esac done DB_NAME= echo "" echo -e "\033[32m--\033[m" echo "" echo "Enter Database Name used by Keycloak Service" echo "" if [[ -n "$DEFAULT_DB_NAME" ]]; then while [[ "X${DB_NAME}" = "X" ]]; do echononl "Database Name [${DEFAULT_DB_NAME}]: " read DB_NAME if [[ "X${DB_NAME}" = "X" ]]; then DB_NAME=$DEFAULT_DB_NAME fi done else while [[ "X${DB_NAME}" = "X" ]]; do echononl "Database Name: " read DB_NAME if [[ "X${DB_NAME}" = "X" ]]; then echo -e "\n\t\033[33m\033[1m Database Name is reqired\033[m\n" fi done fi DB_USER= echo "" echo -e "\033[32m--\033[m" echo "" echo "Enter Database User used by Keycloak Service" echo "" if [[ -n "$DEFAULT_DB_USER" ]]; then while [[ "X${DB_USER}" = "X" ]]; do echononl "Database User [${DEFAULT_DB_USER}]: " read DB_USER if [[ "X${DB_USER}" = "X" ]]; then DB_USER=$DEFAULT_DB_USER fi done else while [[ "X${DB_USER}" = "X" ]]; do echononl "Database User: " read DB_USER if [[ "X${DB_USER}" = "X" ]]; then echo -e "\n\t\033[33m\033[1m Database User is reqired\033[m\n" fi done fi DB_PASS= echo "" echo -e "\033[32m--\033[m" echo "" echo "Enter Database Password used by Keycloak Service" echo "" if [[ -n "$DEFAULT_DB_PASS" ]]; then while [[ "X${DB_PASS}" = "X" ]]; do echononl "Database Password [${DEFAULT_DB_PASS}]: " read DB_PASS if [[ "X${DB_PASS}" = "X" ]]; then DB_PASS=$DEFAULT_DB_PASS fi done else while [[ "X${DB_PASS}" = "X" ]]; do echononl "Database Password: " read DB_PASS if [[ "X${DB_PASS}" = "X" ]]; then echo -e "\n\t\033[33m\033[1m Database Password is reqired\033[m\n" fi done fi if [[ "$DB_TYPE" = "mysql" ]] ; then [[ -n "${MYSQL_CREDENTIAL_ARGS}" ]] && DEFAULT_MYSQL_CREDENTIAL_ARGS="${MYSQL_CREDENTIAL_ARGS}" # Test database connection # if ! $(mysql ${DEFAULT_MYSQL_CREDENTIAL_ARGS} -N -s -e 'quit' > /dev/null 2>&1) ; then echo "" echo -e "\033[32m--\033[m" echo "" echo "Insert Database Credentials.." echo "" echo -e " A string containing credentials to establish a database connection. This character string can consist of username and password, but also of login information stored in the file system or the database itself. Example: \033[33m-u root -p''\033[m \033[33m--login-path=local\033[m \033[33m--login-path=mysql-5.7\033[m \033[33m--defaults-file=/usr/local/mysql/sys-maint.cnf\033[m \033[33m-u root -S /run/mysqld/mysqld.sock\033[m" echo "" echononl "Database Credentials: " read MYSQL_CREDENTIAL_ARGS while [ "X${MYSQL_CREDENTIAL_ARGS}" = "X" ] ; do echo -e "\n\t\033[33m\033[1mEingabe erforderlich.\033[m\n" echononl "Database Credentials: " read MYSQL_CREDENTIAL_ARGS done else MYSQL_CREDENTIAL_ARGS="${DEFAULT_MYSQL_CREDENTIAL_ARGS}" fi if ! $(mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e 'quit' > /dev/null 2>&1) ; then fatal "Connection to MySQL Service failed.!" fi fi FQHN_HOSTNAME= echo "" echo -e "\033[32m--\033[m" echo "" echo "Insert full qualified hostname for Keycloak Service" echo "" if [[ -n "${DEFAULT_FQHN_HOSTNAME}" ]]; then while [[ "X${FQHN_HOSTNAME}" = "X" ]]; do echononl "Full qualified hostname [${DEFAULT_FQHN_HOSTNAME}]: " read FQHN_HOSTNAME if [[ "X${FQHN_HOSTNAME}" = "X" ]]; then FQHN_HOSTNAME=$DEFAULT_FQHN_HOSTNAME fi if [[ ! ${FQHN_HOSTNAME} =~ \. ]]; then echo -e "\n\tGiven Host \033[33m\033[1m${FQHN_HOSTNAME}\033[m seems not to be a full qualified hostname.\n" FQHN_HOSTNAME="" fi done else while [[ "X${FQHN_HOSTNAME}" = "X" ]]; do echononl "Full qualified hostname: " read FQHN_HOSTNAME if [[ "X${FQHN_HOSTNAME}" = "X" ]]; then echo -e "\n\t\033[33m\033[1mFull qualified hostname is reqired\033[m\n" fi if [[ ! ${FQHN_HOSTNAME} =~ \. ]]; then echo -e "\n\tGiven Host \033[33m\033[1m${FQHN_HOSTNAME}\033[m seems not to be a full qualified hostname.\n" FQHN_HOSTNAME="" fi done fi HOSTNAME="${FQHN_HOSTNAME%%.*}" echo "" echo "" echo -e "\t\033[32mStart install script for Keycloak Service with the following parameters\033[m" echo "" echo -e "\t(New) Keycloak Server Version...: \033[33m\033[1m${KEYCLOAK_VERSION}\033[m" echo "" if [[ -n "${OLD_VERSION}" ]] ; then echo -e "\tCurrent (old) Keycloak Version..: ${OLD_VERSION}" else echo -e "\tCurrent (old) Keycloak Version..: \033[33mkeycloak is currently NOT installed\033[m" fi echo "" echo -e "\tFull qualified Hostname.........: ${FQHN_HOSTNAME}" echo -e "\tHostname........................: ${HOSTNAME}" echo "" echo -e "\tKeycloak user...................: ${KEYCLOAK_USER}" echo -e "\tKeycloak group..................: ${KEYCLOAK_GROUP}" echo "" echo -e "\tKeycloak base install dir.......: ${KEYCLOAK_BASE_INSTALL_PATH}" echo -e "\tKeycloak install dir............: ${KEYCLOAK_INSTALL_DIR}" echo "" echo -e "\tDownload archive................: ${DOWNLOAD_ARCHIVE}" echo -e "\tDownload URL....................: ${DOWNLOAD_URL}" echo "" if [[ "${DB_TYPE}" = "pgsql" ]] ; then echo -e "\tDatabase Type...................: PostgreSQL" else echo -e "\tDatabase Type...................: MySQL" fi echo "" if [[ "${DB_TYPE}" = "mysql" ]]; then echo -e "\tMYSQL_CREDENTIAL_ARGS...........: ${MYSQL_CREDENTIAL_ARGS}" echo "" fi echo -e "\tDatabase Name...................: ${DB_NAME}" echo -e "\tDatabase User...................: ${DB_USER}" echo -e "\tDatabase Password...............: ${DB_PASS}" echo "" echononl "einverstanden (yes/no): " read OK OK=${OK,,} while [ "X$OK" != "Xyes" -a "X$OK" != "Xno" ]; do echononl "Wrong entry! [yes/no]: " read OK OK=${OK,,} done [ $OK = "yes" ] || fatal Repeat with other settings.. cat < $conf_file #-------------------------------------- # Settings for Keycloak Install scripts #-------------------------------------- # FQHN_HOSTNAME # # The full qualified histname under which bbb service # is available # # Defaults to full qualified hostname of the system # FQHN_HOSTNAME="${FQHN_HOSTNAME}" # KEYCLOAK_USER # # The user under which Keycloak service is running. # # Defaults to: KEYCLOAK_USER="keycloak" # #KEYCLOAK_USER="" KEYCLOAK_USER="${KEYCLOAK_USER}" # KEYCLOAK_GROUP # # The group of the keycloak user. # # #KEYCLOAK_GROUP="" KEYCLOAK_GROUP="${KEYCLOAK_GROUP}" # KEYCLOAK_BASE_INSTALL_PATH # # Base directora in which the keycloak installation lives. # # Defaults to: KEYCLOAK_BASE_INSTALL_PATH="/opt" # #KEYCLOAK_BASE_INSTALL_PATH="/opt" KEYCLOAK_BASE_INSTALL_PATH="${KEYCLOAK_BASE_INSTALL_PATH}" # DB_TYPE # # Type of Keycloak database # # Possible values are 'pgsql' (PostgeSQL) or 'mysql' (MySQL) # # Defaults to POSTFIX_DB_TYPE="pgsql" # # DB_TYPE="pgsql" DB_TYPE="${DB_TYPE}" # MYSQL_CREDENTIAL_ARGS # # Giving password on command line is insecure an sind mysql 5.5 # you will get a warning doing so. # # Reading username/password fro file ist also possible, using MySQL/MariaDB # commandline parameter '--defaults-file'. # # Since Version 5.6, that method is considered as insecure. # To avoid giving the password on command line, we use an # encrypted option file # # Create (encrypted) option file: # $ mysql_config_editor set --login-path=local --socket=/var/run/mysqld/mysqld.sock --user=backup --password # $ Password: # # Use of option file: # $ mysql --login-path=local ... # # Example # MYSQL_CREDENTIAL_ARGS="--login-path=local" # MYSQL_CREDENTIAL_ARGS="--defaults-file=/etc/mysql/debian.cnf" (Debian default) # MYSQL_CREDENTIAL_ARGS="--defaults-file=/usr/local/mysql/sys-maint.cnf" # # # MariaDB 10.4.x # MYSQL_CREDENTIAL_ARGS="-u root -S /tmp/mysql.sock" # # Defaults to MYSQL_CREDENTIAL_ARGS="-u root -S /tmp/mysql.sock" # #MYSQL_CREDENTIAL_ARGS="--login-path=local" EOF if [[ "${DB_TYPE}" = "mysql" ]]; then cat <> ${conf_file} MYSQL_CREDENTIAL_ARGS="${MYSQL_CREDENTIAL_ARGS}" EOF fi cat <> ${conf_file} # DB_NAME # # Database Name of Mattemost's Database # # Defaults to: DB_NAME="keycloak" # #DB_NAME="keycloak" DB_NAME="${DB_NAME}" # DB_USER # # Database USER of Mattemost's Database # # Defaults to: DB_USER="keycloak" # #DB_USER="keycloak" DB_USER="${DB_USER}" # DB_PASS # # Database Password used for Mattemost's Database # # Defaults to a random created one. # #DB_PASS="" DB_PASS="${DB_PASS}" EOF echo echo -e "\033[37m\033[1mSome checks....\033[m" echo _failed=false echononl "Check if Nginx Webservice is installed.." if $(dpkg -s nginx-extras > "$log_file" 2>&1) ; then nginx_installed=true elif $(dpkg -s nginx-full > "$log_file" 2>&1) ; then nginx_installed=true else nginx_installed=false fi if $nginx_installed ; then echo -e "\033[85G[ \033[32mYES\033[m ]" else echo -e "\033[85G[ \033[1;31mNOT installed\033[m ]" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" blank_line fi _failed=false echononl "Check if OpenJDK is installed.." if $(dpkg -s default-jdk > "$log_file" 2>&1) ; then java_jdk_installed=true elif $(dpkg -s default-jre > "$log_file" 2>&1) ; then java_installed=true else java_installed=false fi if $java_installed ; then echo -e "\033[85G[ \033[32mYES\033[m ]" else echo -e "\033[85G[ \033[1;31mNOT installed\033[m ]" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" blank_line fi _failed=false if [[ "${DB_TYPE}" = "mysql" ]]; then echononl "Check if MySQL Database Service is installed.." if $(dpkg -s mysql-server > "$log_file" 2>&1) ; then database_service_installed=true else database_service_installed=false fi if ${database_service_installed} ; then echo -e "\033[85G[ \033[32mYES\033[m ]" else echo -e "\033[85G[ \033[1;31mNOT installed\033[m ]" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" blank_line fi else echononl "Check if PostgreSQL Database Service is installed.." if $(dpkg -s postgresql > "$log_file" 2>&1) ; then database_service_installed=true else database_service_installed=false fi if ${database_service_installed} ; then echo -e "\033[85G[ \033[32mYES\033[m ]" else echo -e "\033[85G[ \033[1;31mNOT installed\033[m ]" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" blank_line fi fi _failed=false echononl "Check if certificate for '${FQHN_HOSTNAME}' is present.." if [[ -d "/var/lib/dehydrated/certs/${FQHN_HOSTNAME}" ]] ; then if [[ -h "/var/lib/dehydrated/certs/${FQHN_HOSTNAME}/fullchain.pem" ]]; then cert_present=true else cert_present=false fi else cert_present=false fi if $cert_present ; then echo -e "\033[85G[ \033[32mYES\033[m ]" else echo -e "\033[85G[ \033[1;31mNOT present\033[m ]" fi if ! ${nginx_installed} || ! ${database_service_installed} || ! ${java_installed} ; then fatal "Prerequisites are a correct installation of the NGINX Web Service as well as a correct installation of the ${DB_TYPE} database service. Also Java is needed (recommended: OpenJDK 17 or 21) It's also highly recommended to have a valid certificate for your FQHN Hostname '${FQHN_HOSTNAME}'." elif ! ${cert_present} ; then warn "It is highly recommended to have a valid certificate for your FQHN Hostname '${FQHN_HOSTNAME}'." echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" fi echo echo -e "\033[37m\033[1mSome pre-installation stuff..\033[m" echo cron_root_is_empty=false echononl "Backup crontab.." if [[ $(crontab -u root -l 2> /dev/null | wc -c) -gt 0 ]] ; then crontab -u root -l > ${crontab_backup_file} 2> $log_file if [[ "$?" = "0" ]]; then echo_ok else echo_failed error "$(cat $log_file)" fi else cron_root_is_empty=true echo_skipped fi echononl "Disable crontab for user root" if ! ${cron_root_is_empty} ; then crontab -r -u root > ${log_file} 2>&1 if [[ "$?" = "0" ]]; then echo_ok else echo_failed error "$(cat $log_file)" fi else echo_skipped fi blank_line echononl "Stop Keycloak Service.." if $(systemctl is-active --quiet service keycloak.service) ; then systemctl stop keycloak.service > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi blank_line if [[ "${DB_TYPE}" = "mysql" ]] ; then #echononl "Check if Database '${DB_NAME}' already exists.." #if $(mysql ${MYSQL_CREDENTIAL_ARGS} -e "use ${DB_NAME}" 2> /dev/null) ; then # database_exists=true #else # database_exists=false #fi echononl "Create MySQL Database User '${DB_USER}' with Password '${DB_PASS}'.." if [[ "$(mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e \ "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '${DB_USER}')" 2>/dev/null)" = 1 ]]; then echo_skipped else mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e \ "CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}'" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi echononl "Create MySQL Database '${DB_NAME}'.." if [[ "$(mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e \ "SHOW DATABASES LIKE '${DB_NAME}'" 2>/dev/null)" = "${DB_NAME}" ]]; then echo_skipped else mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e "CREATE DATABASE ${DB_NAME}" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi echononl "Grant access privileges to the user '${DB_USER}'’." mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e \ "GRANT ALL PRIVILEGES ON ${DB_NAME}.* to '${DB_USER}'@'localhost';" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echononl "FLUSH PRIVILEGES to dadabase engine .." mysql ${MYSQL_CREDENTIAL_ARGS} -N -s -e \ "FLUSH PRIVILEGES" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else # Check if PostgreSQL database '$DB_NAME' exists .. # count=$(su - postgres -c "psql -q -A -t -l" | grep -c -e "^$DB_NAME") if [[ $count -eq 0 ]];then database_exists=false else database_exists=true fi # sudo -u postgres psql -c "CREATE DATABASE ${DB_NAME};" > $log_file 2>&1 # sudo -u postgres psql -c "CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASS}';" > $log_file 2>&1 # sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} to ${DB_USER};" > $log_file 2>&1 # sudo -u postgres psql -c "ALTER DATABASE ${DB_NAME} OWNER TO ${DB_USER};" > $log_file 2>&1 # sudo -u postgres psql -c "GRANT USAGE, CREATE ON SCHEMA PUBLIC TO ${DB_USER};" > $log_file 2>&1 echononl "Create PostgreSQL database '${DB_NAME}'.." if ${database_exists} ; then echo_skipped echononl "Backup existing database '${DB_NAME}'" sudo -u postgres pg_dump -U postgres -d ${DB_NAME} \ -f /tmp/${DB_NAME}-${OLD_VERSION}-${backup_date}.sql > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi echononl "Move database backup file to folder '${KEYCLOAK_BASE_INSTALL_PATH}'.." mv "/tmp/${DB_NAME}-${OLD_VERSION}-${backup_date}.sql" "${KEYCLOAK_BASE_INSTALL_PATH}" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi echononl "Empty Database '${DB_NAME}'" # Get a list of all tables in the database # db_tables=$(sudo -u postgres psql -U postgres -d ${DB_NAME} -t \ -c "SELECT tablename FROM pg_tables WHERE schemaname = 'public';") > $log_file 2>&1 # Delete each table # : > $log_file _failed=false error_message="Errors deleting tables from database ${DB_NAME}:" for _table in ${db_tables} ; do sudo -u postgres psql -U postgres -d ${DB_NAME} -c "DROP TABLE IF EXISTS $_table CASCADE;" >> $log_file 2>&1 if [[ $? -ne 0 ]] ; then error_message+="\n Unable to remove table ${_table} from database ${DB_NAME}" _failed=true fi done if ${_failed} ; then echo_failed error "$(echo -e "${error_message}"i)" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi # Also delete all sequences, if available # : > $log_file _failed=false error_message="Errors deleting sequences from database ${DB_NAME}:" db_sequences=$(sudo -u postgres psql -U postgres -d ${DB_NAME} -t \ -c "SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = 'public';") > $log_file 2>&1 for _sequence in ${db_sequences}; do sudo -u postgres psql -U postgres -d ${DB_NAME} \ -c "DROP SEQUENCE IF EXISTS ${_sequence} CASCADE;" >> $log_file 2>&1 if [[ $? -ne 0 ]] ; then error_message+="\n Unable to remove sequence ${_sequence} from database ${DB_NAME}" _failed=true fi done else sudo -u postgres psql -c "CREATE DATABASE ${DB_NAME};" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi fi declare -i _response _response="$(sudo -u postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'" 2>/dev/null)" echononl "Create PostgreSQL database user ${DB_USER}.." if [[ ${_response} -eq 1 ]]; then echo_skipped echononl "Reset the Password for database user '${DB_USER}'.." sudo -u postgres psql -c "ALTER USER ${DB_USER} WITH PASSWORD '${DB_PASS}';" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi else sudo -u postgres psql -c "CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASS}';" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi fi echononl "Grant the user access to the Keycloak database.." sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} to ${DB_USER};" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi echononl "Change the owner of database '${DB_NAME}' to '${DB_USER}'.." sudo -u postgres psql -c "ALTER DATABASE ${DB_NAME} OWNER TO ${DB_USER};" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi echononl "Grant access to objects contained in the specified schema.." sudo -u postgres psql -c "GRANT USAGE, CREATE ON SCHEMA PUBLIC TO ${DB_USER};" > $log_file 2>&1 if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" echo "" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi fi blank_line echononl "Create the Keycloak (system) group.." if cat /etc/group | grep -e "^${KEYCLOAK_GROUP}:" > /dev/null 2>&1 ; then echo_skipped else groupadd -r ${KEYCLOAK_GROUP} > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi echononl "Create the Keycloak (system) user.." if id -u ${KEYCLOAK_USER} > /dev/null 2>&1; then echo_skipped else useradd -r -M -d /opt/Keycloak -s /bin/false -g ${KEYCLOAK_GROUP} ${KEYCLOAK_USER} > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi blank_line echononl "Download the latest version (${KEYCLOAK_VERSION}) of the Keycloak Server.." if [[ ! -f "${working_dir}/${DOWNLOAD_ARCHIVE}" ]]; then wget -O "${working_dir}/${DOWNLOAD_ARCHIVE}" "${DOWNLOAD_URL}" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi echo echo -e "\033[37m\033[1mInstalling Keycloak Service..\033[m" echo echononl "Backup Keycloak Installation directory.." if [[ -n "${OLD_INSTALL_DIR}" ]]; then mv "${OLD_INSTALL_DIR}" "${OLD_INSTALL_DIR}.${backup_date}" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi echononl "Remove Symlink '${KEYCLOAK_BASE_INSTALL_PATH}/keycloak' .." if [[ -h "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak" ]] ; then rm "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi blank_line echononl "Extract the Keycloak Service files.." tar -C "${KEYCLOAK_BASE_INSTALL_PATH}" -xvzf "${working_dir}/${DOWNLOAD_ARCHIVE}" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line echononl "Symlink keycloak -> keycloak-${KEYCLOAK_VERSION} .." ln -s "keycloak-${KEYCLOAK_VERSION}" "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echononl "Backup original configuration file.." mv "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/conf/keycloak.conf" \ "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/conf/keycloak.conf.ORIG" if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echononl "Create new configuration .." if [[ "${DB_TYPE}" = "pgsql" ]]; then _db_type="postgres" _db_url="jdbc:postgresql://localhost/${DB_NAME}" else _db_type="mysql" _db_url="jdbc:mysql://localhost/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8" fi cat < "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/conf/keycloak.conf" 2> "$log_file" # --------------------------------------------- # Configuration for KEYCLOAK Service # located: /opt/keycloak/conf/keycloak.conf # --------------------------------------------- # Database db=${_db_type} db-url=${_db_url} db-username=${DB_USER} db-password=${DB_PASS} # Hostname v2 hostname=${FQHN_HOSTNAME} hostname-strict=true # HTTP(S) http-enabled=true http-host=127.0.0.1 http-port=8080 EOF if ${_certs_installed} ; then cat <> "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/conf/keycloak.conf" 2> "$log_file" # HTTPS aktivieren #https-port=8443 #https-certificate-file=/opt/keycloak/certs/${FQHN_HOSTNAME}.crt #https-certificate-key-file=/opt/keycloak/certs/${FQHN_HOSTNAME}.key EOF else cat <> "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/conf/keycloak.conf" 2> "$log_file" # HTTPS aktivieren #https-port=8443 #https-certificate-file=/opt/keycloak/certs/${FQHN_HOSTNAME}.crt #https-certificate-key-file=/opt/keycloak/certs/${FQHN_HOSTNAME}.key EOF fi cat <> "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/conf/keycloak.conf" 2> "$log_file" # Proxy proxy-headers=xforwarded # Admin CLI aktivieren #admin-cli-enabled=true EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echo echo -e "\033[37m\033[1mSetup Keycloak to use systemd for starting and stopping..\033[m" echo echononl "Create a systemd unit file.." if [[ "${DB_TYPE}" = "pgsql" ]]; then cat < /etc/systemd/system/keycloak.service 2>"$log_file" [Unit] Description=Keycloak Server After=network.target postgresql.service Requires=postgresql.service [Service] User=${KEYCLOAK_USER} Group=${KEYCLOAK_GROUP} ExecStart=${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/bin/kc.sh start --optimized #Environment="JAVA_OPTS=-Xms512m -Xmx1024m" Restart=always LimitNOFILE=102400 [Install] WantedBy=multi-user.target EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else cat < /etc/systemd/system/keycloak.service 2>"$log_file" [Unit] Description=Keycloak Server After=network.target postgresql.service Requires=postgresql.service [Service] User=${KEYCLOAK_USER} Group=${KEYCLOAK_GROUP} ExecStart=${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/bin/kc.sh start --optimized Environment="JAVA_OPTS=-Xms512m -Xmx1024m" Restart=always LimitNOFILE=102400 [Install] WantedBy=multi-user.target EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi echononl "Make systemd load the new unit.." systemctl daemon-reload > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echononl "Set Keycloak Service to start on machine start up.." systemctl enable keycloak.service > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line _certs_installed=false echononl "Run script 'check_cert_for_keycloak.sh'.." if [[ -x "/root/bin/monitoring/check_cert_for_keycloak.sh" ]] ; then /root/bin/monitoring/check_cert_for_keycloak.sh > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed cat "$log_file" else echo_ok _certs_installed=true fi else warn "Certificate/Key for ${FQHN_HOSTNAME} cannot be provided." fi echononl "Add a cronjob for checking cert.." if [[ -f "$crontab_backup_file" ]]; then if ! grep -iq -E "/root/bin/monitoring/check_cert_for_keycloak.sh" "$crontab_backup_file" > /dev/null 2>&1; then cat <> $crontab_backup_file # Check if cert for Keycloak service is up-to-date # 51 05 * * * /root/bin/monitoring/check_cert_for_keycloak.sh EOF if [[ "$?" -ne 0 ]] ; then echo_failed else echo_ok fi else echo_skipped fi elif [[ -f "/var/spool/cron/crontabs/root" ]] ; then if ! grep -i -E "/root/bin/monitoring/check_cert_for_keycloak.sh" /var/spool/cron/crontabs/root > /dev/null 2>&1; then installation_failed=false crontab -l > /tmp/tmp_crontab 2> $log_file if [[ "$?" -ne 0 ]] ; then installation_failed=true fi cat << EOF >> /tmp/tmp_crontab 2>> $log_file # Check if cert for Keycloak service is up-to-date # 51 05 * * * /root/bin/monitoring/check_cert_for_keycloak.sh EOF if [[ "$?" -ne 0 ]] ; then installation_failed=true fi crontab /tmp/tmp_crontab > /dev/null 2>> $log_file if [[ "$?" -ne 0 ]] ; then installation_failed=true fi rm /tmp/tmp_crontab > /dev/null 2>> $log_file if [[ "$?" -ne 0 ]] ; then installation_failed=true fi if ! $installation_failed ; then echo_ok else echo_failed error "Adding cronjob for checking cert failed!" fi else echo_skipped fi fi blank_line echononl "Genereate temporary admin user.." export ADMIN_PASS="$(generate_random_string "16")" /opt/keycloak/bin/kc.sh bootstrap-admin \ user --username temp-admin \ --password:env ADMIN_PASS \ --no-prompt > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line echononl "Creates a new and optimized server image.." ${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/bin/kc.sh build > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" echononl "\033[1mcontinue anyway\033[m [yes/no]: " read OK while [[ "${OK,,}" != "yes" ]] && [[ "${OK,,}" != "no" ]] ; do echononl "Wrong entry! - repeat [yes/nno]: " read OK done [[ $OK = "yes" ]] || fatal "Abbruch durch User" else echo_ok fi blank_line echononl "Set ownbership of installation directory '${KEYCLOAK_INSTALL_DIR}'.." chown -R ${KEYCLOAK_USER}:${KEYCLOAK_GROUP} "${KEYCLOAK_INSTALL_DIR}" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi #echononl "Give write permissions to the keycloak group.." #chmod -R g+w "${KEYCLOAK_INSTALL_DIR}" > "$log_file" 2>&1 #if [[ $? -ne 0 ]]; then # echo_failed # error "$(cat "$log_file")" #else # echo_ok #fi blank_line echononl "Start Keycloak Service" systemctl start keycloak.service > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echo "" echo -e "\033[37m\033[1mConfiguring NGINX with SSL and HTTP/2..\033[m" echo "" echononl "Backup existing NGINX configuration.." if [[ -f "/etc/nginx/sites-available/${FQHN_HOSTNAME}.conf" ]] ; then cp -a "/etc/nginx/sites-available/${FQHN_HOSTNAME}.conf" \ "/etc/nginx/sites-available/${FQHN_HOSTNAME}.conf.${backup_date}" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi echononl "NGINX virtual host configuration for '${FQHN_HOSTNAME}'.." cat < "/etc/nginx/sites-available/${FQHN_HOSTNAME}.conf" 2> "$log_file" # -- ${FQHN_HOSTNAME} -- upstream kc_backend { server 127.0.0.1:8443; keepalive 32; } server { listen 80; listen [::]:80; server_name ${FQHN_HOSTNAME}; return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ${FQHN_HOSTNAME}; # Include location directive for Let's Encrypt ACME Challenge # # Needed for (automated) updating certificate # include snippets/letsencrypt-acme-challenge.conf; ssl_certificate /var/lib/dehydrated/certs/${FQHN_HOSTNAME}/fullchain.pem; ssl_certificate_key /var/lib/dehydrated/certs/${FQHN_HOSTNAME}/privkey.pem; ssl_trusted_certificate /var/lib/dehydrated/certs/${FQHN_HOSTNAME}/chain.pem; # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits # # To generate a dhparam.pem file, run in a terminal # openssl dhparam -dsaparam -out /etc/nginx/ssl/dhparam.pem 2048 # ssl_dhparam /etc/nginx/ssl/dhparam.pem; # Enable TLS versions (TLSv1.3 is required upcoming HTTP/3 QUIC). ssl_protocols TLSv1.2 TLSv1.3; # Enable TLSv1.3's 0-RTT. Use \$ssl_early_data when reverse proxying to # prevent replay attacks. # # @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data ssl_early_data on; # ECDHE better than DHE (faster) ECDHE & DHE GCM better than CBC (attacks on AES) # Everything better than SHA1 (deprecated) # ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; ssl_prefer_server_ciphers on; # Eable session resumption to improve https performance ssl_session_cache shared:SSL:50m; ssl_session_timeout 10m; ssl_session_tickets off; # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) # add_header Strict-Transport-Security max-age=15768000; # OCSP Stapling --- # fetch OCSP records from URL in ssl_certificate and cache them ssl_stapling on; ssl_stapling_verify on; #add_header X-Early-Data \$tls1_3_early_data; location / { proxy_pass http://localhost:8080; #proxy_pass https://localhost:8443; #proxy_pass https://kc_backend; 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 \$server_name; proxy_set_header X-Forwarded-Proto https; #proxy_set_header X-Forwarded-Proto \$scheme; } } EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echononl "Enable created configuration.." if [[ ! -h "/etc/nginx/sites-enabled/${FQHN_HOSTNAME}.conf" ]]; then ln -s "../sites-available/${FQHN_HOSTNAME}.conf" \ "/etc/nginx/sites-enabled/${FQHN_HOSTNAME}.conf" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi echononl "Restart NGINX Service.." systemctl restart nginx > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echo echo -e "\033[37m\033[1mSome post-installation stuff..\033[m" echo _cron_reenabled=false echononl "Reenable previously saved crontab from '$(basename "${crontab_backup_file}")'.." if [[ -f "${crontab_backup_file}" ]] ; then crontab ${crontab_backup_file} > $log_file 2>&1 if [[ $? -eq 0 ]]; then echo_ok _cron_reenabled=true else echo_failed error "$(cat $log_file)" fi else echo_skipped fi blank_line echononl "Wait until the Keycloak service has started completely." declare -i index=0 declare -i _max_secs_waiting=20 keycloak_service_started=false while true ; do # Try to establish a connection to localhost:8080 # if $(curl -s -o /dev/null -I http://localhost:8080) ; then echo_ok keycloak_service_started=true break fi if [[ ${index} -gt ${_max_secs_waiting} ]]; then echo_failed error "Could not connect to loacalhost on port 8080 after about 20 seconds!" break fi (( index++ )) sleep 1 done echononl "Save configuration to file 'current-configuration.txt'." ${KEYCLOAK_BASE_INSTALL_PATH}/keycloak/bin/kc.sh show-config > "${working_dir}/current-configuration.txt" 2> "$log_file" if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line _admin_user_created=true echononl "Login as temporary admin user .." if ${keycloak_service_started} ; then export KC_CLI_PASSWORD=${ADMIN_PASS} /opt/keycloak/bin/kcadm.sh config credentials \ --server http://localhost:8080 \ --realm master \ --user temp-admin > "$log_file" 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed _admin_user_created=false error "$(cat $log_file)" fi else echo_skipped fi echononl "Create permanent user 'admin'.." if ${_admin_user_created} ; then /opt/keycloak/bin/kcadm.sh create users \ -r master \ -s username=admin \ -s enabled=true \ -o --fields id,username > "$log_file" 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed _admin_user_created=false error "$(cat $log_file)" fi else echo_skipped fi echononl "Set password for user 'admin'.." if ${_admin_user_created} ; then NEW_ADMIN_PASS="$(generate_random_string "16")" /opt/keycloak/bin/kcadm.sh set-password --username admin --new-password ${NEW_ADMIN_PASS} if [[ $? -eq 0 ]]; then echo_ok else echo_failed _admin_user_created=false error "$(cat $log_file)" fi else echo_skipped fi roles="admin create-realm uma_authorization offline_access" for _role in ${roles} ; do echononl "Add Role '${_role}' to user 'admin'.." if ${_admin_user_created} ; then if ${keycloak_service_started} ; then /opt/keycloak/bin/kcadm.sh add-roles --uusername admin --rolename ${_role} if [[ $? -eq 0 ]]; then echo_ok else echo_failed _admin_user_created=false error "$(cat $log_file)" fi else echo_skipped fi else echo_skipped fi done blank_line echononl "Remove previously saved crontab file '$(basename "${crontab_backup_file}")'.." if ${_cron_reenabled} ; then rm "${crontab_backup_file}" > $log_file 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed error "$(cat $log_file)" fi else echo_skipped fi blank_line echononl "Save credentials for 'temp-admin' into file 'temporary-login-credentials.txt'.." cat < "${working_dir}/login-credentials-temp-admin.txt" 2> "$log_file" Login into new Keycloak Service: URL: https://${FQHN_HOSTNAME} USER: temp-admin PASSSWORD: ${ADMIN_PASS} EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi info "Login into new Keycloak Service as temporary admin user: URL: https://${FQHN_HOSTNAME} USER: temp-admin PASSSWORD: ${ADMIN_PASS} see also: ${working_dir}/login-credentials-temp-admin.txt " if ${_admin_user_created} ; then echononl "Save credentials for permanent admin into file 'login-credentials-admin.txt'.." cat < "${working_dir}/login-credentials-admin.txt" 2> "$log_file" Login into new Keycloak Service: URL: https://${FQHN_HOSTNAME} USER: admin PASSSWORD: ${NEW_ADMIN_PASS} EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok info "Login into new Keycloak Service as permanent admin user: URL: https://${FQHN_HOSTNAME} USER: admin PASSSWORD: ${NEW_ADMIN_PASS} see also: ${working_dir}/login-credentials-admin.txt " fi else rm -r "${working_dir}/login-credentials-admin.txt" > /dev/null 2>&1 fi clean_up 0