You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, i adatped you script guac-install for Almalinux 8.4 and it works, i'm not able to use git,
`#!/bin/env bash
#Script to install guacamole RDP html5 gateway into Almalinux 8.4
#The script is working in progress is not all my work, i adapted a existent script to my distro
PRE-RUN CHECKS
if ! [ $(id -u) = 0 ]; then echo "This script must be run as sudo or root, try again..."; exit 1; fi
if ! [ $(getenforce) = "Enforcing" ]; then echo "This script requires SELinux to be active and in "Enforcing mode""; exit 1; fi
if ! [ $(uname -m) = "x86_64" ]; then echo "This script will only run on 64 bit versions of RHEL/CentOS"; exit 1; fi
Check that firewalld is installed
if ! rpm -q --quiet "firewalld"; then echo "This script requires firewalld to be installed on the system"; exit 1; fi
SCRIPT_BUILD="2021_07_03" # Scripts Date for last modified as "yyyy_mm_dd"
ADM_POC="Local Admin, [email protected]" # Point of contact for the Guac server admin
Versions
GUAC_STBL_VER="1.3.0" # Latest stable version of Guac from https://guacamole.apache.org/releases/
MYSQL_CON_VER="8.0.25" # Working stable release of MySQL Connecter J
MAVEN_VER="3.8.1" # Latest stable version of Apache Maven
TOMCAT_VER="tomcat9" # Tomcat Version
MYSQL_PASSWD_DEF="guacamole" # Default MySQL/MariaDB root password
DB_NAME_DEF="guac_db" # Defualt database name
DB_USER_DEF="guac_adm" # Defualt database user name
DB_PASSWD_DEF="guacamole" # Defualt database password
JKS_GUAC_PASSWD_DEF="guacamole" # Default Java Keystore password
JKS_CACERT_PASSWD_DEF="guacamole" # Default CACert Java Keystore password, used with LDAPS
Misc
GUACD_USER="guacd" # The user name and group of the user running the guacd service
GUAC_URIPATH_DEF="/" # Default URI for Guacamole
DOMAIN_NAME_DEF="localhost" # Default domain name of server
H_ERR=false # Defualt value of if an error has been triggered, should be false
LIBJPEG_EXCLUDE="exclude=libjpeg-turbo-[0-9],libjpeg-turbo-..9[0-9]-"
DEL_TMP_VAR=true # Default behavior to delete the temp var file used by error handler on completion. Set to false to keep the file to review last values
NAME_SERVERS_DEF="1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001" # OCSP resolver DNS name servers defaults !!Only used if the host does not have name servers in resolv.conf!!
LIB_DIR="/var/lib/guacamole/"
GUAC_CONF="guacamole.properties" # Guacamole configuration/properties file
MYSQL_CON="mysql-connector-java-${MYSQL_CON_VER}"
TMP_VAR_FILE="guac_tmp_vars" # Temp file name used to store varaibles for the error handler
Set full path/file name of file used to stored temp variables used by the error handler
VAR_FILE="${PWD}/${TMP_VAR_FILE}"
echo "-1" > "${VAR_FILE}" # create file with -1 to set not as background process
Determine if OS is RHEL, CentOS or something else
if grep -q "CentOS" /etc/redhat-release; then
OS_NAME="CentOS"
elif grep -q "Red Hat Enterprise" /etc/redhat-release; then
OS_NAME="RHEL"
elif grep -q "AlmaLinux release 8.4" /etc/redhat-release; then
OS_NAME="CentOS"
else
echo "Unable to verify OS from /etc/redhat-release as CentOS or RHEL, this script is intended only for those distro's, exiting."
exit 1
fi
OS_NAME_L="$(echo $OS_NAME | tr '[:upper:]' '[:lower:]')" # Set lower case rhel or centos for use in some URLs
Outputs the major.minor.release number of the OS, Ex: 7.6.1810 and splits the 3 parts.
MAJOR_VER=cat /etc/redhat-release | grep -oP "[0-9]+" | sed -n 1p # Return the leftmost digit representing major version
MINOR_VER=cat /etc/redhat-release | grep -oP "[0-9]+" | sed -n 2p # Returns the middle digit representing minor version
Placeholder in case this info is ever needed. RHEL does not have release number, only major.minor
RELEASE_VER=cat /etc/redhat-release | grep -oP "[0-9]+" | sed -n 3p # Returns the rightmost digits representing release number
#Set arch used in some paths
MACHINE_ARCH=uname -m
ARCH="64"
while true; do
echo -n "${Green} Pick the desired source to install from (enter 'stable' or 'git', default is 'stable'): ${Yellow}"
read GUAC_SOURCE
case $GUAC_SOURCE in
[Ss]table|"" ) GUAC_SOURCE="Stable"; break;;
[Gg][Ii][Tt] ) GUAC_SOURCE="Git"; break;;
* ) echo "${Green} Please enter 'stable' or 'git' to select source/version (without quotes)";;
esac
done
tput sgr0
}
START EXECUTION
init_vars
src_menu
src_vars
MENU HEADERS
Called by each menu and summary menu to display the dynamic header
db_menu () {
SUB_MENU_TITLE="Database and JKS Menu"
menu_header
echo -n "${Green} Enter the Guacamole DB name (default ${DB_NAME_DEF}): ${Yellow}"
read DB_NAME
DB_NAME=${DB_NAME:-${DB_NAME_DEF}}
echo -n "${Green} Enter the Guacamole DB username (default ${DB_USER_DEF}): ${Yellow}"
read DB_USER
DB_USER=${DB_USER:-${DB_USER_DEF}}
echo -n "${Green} Enter the Java KeyStore key-size to use (default ${JKSTORE_KEY_SIZE_DEF}): ${Yellow}"
read JKSTORE_KEY_SIZE
JKSTORE_KEY_SIZE=${JKSTORE_KEY_SIZE:-${JKSTORE_KEY_SIZE_DEF}}
}
PASSWORDS MENU
pw_menu () {
SUB_MENU_TITLE="Passwords Menu"
menu_header
echo -n "${Green} Enter the root password for MariaDB: ${Yellow}"
read MYSQL_PASSWD
MYSQL_PASSWD=${MYSQL_PASSWD:-${MYSQL_PASSWD_DEF}}
echo -n "${Green} Enter the Guacamole DB password: ${Yellow}"
read DB_PASSWD
DB_PASSWD=${DB_PASSWD:-${DB_PASSWD_DEF}}
echo -n "${Green} Enter the Guacamole Java KeyStore password, must be 6 or more characters: ${Yellow}"
read JKS_GUAC_PASSWD
JKS_GUAC_PASSWD=${JKS_GUAC_PASSWD:-${JKS_GUAC_PASSWD_DEF}}
}
SSL CERTIFICATE TYPE MENU
ssl_cert_type_menu () {
SUB_MENU_TITLE="SSL Certificate Type Menu"
menu_header
echo "${Green} What kind of SSL certificate should be used (default 2)?${Yellow}"
PS3="${Green} Enter the number of the desired SSL certificate type: ${Yellow}"
options=("LetsEncrypt" "Self-signed" "None")
select opt in "${options[@]}"
do
case $opt in
"LetsEncrypt") SSL_CERT_TYPE="LetsEncrypt"; le_menu; break;;
"Self-signed"|"") SSL_CERT_TYPE="Self-signed"; ss_menu; break;;
"None")
SSL_CERT_TYPE="None"
OCSP_USE=false
echo -e "\n\n${Red} No SSL certificate selected. This can be configured manually at a later time."
sleep 3
break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing your desired cert type.";;
esac
done
}
LETSENCRYPT MENU
le_menu () {
SUB_MENU_TITLE="LetsEncrypt Menu"
menu_header
echo -n "${Green} Enter a valid e-mail for let's encrypt certificate: ${Yellow}"
read EMAIL_NAME
echo -n "${Green} Enter the Let's Encrypt key-size to use (default ${LE_KEY_SIZE_DEF}): ${Yellow}"
read LE_KEY_SIZE
LE_KEY_SIZE=${LE_KEY_SIZE:-${LE_KEY_SIZE_DEF}}
while true; do
echo -n "${Green} Use OCSP Stapling (default yes): ${Yellow}"
read yn
case $yn in
[Yy]|"" ) OCSP_USE=true; break;;
[Nn] ) OCSP_USE=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
}
echo -n "${Green} Enter the Self-Signed SSL key-size to use (default ${SSL_KEY_SIZE_DEF}): ${Yellow}"
read SSL_KEY_SIZE
SSL_KEY_SIZE=${SSL_KEY_SIZE:-${SSL_KEY_SIZE_DEF}}
}
NGINX OPTIONS MENU
nginx_menu () {
SUB_MENU_TITLE="Nginx Menu"
menu_header
Server LAN IP
GUAC_LAN_IP_DEF=$(hostname -I | sed 's/ .*//')
echo -n "${Green} Enter the LAN IP of this server (default ${GUAC_LAN_IP_DEF}): ${Yellow}"
read GUAC_LAN_IP
GUAC_LAN_IP=${GUAC_LAN_IP:-${GUAC_LAN_IP_DEF}}
echo -n "${Green} Enter a valid hostname or public domain such as mydomain.com (default ${DOMAIN_NAME_DEF}): ${Yellow}"
read DOMAIN_NAME
DOMAIN_NAME=${DOMAIN_NAME:-${DOMAIN_NAME_DEF}}
echo -n "${Green} Enter the URI path, starting and ending with / for example /guacamole/ (default ${GUAC_URIPATH_DEF}): ${Yellow}"
read GUAC_URIPATH
GUAC_URIPATH=${GUAC_URIPATH:-${GUAC_URIPATH_DEF}}
Only prompt if SSL will be used
if [ $SSL_CERT_TYPE != "None" ]; then
while true; do
echo -n "${Green} Use only >= 256-bit SSL ciphers (More secure, less compatible. default: yes)?: ${Yellow}"
read yn
case $yn in
[Yy]|"" ) NGINX_SEC=true; break;;
[Nn] ) NGINX_SEC=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
while true; do
echo -n "${Green} Use Content-Security-Policy [CSP] (More secure, less compatible. default: yes)?: ${Yellow}"
read yn
case $yn in
[Yy]*|"" ) USE_CSP=true; break;;
[Nn]* ) USE_CSP=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
Allows selection of an authentication method in addition to MariaDB/Database or just MariaDB
which is used to store connection and user meta data for all other methods
echo "${Green} What Guacamole extension should be used as the primary user authentication method (default 1)?${Yellow}"
PS3="${Green} Enter the number of the desired authentication method: ${Yellow}"
Removing non-working options from the menu until they are ready
"RADIUS" "OpenID" "CAS"
options=("MariaDB Database" "LDAP(S)")
COLUMNS=1
select opt in "${options[@]}"
do
case $opt in
"MariaDB Database"|"") PRIME_AUTH_TYPE="MariaDB"; break;;
"LDAP(S)") PRIME_AUTH_TYPE="LDAP"; LDAP_ext_menu; break;;
# "RADIUS") PRIME_AUTH_TYPE="RADIUS"; Radius_ext_menu; break;;
# "OpenID") PRIME_AUTH_TYPE="OpenID"; OpenID_ext_menu; break;;
# "CAS") PRIME_AUTH_TYPE="CAS"; CAS_ext_menu; break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing the desired primary authentication method.";;
esac
done
Allows optional selection of a Two Factor Authentication (2FA) method
echo "${Green} What Guacamole extension should be used as the 2FA authentication method (default 1)?${Yellow}"
PS3="${Green} Enter the number of the desired authentication method: ${Yellow}"
Removing non-working options from the menu until they are ready
"DUO"
options=("None" "TOTP")
COLUMNS=1
select opt in "${options[@]}"
do
case $opt in
"None"|"") TFA_TYPE="None"; break;;
"TOTP") TFA_TYPE="TOTP"; TOTP_ext_menu; break;;
# "DUO") TFA_TYPE="DUO"; Duo_ext_menu; break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing the desired 2FA method.";;
esac
done
while true; do
echo -n "${Green} Use LDAPS instead of LDAP (Requires having the cert from the server copied locally, default: no): ${Yellow}"
read SECURE_LDAP
case $SECURE_LDAP in
[Yy]* ) SECURE_LDAP=true; break;;
[Nn]*|"" ) SECURE_LDAP=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
Check if LDAPS was selected
if [ $SECURE_LDAP = true ]; then
echo -ne "\n${Green} Enter the LDAP Port (default 636): ${Yellow}"
read LDAP_PORT
LDAP_PORT=${LDAP_PORT:-636}
# LDAPS Certificate placeholder values
LDAPS_CERT_FN="mycert.cer"
LDAPS_CERT_FULL="xNULLx"
while [ ! -f ${LDAPS_CERT_FULL} ]; do
echo -ne "\n${Green} Enter a valid filename of the .cer certificate file (Ex: mycert.cer): ${Yellow}"
read LDAPS_CERT_FN
LDAPS_CERT_FN=${LDAPS_CERT_FN:-${LDAPS_CERT_FN}}
echo -n "${Green} Enter the full path of the dir containing the .cer certificate file (must end with / Ex: /home/me/): ${Yellow}"
read LDAPS_CERT_DIR
LDAPS_CERT_DIR=${LDAPS_CERT_DIR:-/home/}
LDAPS_CERT_FULL=${LDAPS_CERT_DIR}${LDAPS_CERT_FN}
if [ ! -f ${LDAPS_CERT_FULL} ]; then
echo "${Red} The file/path: ${LDAPS_CERT_FULL} does not exist! Ensure the file is in the directory and try again..."
fi
done
echo -ne "\n${Green} Set the password for the CACert Java Keystore, must be 6 or more characters (default ${JKS_CACERT_PASSWD_DEF}): ${Yellow}"
read JKS_CACERT_PASSWD
JKS_CACERT_PASSWD=${JKS_CACERT_PASSWD:-${JKS_CACERT_PASSWD_DEF}}
else # Use LDAP not LDAPS
echo -ne "\n${Green} Enter the LDAP Port (default 389): ${Yellow}"
read LDAP_PORT
LDAP_PORT=${LDAP_PORT:-389}
fi
echo -ne "\n${Green} Enter the LDAP Server Hostname (use the FQDN, Ex: ldaphost.domain.com): ${Yellow}"
read LDAP_HOSTNAME
LDAP_HOSTNAME=${LDAP_HOSTNAME:-ldaphost.domain.com}
echo -n "${Green} Enter the LDAP User-Base-DN (Ex: dc=domain,dc=com): ${Yellow}"
read LDAP_BASE_DN
LDAP_BASE_DN=${LDAP_BASE_DN:-dc=domain,dc=com}
echo -n "${Green} Enter the LDAP Search-Bind-DN (Ex: cn=user,ou=Admins,dc=domain,dc=com): ${Yellow}"
read LDAP_BIND_DN
LDAP_BIND_DN=${LDAP_BIND_DN:-cn=user,ou=Admins,dc=domain,dc=com}
echo -n "${Green} Enter the LDAP Search-Bind-Password: ${Yellow}"
read LDAP_BIND_PW
LDAP_BIND_PW=${LDAP_BIND_PW:-password}
echo -n "${Green} Enter the LDAP Username-Attribute (default sAMAccountName): ${Yellow}"
read LDAP_UNAME_ATTR
LDAP_UNAME_ATTR=${LDAP_UNAME_ATTR:-sAMAccountName}
LDAP_SEARCH_FILTER_DEF="(objectClass=*)"
echo -n "${Green} Enter a custom LDAP user search filter (default "${LDAP_SEARCH_FILTER_DEF}"): ${Yellow}"
read LDAP_SEARCH_FILTER
LDAP_SEARCH_FILTER=${LDAP_SEARCH_FILTER:-${LDAP_SEARCH_FILTER_DEF}}
}
echo -n "${Green} Enter the TOTP issuer (default Apache Guacamole): ${Yellow}"
read TOTP_ISSUER
TOTP_ISSUER=${TOTP_ISSUER:-Apache Guacamole}
echo -n "${Green} Enter the number of digits to use for TOTP (default 6): ${Yellow}"
read TOTP_DIGITS
TOTP_DIGITS=${TOTP_DIGITS:-6}
echo -n "${Green} Enter the TOTP period in seconds (default 30): ${Yellow}"
read TOTP_PER
TOTP_PER=${TOTP_PER:-30}
echo -n "${Green} Enter the TOTP mode (default sha1): ${Yellow}"
read TOTP_MODE
TOTP_MODE=${TOTP_MODE:-sha1}
}
while true; do
echo -n "${Green} Would you like to install a custom Guacamole extensions from a local file (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* )
INSTALL_CUST_EXT=true
# Set placeholder values
CUST_FN="myextension.jar"
CUST_FULL="xNULLx"
while [ ! -f ${CUST_FULL} ]; do
echo -ne "\n${Green} Enter a valid filename of the .jar extension file (Ex: myextension.jar): ${Yellow}"
read CUST_FN
CUST_FN=${CUST_FN:-${CUST_FN}}
echo -n "${Green} Enter the full path of the dir containing the .jar extension file (must end with / Ex: /home/me/): ${Yellow}"
read CUST_DIR
CUST_DIR=${CUST_DIR:-/home/}
CUST_FULL=${CUST_DIR}${CUST_FN}
if [ ! -f ${CUST_FULL} ]; then # Check that full path/name exists, otherwise prompt again
echo "${Red} The file/path: ${CUST_FULL} does not exist! Ensure the file is in the directory and try again..."
fi
done
break;;
[Nn]*|"" ) INSTALL_CUST_EXT=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
echo "${Green} Select a category to review selections: ${Yellow}"
PS3="${Green} Enter the number of the category to review: ${Yellow}"
options=("Database" "Passwords" "SSL Cert Type" "Nginx" "Primary Authentication Extension" "2FA Extension" "Custom Extension" "Accept and Run Installation" "Cancel and Start Over" "Cancel and Exit Script")
select opt in "${options[@]}"
do
case $opt in
"Database") sum_db; break;;
"Passwords") sum_pw; break;;
"SSL Cert Type") sum_ssl; break;;
"Nginx") sum_nginx; break;;
"Primary Authentication Extension") sum_prime_auth_ext; break;;
"2FA Extension") sum_secondary_auth_ext; break;;
"Custom Extension") sum_cust_ext; break;;
"Accept and Run Installation") RUN_INSTALL=true; break;;
"Cancel and Start Over") ScriptLoc=$(readlink -f "$0"); exec "$ScriptLoc"; break;;
"Cancel and Exit Script") tput sgr0; exit 1; break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing the category to review.";;
esac
done
}
DATABASE SUMMARY
sum_db () {
SUB_MENU_TITLE="Database Summary"
menu_header
echo "${Green} Guacamole DB name: ${Yellow}${DB_NAME}"
echo "${Green} Guacamole DB username: ${Yellow}${DB_USER}"
echo -e "${Green} Java KeyStore key-size: ${Yellow}${JKSTORE_KEY_SIZE}\n"
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) db_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) pw_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
Check the certificate selection to display proper information for selection
case $SSL_CERT_TYPE in
"LetsEncrypt")
echo "${Green} e-mail for LetsEncrypt certificate: ${Yellow}${EMAIL_NAME}"
echo "${Green} LetEncrypt key-size: ${Yellow}${LE_KEY_SIZE}"
echo -e "${Green} Use OCSP Stapling?: ${Yellow}${OCSP_USE}\n"
;;
"Self-signed")
echo -e "${Green} Self-Signed SSL key-size: ${Yellow}${SSL_KEY_SIZE}\n"
;;
"None")
echo -e "${Yellow} As no certificate type was selected, an SSL certificate can be configured manually at a later time.\n"
;;
esac
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) ssl_cert_type_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
NGINX SUMMARY
sum_nginx () {
SUB_MENU_TITLE="Nginx Summary"
menu_header
echo "${Green} Guacamole Server LAN IP address: ${Yellow}${GUAC_LAN_IP}"
echo "${Green} Guacamole Server hostname or public domain: ${Yellow}${DOMAIN_NAME}"
echo "${Green} URI path: ${Yellow}${GUAC_URIPATH}"
echo "${Green} Using only 256-bit >= ciphers?: ${Yellow}${NGINX_SEC}"
echo -e "${Green} Content-Security-Policy [CSP] enabled?: ${Yellow}${USE_CSP}\n"
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) nginx_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
echo "${Yellow}${Bold} -- MariaDB is used with all authentication implementations --${Reset}"
echo "${Green} Default Guacamole username: ${Yellow}guacadmin"
echo -e "${Green} Default Guacamole password: ${Yellow}guacadmin\n"
Check the authentication selection to display proper information for the selection
case $PRIME_AUTH_TYPE in
"LDAP")
echo -e "${Reset}${Bold} -- LDAP Specific Parameters --${Reset}\n"
echo "${Green} Use LDAPS instead of LDAP: ${Yellow}${SECURE_LDAP}"
echo -e "${Green} LDAP(S) port: ${Yellow}${LDAP_PORT}\n"
if [ $SECURE_LDAP = true ]; then
echo "${Green} LDAPS full filename and path: ${Yellow}${LDAPS_CERT_FULL}"
echo -e "${Green} CACert Java Keystroe password: ${Yellow}${JKS_CACERT_PASSWD}\n"
fi
echo "${Green} LDAP Server Hostname (should be FQDN, Ex: ldaphost.domain.com): ${Yellow}${LDAP_HOSTNAME}"
echo "${Green} LDAP User-Base-DN (Ex: dc=domain,dc=com): ${Yellow}${LDAP_BASE_DN}"
echo "${Green} LDAP Search-Bind-DN (Ex: cn=user,ou=Admins,dc=domain,dc=com): ${Yellow}${LDAP_BIND_DN}"
echo "${Green} LDAP Search-Bind-Password: ${Yellow}${LDAP_BIND_PW}"
echo "${Green} LDAP Username-Attribute: ${Yellow}${LDAP_UNAME_ATTR}"
echo -e "${Green} LDAP user search filter: ${Yellow}${LDAP_SEARCH_FILTER}\n"
;;
"RADIUS")
echo -e "${Red} RADIUS cannot currently be installed by this script.\n"
;;
"OpenID")
echo -e "${Red} OpenID cannot currently be installed by this script.\n"
;;
"CAS")
echo -e "${Red} CAS cannot currently be installed by this script.\n"
;;
esac
while true; do
echo -n "${Green} Would you like to change the authentication method and properties (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) prime_auth_ext_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
Check the authentication selection to display proper information for the selection
case $TFA_TYPE in
"None")
echo -e "${Yellow}${Bold} -- No form of 2FA will be implemented by this script --${Reset}\n"
;;
"TOTP")
echo "${Green} TOTP issuer: ${Yellow}${TOTP_ISSUER}"
echo "${Green} Number of TOTP digits: ${Yellow}${TOTP_DIGITS}"
echo "${Green} TOTP period in seconds: ${Yellow}${TOTP_PER}"
echo -e "${Green} TOTP mode: ${Yellow}${TOTP_MODE}\n"
;;
"DUO")
echo -e "${Red} DUO cannot currently be installed by this script.\n"
;;
esac
while true; do
echo -n "${Green} Would you like to change the 2FA method and properties (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) secondary_auth_ext_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
echo -e "${Green} Install a custom Guacamole extension: ${Yellow}${INSTALL_CUST_EXT}\n"
if [ $INSTALL_CUST_EXT = true ]; then
echo "${Green} Filename of the .jar extension file: ${Yellow}${CUST_FN}"
echo "${Green} Full path of the dir containing the .jar extension file: ${Yellow}${CUST_DIR}"
echo -e "${Green} Full file path: ${Yellow}${CUST_FULL}\n"
fi
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) cust_ext_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
spinner () {
pid=$!
#Store the background process id in a temp file to use in err_handler
echo $(jobs -p) > "${VAR_FILE}"
spin[0]="-"
spin[1]="\"
spin[2]="|"
spin[3]="/"
Loop while the process is still running
while kill -0 $pid 2>/dev/null
do
for i in "${spin[@]}"
do
if kill -0 $pid 2>/dev/null; then #Check that the process is running to prevent a full 4 character cycle on error
# Display the spinner in 1/4 states
echo -ne "\b\b\b${Bold}[${Green}$i${Reset}${Bold}]" >&3
sleep .5 # time between each state
else #process has ended, stop next loop from finishing iteration
break
fi
done
done
Check if background process failed once complete
if wait $pid; then # Exit 0
echo -ne "\b\b\b${Bold}[${Green}-done-${Reset}${Bold}]" >&3
else # Any other exit
false
fi
#Set background process id value to -1 representing no background process running to err_handler
echo "-1" > "${VAR_FILE}"
tput sgr0 >&3
}
SPECIAL ECHO FUNCTION
This allows echo to log and stdout (now fd3) while sending all else to log by default via exec
s_echo () {
Use first arg $1 to determine if echo skips a line (yes/no)
Second arg $2 is the message
case $1 in
# No preceeding blank line
[Nn])
echo -ne "\n${2}" | tee -a /dev/fd/3
echo # add new line after in log only
;;
# Preceeding blank line
[Yy]|*)
echo -ne "\n\n${2}" | tee -a /dev/fd/3
echo # add new line after in log only
;;
esac
}
Used to force all stdout and stderr to the log file
s_echo function will be used when echo needs to be displayed and logged
exec &> "${logfile}"
ERROR HANDLER FUNCTION
Called by trap to display/log error info and exit script
err_handler () {
EXITCODE=$?
#Read values from temp file used to store cross process values
F_BG=$(sed -n 1p "${VAR_FILE}")
Check if the temp variable file is greater than 1 line of text
if [ $(wc -l < "${VAR_FILE}") -gt 1 ]; then
# If so, set variable according to value of the 2nd line in the file.
H_ERR=$(sed -n 2p "${VAR_FILE}")
else # Otherwise, set to false, error was not triggered previously
H_ERR=false
fi
#Check this is the first time the err_handler has triggered
if [ $H_ERR = false ]; then
#Check if error occured with a background process running
if [ $F_BG -gt 0 ]; then
echo -ne "\b\b\b${Bold}[${Red}-FAILED-${Reset}${Bold}]" >&3
fi
FAILED_COMMAND=$(eval echo "$BASH_COMMAND") # Used to expand the variables in the command returned by BASH_COMMAND
s_echo "y" "${Reset}${Red}%%% ${Reset}${Bold}ERROR (Script Failed) | Line${Reset} ${BASH_LINENO[0]} ${Bold}| Command:${Reset} ${FAILED_COMMAND} ${Bold}| Exit code:${Reset} ${EXITCODE} ${Red}%%%${Reset}\n\n"
#Flag as trap having been run already skipping double error messages
echo "true" >> "${VAR_FILE}"
fi
Log cleanup to remove escape sequences caused by tput for formatting text
sed -i 's/\x1b[[0-9;]*m|\x1b[(]B\x1b[m//g' ${logfile}
tput sgr0 >&3
exit $EXITCODE
}
CHECK INSTALLED PACKAGE FUNCTION
Query rpm for package without triggering trap when not found
chk_installed () {
if rpm -q "$@"; then
RETVAL=$?
else
RETVAL=$?
fi
}
CHECK REPO ENABLED FUNCTION
Query repos files to view if repo is enabled trigger trap when not enabled
chk_repo_enabled () {
if grep -q "$@"; then
RETVAL=$?
else
RETVAL=$?
fi
}
ERROR TRAP
Trap to call error function to display and log error details
reposinstall () {
s_echo "n" "${Bold} ----==== INSTALLING GUACAMOLE ${GUAC_SOURCE} ${GUAC_VER} ====----"
s_echo "y" "Installing Repos and mandatory software"
Install wget
chk_installed "wget"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "${Reset}-WGET is installed."
else
{ yum -y install wget; } &
s_echo "n" "${Reset}-WGET is missing. Installing... "; spinner
fi
Install make
chk_installed "make"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "${Reset}-MAKE is installed."
else
{ yum -y install make; } &
s_echo "n" "${Reset}-MAKE is missing. Installing... "; spinner
fi
chk_repo_enabled "enabled=1" /etc/yum.repos.d/almalinux-powertools.repo
if [ $RETVAL -eq 0 ]; then
s_echo "n" "-Powertools enabled."
else
{ dnf config-manager --enable powertools; } &
s_echo "n" "-PowerTools was not enabled, enabled "; spinner
fi
if [ $GUAC_SOURCE == "Git" ]; then
cd guacamole-server/
{ autoreconf -fi; } &
s_echo "n" "${Reset}-Guacamole Server compile prep... "; spinner
else # Stable release
cd server
fi
Compile Guacamole Server
{ ./configure --with-systemd-dir=/usr/lib/systemd/system/; } &
s_echo "n" "${Reset}-Compiling Guacamole Server Stage 1 of 4... "; spinner
{ make; } &
s_echo "n" "-Compiling Guacamole Server Stage 2 of 4... "; spinner
{ make install; } &
s_echo "n" "-Compiling Guacamole Server Stage 3 of 4... "; spinner
{ ldconfig; } &
s_echo "n" "-Compiling Guacamole Server Stage 4 of 4... "; spinner
cd ..
if [ $GUAC_SOURCE == "Git" ]; then
# Get JDBC from compiled client
{ find ./guacamole-client/extensions -name "guacamole-auth-jdbc-mysql-${GUAC_VER}.jar" -exec mv -v {} ${LIB_DIR}extensions/ ;; } &
s_echo "n" "-Moving Guacamole JDBC extension to extensions dir... "; spinner
fi
Setup guacd user, group and permissions
{
# Create a user and group for guacd with a home folder but no login
groupadd ${GUACD_USER}
# The guacd user is created as a service account, no login but does get a home dir as needed by freerdp
useradd -r ${GUACD_USER} -m -s "/bin/nologin" -g ${GUACD_USER} -c ${GUACD_USER}
# Set the user that runs the guacd service
sed -i "s/User=daemon/User=${GUACD_USER}/g" /usr/lib/systemd/system/guacd.service
{ mysqladmin -u root password ${MYSQL_PASSWD}; } &
s_echo "n" "-Setting root password for MariaDB... "; spinner
Run MariaDB/MySQL Secure Install
{
mysql_secure_installation <<EOF
${MYSQL_PASSWD}
n
y
y
y
y
EOF
} &
s_echo "n" "-Harden MariaDB... "; spinner
Create Database and user
{
mysql -u root -p${MYSQL_PASSWD} -e "CREATE DATABASE ${DB_NAME};"
mysql -u root -p${MYSQL_PASSWD} -e "GRANT SELECT,INSERT,UPDATE,DELETE ON ${DB_NAME}.* TO '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASSWD}';"
mysql -u root -p${MYSQL_PASSWD} -e "FLUSH PRIVILEGES;"
} &
s_echo "n" "-Creating Database & User for Guacamole... "; spinner
Create Guacamole Table
{
if [ $GUAC_SOURCE == "Git" ]; then
cat guacamole-client/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/.sql | mysql -u root -p${MYSQL_PASSWD} -D ${DB_NAME}
else # Stable release
cat extension/mysql/schema/.sql | mysql -u root -p${MYSQL_PASSWD} -D ${DB_NAME}
fi
} &
s_echo "n" "-Creating Guacamole Tables... "; spinner
Populate mysql database with time zones from system
Fixes timezone issues when using MySQLConnectorJ 8.x or geater
{
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p${MYSQL_PASSWD}
MY_CNF_LINE=grep -n "\[mysqld\]" /etc/my.cnf.d/mariadb-server.cnf | grep -o '^[0-9]*'
# MY_CNF_LINE=grep -n "\[mysqld\]" /etc/my.cnf | grep -o '^[0-9]*'
MY_CNF_LINE=$((MY_CNF_LINE + 1 ))
MY_TZ=readlink /etc/localtime | sed "s/.*\/usr\/share\/zoneinfo\///"
sed -i "${MY_CNF_LINE}i default-time-zone='${MY_TZ}'" /etc/my.cnf.d/mariadb-server.cnf
systemctl restart mariadb
} &
s_echo "n" "-Setting Time Zone Database & Config... "; spinner
Setup Tomcat
s_echo "y" "${Bold}Setup Tomcat Server"
{
sed -i '72i URIEncoding="UTF-8"' /etc/${TOMCAT_VER}/server.xml
sed -i '92i <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/var/lib/${TOMCAT_VER}/webapps/.keystore"
keystorePass="JKS_GUAC_PASSWD"
URIEncoding="UTF-8" />' /etc/${TOMCAT_VER}/server.xml
sed -i "s/JKS_GUAC_PASSWD/${JKS_GUAC_PASSWD}/g" /etc/${TOMCAT_VER}/server.xml
} &
s_echo "n" "${Reset}-Base Tomcat configuration... "; spinner
{
Tomcat RemoteIpValve (to pass remote host IP's from proxy to tomcat. Allows Guacamole to log remote host IPs)
sed -i '/<\/Host>/i\<Valve className="org.apache.catalina.valves.RemoteIpValve" \
internalProxies="GUAC_SERVER_IP" \
remoteIpHeader="x-forwarded-for" \
remoteIpProxiesHeader="x-forwarded-by" \
protocolHeader="x-forwarded-proto" />' /etc/${TOMCAT_VER}/server.xml
sed -i "s/GUAC_SERVER_IP/${GUAC_LAN_IP}/g" /etc/${TOMCAT_VER}/server.xml
} &
s_echo "n" "-Set RemoteIpValve in Tomcat configuration... "; spinner
{
Add ErrorReportingValve to prevent displaying tomcat info on error pages
sed -i '/<\/Host>/i\<Valve className="org.apache.catalina.valves.ErrorReportValve" \
showReport="false" \
showServerInfo="false"/>' /etc/${TOMCAT_VER}/server.xml
} &
s_echo "n" "-Set ErrorReportingVavle in ${TOMCAT_VER}n... "; spinner
# If OCSP Stapling was selected add lines
if [ $OCSP_USE = true ]; then
if [[ -r /etc/resolv.conf ]]; then
NAME_SERVERS=$(awk '/^nameserver/{print $2}' /etc/resolv.conf | xargs)
fi
if [[ -z $NAME_SERVERS ]]; then
NAME_SERVERS=$NAME_SERVERS_DEF
fi
echo " #ssl_trusted_certificate guacamole.pem;
ssl_stapling on;
ssl_stapling_verify on;
resolver ${NAME_SERVERS} valid=30s;
resolver_timeout 30s;" >> /etc/nginx/conf.d/guacamole_ssl.conf
fi
# If using >= 256-bit ciphers
if [ $NGINX_SEC = true ]; then
echo " ssl_ciphers 'TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384';" >> /etc/nginx/conf.d/guacamole_ssl.conf
else
echo " ssl_ciphers 'TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256';" >> /etc/nginx/conf.d/guacamole_ssl.conf
fi
# Rest of HTTPS/SSL Nginx Conf
echo " ssl_protocols TLSv1.3 TLSv1.2;
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Referrer-Policy \"no-referrer\";
add_header Strict-Transport-Security \"max-age=15768000; includeSubDomains\" always;" >> /etc/nginx/conf.d/guacamole_ssl.conf
# If CSP was enabled, add line, otherwise add but comment out (to allow easily manual toggle of the feature)
if [ $USE_CSP = true ]; then
echo " add_header Content-Security-Policy \"default-src 'none'; script-src 'self' 'unsafe-eval'; connect-src 'self' wss://${DOMAIN_NAME}; object-src 'self'; frame-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'; form-action 'self'; base-uri 'self'; frame-ancestors 'self';\" always;" >> /etc/nginx/conf.d/guacamole_ssl.conf
else
echo " #add_header Content-Security-Policy \"default-src 'none'; script-src 'self' 'unsafe-eval'; connect-src 'self' wss://${DOMAIN_NAME}; object-src 'self'; frame-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'; form-action 'self'; base-uri 'self'; frame-ancestors 'self';\" always;" >> /etc/nginx/conf.d/guacamole_ssl.conf
fi
echo " add_header X-Frame-Options \"SAMEORIGIN\" always;
add_header X-Content-Type-Options \"nosniff\" always;
add_header X-XSS-Protection \"1; mode=block\" always;
proxy_hide_header Server;
proxy_hide_header X-Powered-By;
client_body_timeout 10;
client_header_timeout 10;
location ${GUAC_URIPATH} {
proxy_pass http://${GUAC_LAN_IP}:8080/guacamole/;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$http_connection;
proxy_cookie_path /guacamole/ \"${GUAC_URIPATH}; HTTPOnly; Secure; SameSite\";
access_log /var/log/nginx/guac_access.log;
error_log /var/log/nginx/guac_error.log;
}
}" >> /etc/nginx/conf.d/guacamole_ssl.conf
} &
s_echo "n" "-Generate Nginx guacamole_ssl.config... "; spinner
Nginx CIS hardening v1.0.0
{
# 2.3.2 Restrict access to Nginx files
find /etc/nginx -type d | xargs chmod 750
find /etc/nginx -type f | xargs chmod 640
# 2.4.3 & 2.4.4 set keepalive_timeout and send_timeout to 1-10 seconds, default 65/60.
sed -i '/keepalive_timeout/c\keepalive_timeout 10\;' /etc/nginx/nginx.conf
# sed -i '/send_timeout/c\send_timeout 10\;' /etc/nginx/nginx.conf
# 2.5.2 Reoving mentions of Nginx from index and error pages
! read -r -d '' BLANK_HTML <<"EOF"
EOF
echo "${BLANK_HTML}" > /usr/share/nginx/html/index.html
echo "${BLANK_HTML}" > /usr/share/nginx/html/50x.html
# 3.4 Ensure logs are rotated (may set this as a user defined parameter)
sed -i "s/daily/weekly/" /etc/logrotate.d/nginx
sed -i "s/rotate 52/rotate 13/" /etc/logrotate.d/nginx
} &
s_echo "n" "-Hardening Nginx config... "; spinner
Call each Guac extension function for those selected
if [ $INSTALL_LDAP = true ]; then ldapsetup; fi
if [ $INSTALL_TOTP = true ]; then totpsetup; fi
if [ $INSTALL_DUO = true ]; then duosetup; fi
if [ $INSTALL_RADIUS = true ]; then radiussetup; fi
if [ $INSTALL_CAS = true ]; then cassetup; fi
if [ $INSTALL_OPENID = true ]; then openidsetup; fi
if [ $INSTALL_CUST_EXT = true ]; then custsetup; fi
selinuxsettings
}
LDAP SETUP
ldapsetup () {
s_echo "y" "${Bold}Setup the LDAP Extension"
Append LDAP configuration lines to guacamole.properties
{ echo "
LDAP properties
ldap-hostname: ${LDAP_HOSTNAME}
ldap-port: ${LDAP_PORT}" >> /etc/guacamole/${GUAC_CONF}; } &
s_echo "n" "${Reset}-Updating guacamole.properties file for LDAP... "; spinner
{
if [ $RETVAL -eq 0 ]; then
systemctl enable firewalld
systemctl restart firewalld
fi
} &
s_echo "n" "${Reset}-firewalld is installed and started on the system... "; spinner
Backup firewall public zone config
{ cp /etc/firewalld/zones/public.xml $fwbkpfile; } &
s_echo "n" "-Backing up firewall public zone to: $fwbkpfile "; spinner
Open HTTP and HTTPS ports
{
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-service=http"
firewall-cmd --permanent --zone=public --add-service=http
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-service=https"
firewall-cmd --permanent --zone=public --add-service=https
} &
s_echo "n" "-Opening HTTP and HTTPS service ports... "; spinner
Open 8080 and 8443 ports. Need to review if this is required or not
{
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-port=8080/tcp"
firewall-cmd --permanent --zone=public --add-port=8080/tcp
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-port=8443/tcp"
firewall-cmd --permanent --zone=public --add-port=8443/tcp
} &
s_echo "n" "-Opening ports 8080 and 8443 on TCP... "; spinner
if [ $SSL_CERT_TYPE != "None" ]; then
# Lets Encrypt Setup (If selected)
if [ $SSL_CERT_TYPE = "LetsEncrypt" ]; then
# Install certbot from repo
{ yum install -y certbot python2-certbot-nginx; } &
s_echo "n" "${Reset}-Downloading certboot tool... "; spinner
# OCSP
{
if [ $OCSP_USE = true ]; then
certbot certonly --nginx --must-staple -n --agree-tos --rsa-key-size ${LE_KEY_SIZE} -m "${EMAIL_NAME}" -d "${DOMAIN_NAME}"
else # Generate without OCSP --must-staple
certbot certonly --nginx -n --agree-tos --rsa-key-size ${LE_KEY_SIZE} -m "${EMAIL_NAME}" -d "${DOMAIN_NAME}"
fi
} &
s_echo "n" "-Generating a ${SSL_CERT_TYPE} SSL Certificate... "; spinner
# Symlink Lets Encrypt certs so renewal does not break Nginx
{
ln -vs "/etc/letsencrypt/live/${DOMAIN_NAME}/fullchain.pem" /etc/nginx/guacamole.crt
ln -vs "/etc/letsencrypt/live/${DOMAIN_NAME}/privkey.pem" /etc/nginx/guacamole.key
ln -vs "/etc/letsencrypt/live/${DOMAIN_NAME}/chain.pem" /etc/nginx/guacamole.pem
} &
s_echo "n" "-Creating symlinks to ${SSL_CERT_TYPE} SSL certificates... "; spinner
# Setup automatic cert renewal
{
systemctl enable certbot-renew.service
systemctl enable certbot-renew.timer
systemctl list-timers --all | grep certbot
} &
s_echo "n" "-Setup automatic ${SSL_CERT_TYPE} SSL certificate renewals... "; spinner
else # Use a Self-Signed Cert
{ openssl req -x509 -sha512 -nodes -days 365 -newkey rsa:${SSL_KEY_SIZE} -keyout /etc/nginx/guacamole.key -out /etc/nginx/guacamole.crt -subj "/C=''/ST=''/L=''/O=''/OU=''/CN=''"; } &
s_echo "n" "${Reset}-Generating ${SSL_CERT_TYPE} SSL Certificate... "; spinner
fi
# Nginx CIS v1.0.0 - 4.1.3 ensure private key permissions are restricted
{
ls -l /etc/nginx/guacamole.key
chmod 400 /etc/nginx/guacamole.key
} &
s_echo "n" "${Reset}-Changing permissions on SSL private key... "; spinner
{
# Uncomment listen lines from Nginx guacamole_ssl.conf (fixes issue introduced by Nginx 1.16.0)
sed -i 's/#\(listen.*443.*\)/\1/' /etc/nginx/conf.d/guacamole_ssl.conf
# Uncomment cert lines from Nginx guacamole_ssl.conf
sed -i 's/#\(.*ssl_.*certificate.*\)/\1/' /etc/nginx/conf.d/guacamole_ssl.conf
} &
s_echo "n" "${Reset}-Enabling SSL certificate in guacamole_ssl.conf... "; spinner
HTTPS_ENABLED=true
else # Cert is set to None
s_echo "n" "${Reset}-No SSL Cert selected..."
# Will not force/use HTTPS without a cert, comment out redirect
{ sed -i '/\(return 301 https\)/s/^/#/' /etc/nginx/conf.d/guacamole.conf; } &
s_echo "n" "${Reset}-Update guacamole.conf to allow HTTP connections... "; spinner
HTTPS_ENABLED=false
fi
showmessages
}
COMPLETION MESSAGES
showmessages () {
s_echo "y" "${Bold}Services"
Restart all services and log status
{
systemctl restart ${TOMCAT_VER}
systemctl status ${TOMCAT_VER}
systemctl restart guacd
systemctl status guacd
systemctl restart mariadb
systemctl status mariadb
systemctl restart nginx
systemctl status nginx
# Verify that the guacd user is running guacd
ps aux | grep ${GUACD_USER}
ps -U ${GUACD_USER}
} &
s_echo "n" "${Reset}-Restarting all services... "; spinner
s_echo "y" "${Bold}Log Files"
s_echo "n" "${Reset}-Log file: ${logfile}"
s_echo "n" "-firewall backup file: ${fwbkpfile}"
Determine Guac server URL for web GUI
if [ ${DOMAIN_NAME} = "localhost" ]; then
GUAC_URL=${GUAC_LAN_IP}${GUAC_URIPATH}
else # Not localhost
GUAC_URL=${DOMAIN_NAME}${GUAC_URIPATH}
fi
Determine if HTTPS is used or not
if [ ${HTTPS_ENABLED} = true ]; then
HTTPS_MSG="${Reset} or ${Bold}https://${GUAC_URL}${Reset}"
else # HTTPS not used
HTTPS_MSG="${Reset}. Without a cert, HTTPS is not forced/available."
fi
Manage Guac
s_echo "y" "${Bold}To manage Guacamole"
s_echo "n" "${Reset}-go to: ${Bold}http://${GUAC_URL}${HTTPS_MSG}"
s_echo "n" "-The default username and password are: ${Red}guacadmin"
Recommendations
s_echo "y" "Important Recommendations${Reset}"
if [ $INSTALL_LDAP = false ]; then
s_echo "n" "-It is highly recommended to create an admin account in Guacamole and delete/disable the default asap!"
else
s_echo "n" "-You should assign at least one AD/LDAP user to have full admin, see the directions on how-to at:"
s_echo "n" "${Green} https://github.com/Zer0CoolX/guacamole-install-rhel-7/wiki/LDAP-or-LDAPS-Authentication#important-manual-steps${Reset}"
s_echo "n" "-Afterwards, it is highly recommended to delete/disable the default admin account and/or create a uniquely named local admin account asap!"
if [ $SECURE_LDAP = true ]; then
s_echo "n" "-Its highly recommended to remove the LDAPS certificate file from: ${LDAPS_CERT_FULL}"
fi
fi
s_echo "y" "${Green}While not technically required, you should consider a reboot after verifying installation${Reset}"
s_echo "y" "${Bold}Contact ${Reset}${ADM_POC}${Bold} with any questions or concerns regarding this script\n"
Log cleanup to remove escape sequences caused by tput for formatting text
sed -i 's/\x1b[[0-9;]*m|\x1b[(]B\x1b[m//g' ${logfile}
tput sgr0 >&3
}
INSTALLATION EXECUTION
Runs the install if the option was selected from the summary menu
if [ ${RUN_INSTALL} = true ]; then
tput sgr0 >&3
clear >&3
reposinstall
if [ $DEL_TMP_VAR = true ]; then
rm "$VAR_FILE"
fi
exit 0
fi
`
You can see parts where i added fwe things to allow running into AlmaLinux 8
Hope it helps
Bye!
The text was updated successfully, but these errors were encountered:
Hi, i adatped you script guac-install for Almalinux 8.4 and it works, i'm not able to use git,
`#!/bin/env bash
#Script to install guacamole RDP html5 gateway into Almalinux 8.4
#The script is working in progress is not all my work, i adapted a existent script to my distro
PRE-RUN CHECKS
if ! [ $(id -u) = 0 ]; then echo "This script must be run as sudo or root, try again..."; exit 1; fi
if ! [ $(getenforce) = "Enforcing" ]; then echo "This script requires SELinux to be active and in "Enforcing mode""; exit 1; fi
if ! [ $(uname -m) = "x86_64" ]; then echo "This script will only run on 64 bit versions of RHEL/CentOS"; exit 1; fi
Check that firewalld is installed
if ! rpm -q --quiet "firewalld"; then echo "This script requires firewalld to be installed on the system"; exit 1; fi
Allow trap to work in functions
set -E
######################################################################
VARIABLES
######################################################################
UNIVERSAL VARIABLES
USER CONFIGURABLE
Generic
SCRIPT_BUILD="2021_07_03" # Scripts Date for last modified as "yyyy_mm_dd"
ADM_POC="Local Admin, [email protected]" # Point of contact for the Guac server admin
Versions
GUAC_STBL_VER="1.3.0" # Latest stable version of Guac from https://guacamole.apache.org/releases/
MYSQL_CON_VER="8.0.25" # Working stable release of MySQL Connecter J
MAVEN_VER="3.8.1" # Latest stable version of Apache Maven
TOMCAT_VER="tomcat9" # Tomcat Version
Ports
GUAC_PORT="4822"
MYSQL_PORT="3306"
Key Sizes
JKSTORE_KEY_SIZE_DEF="4096" # Default Java Keystore key-size
LE_KEY_SIZE_DEF="4096" # Default Let's Encrypt key-size
SSL_KEY_SIZE_DEF="4096" # Default Self-signed SSL key-size
Default Credentials
MYSQL_PASSWD_DEF="guacamole" # Default MySQL/MariaDB root password
DB_NAME_DEF="guac_db" # Defualt database name
DB_USER_DEF="guac_adm" # Defualt database user name
DB_PASSWD_DEF="guacamole" # Defualt database password
JKS_GUAC_PASSWD_DEF="guacamole" # Default Java Keystore password
JKS_CACERT_PASSWD_DEF="guacamole" # Default CACert Java Keystore password, used with LDAPS
Misc
GUACD_USER="guacd" # The user name and group of the user running the guacd service
GUAC_URIPATH_DEF="/" # Default URI for Guacamole
DOMAIN_NAME_DEF="localhost" # Default domain name of server
H_ERR=false # Defualt value of if an error has been triggered, should be false
LIBJPEG_EXCLUDE="exclude=libjpeg-turbo-[0-9],libjpeg-turbo-..9[0-9]-"
DEL_TMP_VAR=true # Default behavior to delete the temp var file used by error handler on completion. Set to false to keep the file to review last values
NAME_SERVERS_DEF="1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001" # OCSP resolver DNS name servers defaults !!Only used if the host does not have name servers in resolv.conf!!
ONLY CHANGE IF NOT WORKING
URLS
MYSQL_CON_URL="https://dev.mysql.com/get/Downloads/Connector-J/" #Direct URL for download
LIBJPEG_REPO="https://libjpeg-turbo.org/pmwiki/uploads/Downloads/libjpeg-turbo.repo"
Dirs and File Names
LIB_DIR="/var/lib/guacamole/"
GUAC_CONF="guacamole.properties" # Guacamole configuration/properties file
MYSQL_CON="mysql-connector-java-${MYSQL_CON_VER}"
TMP_VAR_FILE="guac_tmp_vars" # Temp file name used to store varaibles for the error handler
Formats
Black=
tput setaf 0
#${Black}Red=
tput setaf 1
#${Red}Green=
tput setaf 2
#${Green}Yellow=
tput setaf 3
#${Yellow}Blue=
tput setaf 4
#${Blue}Magenta=
tput setaf 5
#${Magenta}Cyan=
tput setaf 6
#${Cyan}White=
tput setaf 7
#${White}Bold=
tput bold
#${Bold}UndrLn=
tput sgr 0 1
#${UndrLn}Rev=
tput smso
#${Rev}Reset=
tput sgr0
#${Reset}END UNIVERSAL VARIABLES
INITIALIZE COMMON VARIABLES
ONLY CHANGE IF NOT WORKING
init_vars () {
Get the release version of Guacamole from/for Git
GUAC_GIT_VER=
curl -s https://raw.githubusercontent.com/apache/guacamole-server/master/configure.ac | grep 'AC_INIT([guacamole-server]*' | awk -F'[][]' -v n=2 '{ print $(2*n) }'
PWD=
pwd
# Current directorySet full path/file name of file used to stored temp variables used by the error handler
VAR_FILE="${PWD}/${TMP_VAR_FILE}"
echo "-1" > "${VAR_FILE}" # create file with -1 to set not as background process
Determine if OS is RHEL, CentOS or something else
if grep -q "CentOS" /etc/redhat-release; then
OS_NAME="CentOS"
elif grep -q "Red Hat Enterprise" /etc/redhat-release; then
OS_NAME="RHEL"
elif grep -q "AlmaLinux release 8.4" /etc/redhat-release; then
OS_NAME="CentOS"
else
echo "Unable to verify OS from /etc/redhat-release as CentOS or RHEL, this script is intended only for those distro's, exiting."
exit 1
fi
OS_NAME_L="$(echo $OS_NAME | tr '[:upper:]' '[:lower:]')" # Set lower case rhel or centos for use in some URLs
Outputs the major.minor.release number of the OS, Ex: 7.6.1810 and splits the 3 parts.
MAJOR_VER=
cat /etc/redhat-release | grep -oP "[0-9]+" | sed -n 1p
# Return the leftmost digit representing major versionMINOR_VER=
cat /etc/redhat-release | grep -oP "[0-9]+" | sed -n 2p
# Returns the middle digit representing minor versionPlaceholder in case this info is ever needed. RHEL does not have release number, only major.minor
RELEASE_VER=
cat /etc/redhat-release | grep -oP "[0-9]+" | sed -n 3p
# Returns the rightmost digits representing release number#Set arch used in some paths
MACHINE_ARCH=
uname -m
ARCH="64"
Set nginx url for RHEL or CentOS
NGINX_URL="https://nginx.org/packages/$OS_NAME_L/$MAJOR_VER/$MACHINE_ARCH/"
}
SOURCE VARIABLES
src_vars () {
Check if selected source is Git or stable release, set variables based on selection
if [ $GUAC_SOURCE == "Git" ]; then
GUAC_VER=${GUAC_GIT_VER}
GUAC_URL="git://github.com/apache/"
GUAC_SERVER="guacamole-server.git"
GUAC_CLIENT="guacamole-client.git"
MAVEN_MAJOR_VER=${MAVEN_VER:0:1}
MAVEN_URL="https://www-us.apache.org/dist/maven/maven-${MAVEN_MAJOR_VER}/${MAVEN_VER}/binaries/"
MAVEN_FN="apache-maven-${MAVEN_VER}"
MAVEN_BIN="${MAVEN_FN}-bin.tar.gz"
else # Stable release
GUAC_VER=${GUAC_STBL_VER}
GUAC_URL="https://apache.org/dyn/closer.cgi?action=download&filename=guacamole/${GUAC_VER}/"
GUAC_SERVER="guacamole-server-${GUAC_VER}"
GUAC_CLIENT="guacamole-${GUAC_VER}"
fi
JDBC Extension file name
GUAC_JDBC="guacamole-auth-jdbc-${GUAC_VER}"
LDAP extension file name
GUAC_LDAP="guacamole-auth-ldap-${GUAC_VER}"
TOTP extension file name
GUAC_TOTP="guacamole-auth-totp-${GUAC_VER}"
Dirs and file names
INSTALL_DIR="/usr/local/src/guacamole/${GUAC_VER}/" # Guacamole installation dir
FILENAME="${PWD}/guacamole-${GUAC_VER}_"$(date +"%d-%y-%b")"" # Script generated log filename
logfile="${FILENAME}.log" # Script generated log file full name
fwbkpfile="${FILENAME}.firewall.bkp" # Firewall backup file name
}
######################################################################
MENUS
######################################################################
SOURCE MENU
src_menu () {
clear
echo -e " ${Reset}${Bold}----====Gucamole Installation Script====----\n ${Reset}Guacamole Remote Desktop Gateway\n"
echo -e " ${Bold}*** Source Menu ***\n"
echo " OS: ${Yellow}${OS_NAME} ${MAJOR_VER}.${MINOR_VER} ${MACHINE_ARCH}${Reset}"
echo -e " ${Bold}Stable Version: ${Yellow}${GUAC_STBL_VER}${Reset} || ${Bold}Git Version: ${Yellow}${GUAC_GIT_VER}${Reset}\n"
while true; do
echo -n "${Green} Pick the desired source to install from (enter 'stable' or 'git', default is 'stable'): ${Yellow}"
read GUAC_SOURCE
case $GUAC_SOURCE in
[Ss]table|"" ) GUAC_SOURCE="Stable"; break;;
[Gg][Ii][Tt] ) GUAC_SOURCE="Git"; break;;
* ) echo "${Green} Please enter 'stable' or 'git' to select source/version (without quotes)";;
esac
done
tput sgr0
}
START EXECUTION
init_vars
src_menu
src_vars
MENU HEADERS
Called by each menu and summary menu to display the dynamic header
menu_header () {
tput sgr0
clear
echo -e " ${Reset}${Bold}----====Gucamole Installation Script====----\n ${Reset}Guacamole Remote Desktop Gateway\n"
echo -e " ${Bold}*** ${SUB_MENU_TITLE} ***\n"
echo " OS: ${Yellow}${OS_NAME} ${MAJOR_VER}.${MINOR_VER} ${MACHINE_ARCH}${Reset}"
echo -e " ${Bold}Source/Version: ${Yellow}${GUAC_SOURCE} ${GUAC_VER}${Reset}\n"
}
DATABASE AND JKS MENU
db_menu () {
SUB_MENU_TITLE="Database and JKS Menu"
menu_header
echo -n "${Green} Enter the Guacamole DB name (default ${DB_NAME_DEF}): ${Yellow}"
read DB_NAME
DB_NAME=${DB_NAME:-${DB_NAME_DEF}}
echo -n "${Green} Enter the Guacamole DB username (default ${DB_USER_DEF}): ${Yellow}"
read DB_USER
DB_USER=${DB_USER:-${DB_USER_DEF}}
echo -n "${Green} Enter the Java KeyStore key-size to use (default ${JKSTORE_KEY_SIZE_DEF}): ${Yellow}"
read JKSTORE_KEY_SIZE
JKSTORE_KEY_SIZE=${JKSTORE_KEY_SIZE:-${JKSTORE_KEY_SIZE_DEF}}
}
PASSWORDS MENU
pw_menu () {
SUB_MENU_TITLE="Passwords Menu"
menu_header
echo -n "${Green} Enter the root password for MariaDB: ${Yellow}"
read MYSQL_PASSWD
MYSQL_PASSWD=${MYSQL_PASSWD:-${MYSQL_PASSWD_DEF}}
echo -n "${Green} Enter the Guacamole DB password: ${Yellow}"
read DB_PASSWD
DB_PASSWD=${DB_PASSWD:-${DB_PASSWD_DEF}}
echo -n "${Green} Enter the Guacamole Java KeyStore password, must be 6 or more characters: ${Yellow}"
read JKS_GUAC_PASSWD
JKS_GUAC_PASSWD=${JKS_GUAC_PASSWD:-${JKS_GUAC_PASSWD_DEF}}
}
SSL CERTIFICATE TYPE MENU
ssl_cert_type_menu () {
SUB_MENU_TITLE="SSL Certificate Type Menu"
menu_header
echo "${Green} What kind of SSL certificate should be used (default 2)?${Yellow}"
PS3="${Green} Enter the number of the desired SSL certificate type: ${Yellow}"
options=("LetsEncrypt" "Self-signed" "None")
select opt in "${options[@]}"
do
case $opt in
"LetsEncrypt") SSL_CERT_TYPE="LetsEncrypt"; le_menu; break;;
"Self-signed"|"") SSL_CERT_TYPE="Self-signed"; ss_menu; break;;
"None")
SSL_CERT_TYPE="None"
OCSP_USE=false
echo -e "\n\n${Red} No SSL certificate selected. This can be configured manually at a later time."
sleep 3
break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing your desired cert type.";;
esac
done
}
LETSENCRYPT MENU
le_menu () {
SUB_MENU_TITLE="LetsEncrypt Menu"
menu_header
echo -n "${Green} Enter a valid e-mail for let's encrypt certificate: ${Yellow}"
read EMAIL_NAME
echo -n "${Green} Enter the Let's Encrypt key-size to use (default ${LE_KEY_SIZE_DEF}): ${Yellow}"
read LE_KEY_SIZE
LE_KEY_SIZE=${LE_KEY_SIZE:-${LE_KEY_SIZE_DEF}}
while true; do
echo -n "${Green} Use OCSP Stapling (default yes): ${Yellow}"
read yn
case $yn in
[Yy]|"" ) OCSP_USE=true; break;;
[Nn] ) OCSP_USE=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
}
SELF-SIGNED SSL CERTIFICATE MENU
ss_menu () {
OCSP_USE=false
SUB_MENU_TITLE="Self-signed SSL Certificate Menu"
menu_header
echo -n "${Green} Enter the Self-Signed SSL key-size to use (default ${SSL_KEY_SIZE_DEF}): ${Yellow}"
read SSL_KEY_SIZE
SSL_KEY_SIZE=${SSL_KEY_SIZE:-${SSL_KEY_SIZE_DEF}}
}
NGINX OPTIONS MENU
nginx_menu () {
SUB_MENU_TITLE="Nginx Menu"
menu_header
Server LAN IP
GUAC_LAN_IP_DEF=$(hostname -I | sed 's/ .*//')
echo -n "${Green} Enter the LAN IP of this server (default ${GUAC_LAN_IP_DEF}): ${Yellow}"
read GUAC_LAN_IP
GUAC_LAN_IP=${GUAC_LAN_IP:-${GUAC_LAN_IP_DEF}}
echo -n "${Green} Enter a valid hostname or public domain such as mydomain.com (default ${DOMAIN_NAME_DEF}): ${Yellow}"
read DOMAIN_NAME
DOMAIN_NAME=${DOMAIN_NAME:-${DOMAIN_NAME_DEF}}
echo -n "${Green} Enter the URI path, starting and ending with / for example /guacamole/ (default ${GUAC_URIPATH_DEF}): ${Yellow}"
read GUAC_URIPATH
GUAC_URIPATH=${GUAC_URIPATH:-${GUAC_URIPATH_DEF}}
Only prompt if SSL will be used
if [ $SSL_CERT_TYPE != "None" ]; then
while true; do
echo -n "${Green} Use only >= 256-bit SSL ciphers (More secure, less compatible. default: yes)?: ${Yellow}"
read yn
case $yn in
[Yy]|"" ) NGINX_SEC=true; break;;
[Nn] ) NGINX_SEC=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
else
NGINX_SEC=false
USE_CSP=false
fi
}
PRIMARY AUTHORIZATION EXTENSIONS MENU
prime_auth_ext_menu () {
SUB_MENU_TITLE="Primary Authentication Extensions Menu"
menu_header
INSTALL_LDAP=false
SECURE_LDAP=false
INSTALL_RADIUS=false
INSTALL_CAS=false
INSTALL_OPENID=false
Allows selection of an authentication method in addition to MariaDB/Database or just MariaDB
which is used to store connection and user meta data for all other methods
echo "${Green} What Guacamole extension should be used as the primary user authentication method (default 1)?${Yellow}"
PS3="${Green} Enter the number of the desired authentication method: ${Yellow}"
Removing non-working options from the menu until they are ready
"RADIUS" "OpenID" "CAS"
options=("MariaDB Database" "LDAP(S)")
COLUMNS=1
select opt in "${options[@]}"
do
case $opt in
"MariaDB Database"|"") PRIME_AUTH_TYPE="MariaDB"; break;;
"LDAP(S)") PRIME_AUTH_TYPE="LDAP"; LDAP_ext_menu; break;;
# "RADIUS") PRIME_AUTH_TYPE="RADIUS"; Radius_ext_menu; break;;
# "OpenID") PRIME_AUTH_TYPE="OpenID"; OpenID_ext_menu; break;;
# "CAS") PRIME_AUTH_TYPE="CAS"; CAS_ext_menu; break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing the desired primary authentication method.";;
esac
done
unset COLUMNS
}
2FA EXTENSIONS MENU
secondary_auth_ext_menu () {
SUB_MENU_TITLE="2FA Extensions Menu"
menu_header
INSTALL_TOTP=false
INSTALL_DUO=false
Allows optional selection of a Two Factor Authentication (2FA) method
echo "${Green} What Guacamole extension should be used as the 2FA authentication method (default 1)?${Yellow}"
PS3="${Green} Enter the number of the desired authentication method: ${Yellow}"
Removing non-working options from the menu until they are ready
"DUO"
options=("None" "TOTP")
COLUMNS=1
select opt in "${options[@]}"
do
case $opt in
"None"|"") TFA_TYPE="None"; break;;
"TOTP") TFA_TYPE="TOTP"; TOTP_ext_menu; break;;
# "DUO") TFA_TYPE="DUO"; Duo_ext_menu; break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing the desired 2FA method.";;
esac
done
unset COLUMNS
}
LDAP MENU
LDAP_ext_menu () {
INSTALL_LDAP=true
SUB_MENU_TITLE="LDAP Extension Menu"
menu_header
Allow selection of LDAPS
while true; do
echo -n "${Green} Use LDAPS instead of LDAP (Requires having the cert from the server copied locally, default: no): ${Yellow}"
read SECURE_LDAP
case $SECURE_LDAP in
[Yy]* ) SECURE_LDAP=true; break;;
[Nn]*|"" ) SECURE_LDAP=false; break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
Check if LDAPS was selected
if [ $SECURE_LDAP = true ]; then
echo -ne "\n${Green} Enter the LDAP Port (default 636): ${Yellow}"
read LDAP_PORT
LDAP_PORT=${LDAP_PORT:-636}
else # Use LDAP not LDAPS
echo -ne "\n${Green} Enter the LDAP Port (default 389): ${Yellow}"
read LDAP_PORT
LDAP_PORT=${LDAP_PORT:-389}
fi
echo -ne "\n${Green} Enter the LDAP Server Hostname (use the FQDN, Ex: ldaphost.domain.com): ${Yellow}"
read LDAP_HOSTNAME
LDAP_HOSTNAME=${LDAP_HOSTNAME:-ldaphost.domain.com}
echo -n "${Green} Enter the LDAP User-Base-DN (Ex: dc=domain,dc=com): ${Yellow}"
read LDAP_BASE_DN
LDAP_BASE_DN=${LDAP_BASE_DN:-dc=domain,dc=com}
echo -n "${Green} Enter the LDAP Search-Bind-DN (Ex: cn=user,ou=Admins,dc=domain,dc=com): ${Yellow}"
read LDAP_BIND_DN
LDAP_BIND_DN=${LDAP_BIND_DN:-cn=user,ou=Admins,dc=domain,dc=com}
echo -n "${Green} Enter the LDAP Search-Bind-Password: ${Yellow}"
read LDAP_BIND_PW
LDAP_BIND_PW=${LDAP_BIND_PW:-password}
echo -n "${Green} Enter the LDAP Username-Attribute (default sAMAccountName): ${Yellow}"
read LDAP_UNAME_ATTR
LDAP_UNAME_ATTR=${LDAP_UNAME_ATTR:-sAMAccountName}
LDAP_SEARCH_FILTER_DEF="(objectClass=*)"
echo -n "${Green} Enter a custom LDAP user search filter (default "${LDAP_SEARCH_FILTER_DEF}"): ${Yellow}"
read LDAP_SEARCH_FILTER
LDAP_SEARCH_FILTER=${LDAP_SEARCH_FILTER:-${LDAP_SEARCH_FILTER_DEF}}
}
TOTP MENU
TOTP_ext_menu () {
INSTALL_TOTP=true
SUB_MENU_TITLE="TOTP Extension Menu"
menu_header
echo -n "${Green} Enter the TOTP issuer (default Apache Guacamole): ${Yellow}"
read TOTP_ISSUER
TOTP_ISSUER=${TOTP_ISSUER:-Apache Guacamole}
echo -n "${Green} Enter the number of digits to use for TOTP (default 6): ${Yellow}"
read TOTP_DIGITS
TOTP_DIGITS=${TOTP_DIGITS:-6}
echo -n "${Green} Enter the TOTP period in seconds (default 30): ${Yellow}"
read TOTP_PER
TOTP_PER=${TOTP_PER:-30}
echo -n "${Green} Enter the TOTP mode (default sha1): ${Yellow}"
read TOTP_MODE
TOTP_MODE=${TOTP_MODE:-sha1}
}
DUO MENU
Duo_ext_menu () {
INSTALL_DUO=false
SUB_MENU_TITLE="DUO Extension Menu"
menu_header
echo "${Red} Duo extension not currently available via this script."
sleep 3
}
RADIUS MENU
Radius_ext_menu () {
INSTALL_RADIUS=false
SUB_MENU_TITLE="RADIUS Extension Menu"
menu_header
echo "${Red} RADIUS extension not currently available via this script."
sleep 3
}
CAS MENU
CAS_ext_menu () {
INSTALL_CAS=false
SUB_MENU_TITLE="CAS Extension Menu"
menu_header
echo "${Red} CAS extension not currently available via this script."
sleep 3
}
OPENID MENU
OpenID_ext_menu () {
INSTALL_OPENID=false
SUB_MENU_TITLE="OpenID Extension Menu"
menu_header
echo "${Red} OpenID extension not currently available via this script."
sleep 3
}
CUSTOM EXTENSION MENU
cust_ext_menu () {
SUB_MENU_TITLE="Custom Extension Menu"
menu_header
while true; do
echo -n "${Green} Would you like to install a custom Guacamole extensions from a local file (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* )
INSTALL_CUST_EXT=true
done
}
######################################################################
SUMMARY MENUS
######################################################################
MAIN SUMMARY MENU
sum_menu () {
SUB_MENU_TITLE="Summary Menu"
menu_header
RUN_INSTALL=false
RET_SUM=false
List categories/menus to review or change
echo "${Green} Select a category to review selections: ${Yellow}"
PS3="${Green} Enter the number of the category to review: ${Yellow}"
options=("Database" "Passwords" "SSL Cert Type" "Nginx" "Primary Authentication Extension" "2FA Extension" "Custom Extension" "Accept and Run Installation" "Cancel and Start Over" "Cancel and Exit Script")
select opt in "${options[@]}"
do
case $opt in
"Database") sum_db; break;;
"Passwords") sum_pw; break;;
"SSL Cert Type") sum_ssl; break;;
"Nginx") sum_nginx; break;;
"Primary Authentication Extension") sum_prime_auth_ext; break;;
"2FA Extension") sum_secondary_auth_ext; break;;
"Custom Extension") sum_cust_ext; break;;
"Accept and Run Installation") RUN_INSTALL=true; break;;
"Cancel and Start Over") ScriptLoc=$(readlink -f "$0"); exec "$ScriptLoc"; break;;
"Cancel and Exit Script") tput sgr0; exit 1; break;;
* ) echo "${Green} ${REPLY} is not a valid option, enter the number representing the category to review.";;
esac
done
}
DATABASE SUMMARY
sum_db () {
SUB_MENU_TITLE="Database Summary"
menu_header
echo "${Green} Guacamole DB name: ${Yellow}${DB_NAME}"
echo "${Green} Guacamole DB username: ${Yellow}${DB_USER}"
echo -e "${Green} Java KeyStore key-size: ${Yellow}${JKSTORE_KEY_SIZE}\n"
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) db_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
PASSWORD SUMMARY
sum_pw () {
SUB_MENU_TITLE="Passwords Summary"
menu_header
echo "${Green} MariaDB root password: ${Yellow}${MYSQL_PASSWD}"
echo "${Green} Guacamole DB password: ${Yellow}${DB_PASSWD}"
echo -e "${Green} Guacamole Java KeyStore password: ${Yellow}${JKS_GUAC_PASSWD}\n"
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) pw_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
SSL CERTIFICATE SUMMARY
sum_ssl () {
SUB_MENU_TITLE="SSL Certificate Summary"
menu_header
echo -e "${Green} Certficate Type: ${Yellow}${SSL_CERT_TYPE}\n"
Check the certificate selection to display proper information for selection
case $SSL_CERT_TYPE in
"LetsEncrypt")
echo "${Green} e-mail for LetsEncrypt certificate: ${Yellow}${EMAIL_NAME}"
echo "${Green} LetEncrypt key-size: ${Yellow}${LE_KEY_SIZE}"
echo -e "${Green} Use OCSP Stapling?: ${Yellow}${OCSP_USE}\n"
;;
"Self-signed")
echo -e "${Green} Self-Signed SSL key-size: ${Yellow}${SSL_KEY_SIZE}\n"
;;
"None")
echo -e "${Yellow} As no certificate type was selected, an SSL certificate can be configured manually at a later time.\n"
;;
esac
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) ssl_cert_type_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
NGINX SUMMARY
sum_nginx () {
SUB_MENU_TITLE="Nginx Summary"
menu_header
echo "${Green} Guacamole Server LAN IP address: ${Yellow}${GUAC_LAN_IP}"
echo "${Green} Guacamole Server hostname or public domain: ${Yellow}${DOMAIN_NAME}"
echo "${Green} URI path: ${Yellow}${GUAC_URIPATH}"
echo "${Green} Using only 256-bit >= ciphers?: ${Yellow}${NGINX_SEC}"
echo -e "${Green} Content-Security-Policy [CSP] enabled?: ${Yellow}${USE_CSP}\n"
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) nginx_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
STANDARD EXTENSIONS SUMMARY
sum_prime_auth_ext () {
SUB_MENU_TITLE="Primary Authentication Extension Summary"
menu_header
echo -e "${Green} Primary Authentication type: ${Yellow}${PRIME_AUTH_TYPE}\n"
echo "${Yellow}${Bold} -- MariaDB is used with all authentication implementations --${Reset}"
echo "${Green} Default Guacamole username: ${Yellow}guacadmin"
echo -e "${Green} Default Guacamole password: ${Yellow}guacadmin\n"
Check the authentication selection to display proper information for the selection
case $PRIME_AUTH_TYPE in
"LDAP")
echo -e "${Reset}${Bold} -- LDAP Specific Parameters --${Reset}\n"
echo "${Green} Use LDAPS instead of LDAP: ${Yellow}${SECURE_LDAP}"
echo -e "${Green} LDAP(S) port: ${Yellow}${LDAP_PORT}\n"
esac
while true; do
echo -n "${Green} Would you like to change the authentication method and properties (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) prime_auth_ext_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
SELECTED EXTENSIONS SUMMARY
sum_secondary_auth_ext () {
SUB_MENU_TITLE="2FA Extension Summary"
menu_header
echo -e "${Green} 2FA selection: ${Yellow}${TFA_TYPE}\n"
Check the authentication selection to display proper information for the selection
case $TFA_TYPE in
"None")
echo -e "${Yellow}${Bold} -- No form of 2FA will be implemented by this script --${Reset}\n"
;;
"TOTP")
echo "${Green} TOTP issuer: ${Yellow}${TOTP_ISSUER}"
echo "${Green} Number of TOTP digits: ${Yellow}${TOTP_DIGITS}"
echo "${Green} TOTP period in seconds: ${Yellow}${TOTP_PER}"
echo -e "${Green} TOTP mode: ${Yellow}${TOTP_MODE}\n"
;;
"DUO")
echo -e "${Red} DUO cannot currently be installed by this script.\n"
;;
esac
while true; do
echo -n "${Green} Would you like to change the 2FA method and properties (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) secondary_auth_ext_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
CUSTOM EXTENSION SUMMARY
sum_cust_ext () {
SUB_MENU_TITLE="Custom Extension Summary"
menu_header
echo -e "${Green} Install a custom Guacamole extension: ${Yellow}${INSTALL_CUST_EXT}\n"
if [ $INSTALL_CUST_EXT = true ]; then
echo "${Green} Filename of the .jar extension file: ${Yellow}${CUST_FN}"
echo "${Green} Full path of the dir containing the .jar extension file: ${Yellow}${CUST_DIR}"
echo -e "${Green} Full file path: ${Yellow}${CUST_FULL}\n"
fi
while true; do
echo -n "${Green} Would you like to change these selections (default no)? ${Yellow}"
read yn
case $yn in
[Yy]* ) cust_ext_menu; break;;
[Nn]*|"" ) break;;
* ) echo "${Green} Please enter yes or no. ${Yellow}";;
esac
done
sum_menu
}
MENU EXECUTION
db_menu
pw_menu
ssl_cert_type_menu
nginx_menu
prime_auth_ext_menu
secondary_auth_ext_menu
cust_ext_menu
sum_menu
Sets file descriptor to 3 for this special echo function and spinner
exec 3>&1
######################################################################
UTILITY FUNCTIONS
######################################################################
PROGRESS SPINNER FUNCTION
Used to show a process is making progress/running
spinner () {$(jobs -p) > "$ {VAR_FILE}"
pid=$!
#Store the background process id in a temp file to use in err_handler
echo
spin[0]="-"
spin[1]="\"
spin[2]="|"
spin[3]="/"
Loop while the process is still running
while kill -0 $pid 2>/dev/null
do
for i in "${spin[@]}"
do
if kill -0 $pid 2>/dev/null; then #Check that the process is running to prevent a full 4 character cycle on error
# Display the spinner in 1/4 states
echo -ne "\b\b\b${Bold}[${Green}$i${Reset}${Bold}]" >&3
sleep .5 # time between each state
else #process has ended, stop next loop from finishing iteration
break
fi
done
done
Check if background process failed once complete
if wait $pid; then # Exit 0
echo -ne "\b\b\b${Bold}[${Green}-done-${Reset}${Bold}]" >&3
else # Any other exit
false
fi
#Set background process id value to -1 representing no background process running to err_handler
echo "-1" > "${VAR_FILE}"
tput sgr0 >&3
}
SPECIAL ECHO FUNCTION
This allows echo to log and stdout (now fd3) while sending all else to log by default via exec
s_echo () {
Use first arg $1 to determine if echo skips a line (yes/no)
Second arg $2 is the message
case $1 in
# No preceeding blank line
[Nn])
echo -ne "\n${2}" | tee -a /dev/fd/3
echo # add new line after in log only
;;
# Preceeding blank line
[Yy]|*)
echo -ne "\n\n${2}" | tee -a /dev/fd/3
echo # add new line after in log only
;;
esac
}
Used to force all stdout and stderr to the log file
s_echo function will be used when echo needs to be displayed and logged
exec &> "${logfile}"
ERROR HANDLER FUNCTION
Called by trap to display/log error info and exit script
err_handler () {
EXITCODE=$?
#Read values from temp file used to store cross process values
F_BG=$(sed -n 1p "${VAR_FILE}")
Check if the temp variable file is greater than 1 line of text
if [$(wc -l < "$ {VAR_FILE}") -gt 1 ]; then
# If so, set variable according to value of the 2nd line in the file.
H_ERR=$(sed -n 2p "${VAR_FILE}")
else # Otherwise, set to false, error was not triggered previously
H_ERR=false
fi
#Check this is the first time the err_handler has triggered
if [ $H_ERR = false ]; then
#Check if error occured with a background process running
if [ $F_BG -gt 0 ]; then
echo -ne "\b\b\b${Bold}[${Red}-FAILED-${Reset}${Bold}]" >&3
fi
fi
Log cleanup to remove escape sequences caused by tput for formatting text
sed -i 's/\x1b[[0-9;]*m|\x1b[(]B\x1b[m//g' ${logfile}
tput sgr0 >&3
exit $EXITCODE
}
CHECK INSTALLED PACKAGE FUNCTION
Query rpm for package without triggering trap when not found
chk_installed () {
if rpm -q "$@"; then
RETVAL=$?
else
RETVAL=$?
fi
}
CHECK REPO ENABLED FUNCTION
Query repos files to view if repo is enabled trigger trap when not enabled
chk_repo_enabled () {
if grep -q "$@"; then
RETVAL=$?
else
RETVAL=$?
fi
}
ERROR TRAP
Trap to call error function to display and log error details
trap err_handler ERR SIGINT SIGQUIT
######################################################################
INSTALLATION
######################################################################
REPOS INSTALLATION
reposinstall () {
s_echo "n" "${Bold} ----==== INSTALLING GUACAMOLE ${GUAC_SOURCE} ${GUAC_VER} ====----"
s_echo "y" "Installing Repos and mandatory software"
Install wget
chk_installed "wget"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "${Reset}-WGET is installed."
else
{ yum -y install wget; } &
s_echo "n" "${Reset}-WGET is missing. Installing... "; spinner
fi
Install make
chk_installed "make"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "${Reset}-MAKE is installed."
else
{ yum -y install make; } &
s_echo "n" "${Reset}-MAKE is missing. Installing... "; spinner
fi
Install EPEL Repo
chk_installed "epel-release"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "${Reset}-EPEL is installed."
else
{ rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-${MAJOR_VER}.noarch.rpm; } &
s_echo "n" "${Reset}-EPEL is missing. Installing... "; spinner
fi
Install RPMFusion Repo
chk_installed "rpmfusion-free-release"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "-RPMFusion is installed."
else
{ rpm -Uvh https://download1.rpmfusion.org/free/el/rpmfusion-free-release-${MAJOR_VER}.noarch.rpm; } &
s_echo "n" "-RPMFusion is missing. Installing... "; spinner
fi
Install RPMFusion nonfree Repo
chk_installed "rpmfusion-nonfree-release"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "-RPMFusion nonfree is installed."
else
{ rpm -Uvh https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-${MAJOR_VER}.noarch.rpm; } &
s_echo "n" "-RPMFusion is missing. Installing... "; spinner
fi
Install harbottle.gitlab Repo neede for tomcat9
chk_installed "harbottle-main-release"
if [ $RETVAL -eq 0 ]; then
s_echo "n" "-harbottle is installed."
else
{ rpm -Uvh https://harbottle.gitlab.io/harbottle-main/${MAJOR_VER}/x86_64/harbottle-main-release.rpm; } &
s_echo "n" "-harbottle is missing. Installing... "; spinner
fi
Check if powertool repo is enabled
chk_repo_enabled "enabled=1" /etc/yum.repos.d/almalinux-powertools.repo
if [ $RETVAL -eq 0 ]; then
s_echo "n" "-Powertools enabled."
else
{ dnf config-manager --enable powertools; } &
s_echo "n" "-PowerTools was not enabled, enabled "; spinner
fi
Install Nginx Repo
{ echo "[nginx-stable]
name=Nginx Stable Repo
baseurl=${NGINX_URL}
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true" > /etc/yum.repos.d/nginx.repo; } &
s_echo "n" "${Reset}-Installing Nginx repo... "; spinner
Install libjpeg-turbo Repo
{
yum install -y wget
wget ${LIBJPEG_REPO} -P /etc/yum.repos.d/
} &
s_echo "n" "-Installing libjpeg-turbo repo... "; spinner
Enable repos needed if using RHEL
if [ $OS_NAME == "RHEL" ] ; then
{ subscription-manager repos --enable "rhel--optional-rpms" --enable "rhel--extras-rpms"; } &
s_echo "n" "-Enabling ${OS_NAME} optional and extras repos... "; spinner
fi
yumupdate
}
YUM UPDATES
yumupdate () {
Update OS/packages
{ yum update -y; } &
s_echo "y" "${Bold}Updating ${OS_NAME}, please wait... "; spinner
baseinstall
}
INSTALL BASE PACKAGES
baseinstall () {
s_echo "y" "${Bold}Installing Required Dependencies"
Install Required Packages
{
yum install -y cairo-devel ffmpeg-devel freerdp-devel freerdp-plugins gcc gnu-free-mono-fonts make libjpeg-turbo-devel libjpeg-turbo-official libpng-devel libssh2-devel libtelnet-devel libvncserver-devel libvorbis-devel libwebp-devel libwebsockets-devel mariadb mariadb-server nginx openssl-devel pango-devel policycoreutils-python-utils pulseaudio-libs-devel setroubleshoot ${TOMCAT_VER} uuid-devel
} &
s_echo "n" "${Reset}-Installing required packages... "; spinner
Additional packages required by git
if [ $GUAC_SOURCE == "Git" ]; then
{ yum install -y git libtool java-1.8.0-openjdk-devel; } &
s_echo "n" "-Installing packages required for git... "; spinner
fi
createdirs
}
CREATE DIRECTORIES
createdirs () {
{
rm -fr ${INSTALL_DIR}
mkdir -vp /etc/guacamole
mkdir -vp ${INSTALL_DIR}{client,selinux}
mkdir -vp ${LIB_DIR}{extensions,lib}
mkdir -vp /usr/share/${TOMCAT_VER}/.guacamole/
} &
s_echo "y" "${Bold}Creating Required Directories... "; spinner
cd ${INSTALL_DIR}
downloadguac
}
DOWNLOAD GUACAMOLE
downloadguac () {
s_echo "y" "${Bold}Downloading Guacamole Packages"
if [ $GUAC_SOURCE == "Git" ]; then
{ git clone ${GUAC_URL}${GUAC_SERVER}; } &
s_echo "n" "${Reset}-Cloning Guacamole Server package from git... "; spinner
{ git clone ${GUAC_URL}${GUAC_CLIENT}; } &
s_echo "n" "-Cloning Guacamole Client package from git... "; spinner
downloadmysqlconn
else # Stable release
{ wget "${GUAC_URL}source/${GUAC_SERVER}.tar.gz" -O ${GUAC_SERVER}.tar.gz; } &
s_echo "n" "${Reset}-Downloading Guacamole Server package for installation... "; spinner
{ wget "${GUAC_URL}binary/${GUAC_CLIENT}.war" -O ${INSTALL_DIR}client/guacamole.war; } &
s_echo "n" "-Downloading Guacamole Client package for installation... "; spinner
{ wget "${GUAC_URL}binary/${GUAC_JDBC}.tar.gz" -O ${GUAC_JDBC}.tar.gz; } &
s_echo "n" "-Downloading Guacamole JDBC Extension package for installation... "; spinner
downloadmysqlconn
fi
{
tar xzvf ${MYSQL_CON}.tar.gz
rm -f ${MYSQL_CON}.tar.gz
mv -v ${MYSQL_CON}/${MYSQL_CON}.jar ${LIB_DIR}lib/
} &
s_echo "n" "-Decompressing MySQL Connector... "; spinner
installguacserver
}
INSTALL GUACAMOLE SERVER
installguacserver () {
s_echo "y" "${Bold}Install Guacamole Server"
if [ $GUAC_SOURCE == "Git" ]; then
cd guacamole-server/
{ autoreconf -fi; } &
s_echo "n" "${Reset}-Guacamole Server compile prep... "; spinner
else # Stable release
cd server
fi
Compile Guacamole Server
{ ./configure --with-systemd-dir=/usr/lib/systemd/system/; } &
s_echo "n" "${Reset}-Compiling Guacamole Server Stage 1 of 4... "; spinner
{ make; } &
s_echo "n" "-Compiling Guacamole Server Stage 2 of 4... "; spinner
{ make install; } &
s_echo "n" "-Compiling Guacamole Server Stage 3 of 4... "; spinner
{ ldconfig; } &
s_echo "n" "-Compiling Guacamole Server Stage 4 of 4... "; spinner
cd ..
installguacclient
}
INSTALL GUACAMOLE CLIENT
installguacclient () {
s_echo "y" "${Bold}Install Guacamole Client"
if [ $GUAC_SOURCE == "Git" ]; then
cd guacamole-client/
{ mvn package; } &
s_echo "n" "${Reset}-Compiling Guacamole Client... "; spinner
else # Stable release
{ mv -v client/guacamole.war ${LIB_DIR}guacamole.war; } &
s_echo "n" "${Reset}-Moving Guacamole Client... "; spinner
fi
finishguac
}
FINALIZE GUACAMOLE INSTALLATION
finishguac () {
s_echo "y" "${Bold}Setup Guacamole"
Generate Guacamole Configuration File
{ echo "# Hostname and port of guacamole proxy
guacd-hostname: localhost
guacd-port: ${GUAC_PORT}
MySQL properties
mysql-hostname: localhost
mysql-port: ${MYSQL_PORT}
mysql-database: ${DB_NAME}
mysql-username: ${DB_USER}
mysql-password: ${DB_PASSWD}
mysql-default-max-connections-per-user: 0
mysql-default-max-group-connections-per-user: 0" > /etc/guacamole/${GUAC_CONF}; } &
s_echo "n" "${Reset}-Generating Guacamole configuration file... "; spinner
Create Required Symlinks for Guacamole
{
ln -vfs ${LIB_DIR}guacamole.war /var/lib/${TOMCAT_VER}/webapps
ln -vfs /etc/guacamole/${GUAC_CONF} /usr/share/${TOMCAT_VER}/.guacamole/
ln -vfs ${LIB_DIR}lib/ /usr/share/${TOMCAT_VER}/.guacamole/
ln -vfs ${LIB_DIR}extensions/ /usr/share/${TOMCAT_VER}/.guacamole/
ln -vfs /usr/local/lib/freerdp/guac* /usr/lib${ARCH}/freerdp
} &
s_echo "n" "-Making required symlinks... "; spinner
Copy JDBC if using git
if [ $GUAC_SOURCE == "Git" ]; then
# Get JDBC from compiled client
{ find ./guacamole-client/extensions -name "guacamole-auth-jdbc-mysql-${GUAC_VER}.jar" -exec mv -v {} ${LIB_DIR}extensions/ ;; } &
s_echo "n" "-Moving Guacamole JDBC extension to extensions dir... "; spinner
fi
Setup guacd user, group and permissions
{
# Create a user and group for guacd with a home folder but no login
groupadd ${GUACD_USER}
# The guacd user is created as a service account, no login but does get a home dir as needed by freerdp
useradd -r ${GUACD_USER} -m -s "/bin/nologin" -g ${GUACD_USER} -c ${GUACD_USER}
} &
s_echo "n" "-Setup guacd user... "; spinner
appconfigs
}
DATABASE/TOMCAT/JKS SETUP
appconfigs () {
s_echo "y" "${Bold}Configure MariaDB"
Enable/Start MariaDB/MySQL Service
{
systemctl enable mariadb.service
systemctl restart mariadb.service
} &
s_echo "n" "${Reset}-Enable & start MariaDB service... "; spinner
Set MariaDB/MySQL Root Password
{ mysqladmin -u root password ${MYSQL_PASSWD}; } &
s_echo "n" "-Setting root password for MariaDB... "; spinner
Run MariaDB/MySQL Secure Install
{
mysql_secure_installation <<EOF
${MYSQL_PASSWD}
n
y
y
y
y
EOF
} &
s_echo "n" "-Harden MariaDB... "; spinner
Create Database and user
{
mysql -u root -p${MYSQL_PASSWD} -e "CREATE DATABASE ${DB_NAME};"
mysql -u root -p${MYSQL_PASSWD} -e "GRANT SELECT,INSERT,UPDATE,DELETE ON ${DB_NAME}.* TO '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASSWD}';"
mysql -u root -p${MYSQL_PASSWD} -e "FLUSH PRIVILEGES;"
} &
s_echo "n" "-Creating Database & User for Guacamole... "; spinner
Create Guacamole Table
{
if [ $GUAC_SOURCE == "Git" ]; then
cat guacamole-client/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/.sql | mysql -u root -p${MYSQL_PASSWD} -D ${DB_NAME}
else # Stable release
cat extension/mysql/schema/.sql | mysql -u root -p${MYSQL_PASSWD} -D ${DB_NAME}
fi
} &
s_echo "n" "-Creating Guacamole Tables... "; spinner
Populate mysql database with time zones from system
Fixes timezone issues when using MySQLConnectorJ 8.x or geater
{
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p${MYSQL_PASSWD}
MY_CNF_LINE=
grep -n "\[mysqld\]" /etc/my.cnf.d/mariadb-server.cnf | grep -o '^[0-9]*'
# MY_CNF_LINE=
grep -n "\[mysqld\]" /etc/my.cnf | grep -o '^[0-9]*'
MY_CNF_LINE=$((MY_CNF_LINE + 1 ))
MY_TZ=
readlink /etc/localtime | sed "s/.*\/usr\/share\/zoneinfo\///"
sed -i "${MY_CNF_LINE}i default-time-zone='${MY_TZ}'" /etc/my.cnf.d/mariadb-server.cnf
systemctl restart mariadb
} &
s_echo "n" "-Setting Time Zone Database & Config... "; spinner
Setup Tomcat
s_echo "y" "${Bold}Setup Tomcat Server"
{
sed -i '72i URIEncoding="UTF-8"' /etc/${TOMCAT_VER}/server.xml
sed -i '92i <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/var/lib/${TOMCAT_VER}/webapps/.keystore"
keystorePass="JKS_GUAC_PASSWD"
URIEncoding="UTF-8" />' /etc/${TOMCAT_VER}/server.xml
sed -i "s/JKS_GUAC_PASSWD/${JKS_GUAC_PASSWD}/g" /etc/${TOMCAT_VER}/server.xml
} &
s_echo "n" "${Reset}-Base Tomcat configuration... "; spinner
{
Tomcat RemoteIpValve (to pass remote host IP's from proxy to tomcat. Allows Guacamole to log remote host IPs)
} &
s_echo "n" "-Set RemoteIpValve in Tomcat configuration... "; spinner
{
Add ErrorReportingValve to prevent displaying tomcat info on error pages
} &
s_echo "n" "-Set ErrorReportingVavle in ${TOMCAT_VER}n... "; spinner
Java KeyStore Setup
{ keytool -genkey -alias Guacamole -keyalg RSA -keysize ${JKSTORE_KEY_SIZE} -keystore /var/lib/${TOMCAT_VER}/webapps/.keystore -storepass ${JKS_GUAC_PASSWD} -keypass ${JKS_GUAC_PASSWD} -noprompt -dname "CN='', OU='', O='', L='', S='', C=''"; } &
s_echo "y" "${Bold}Configuring the Java KeyStore... "; spinner
Enable/Start Tomcat and Guacamole Services
{
systemctl enable ${TOMCAT_VER}
systemctl restart ${TOMCAT_VER}
systemctl enable guacd
systemctl restart guacd
} &
s_echo "y" "${Bold}Enable & Start Tomcat and Guacamole Services... "; spinner
nginxcfg
}
NGINX CONFIGURATION
nginxcfg () {
s_echo "y" "${Bold}Nginx Configuration"
Backup Nginx Configuration
{ mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.ori.bkp; } &
s_echo "n" "${Reset}-Making Nginx config backup... "; spinner
HTTP Nginx Conf
{ echo "server {
listen 80;
listen [::]:80;
server_name ${DOMAIN_NAME};
return 301 https://$host$request_uri;
}" > /etc/nginx/conf.d/guacamole.conf
} &
s_echo "n" "${Reset}-Generate Nginx guacamole.config... "; spinner
HTTPS/SSL Nginx Conf
{
echo "server {
#listen 443 ssl http2 default_server;
#listen [::]:443 ssl http2 default_server;
server_name ${DOMAIN_NAME};
server_tokens off;
#ssl_certificate guacamole.crt;
#ssl_certificate_key guacamole.key; " > /etc/nginx/conf.d/guacamole_ssl.conf
} &
s_echo "n" "-Generate Nginx guacamole_ssl.config... "; spinner
Nginx CIS hardening v1.0.0
{
# 2.3.2 Restrict access to Nginx files
find /etc/nginx -type d | xargs chmod 750
find /etc/nginx -type f | xargs chmod 640
} &
s_echo "n" "-Hardening Nginx config... "; spinner
Enable/Start Nginx Service
{
systemctl enable nginx
systemctl restart nginx
} &
s_echo "n" "-Enable & Start Nginx Service... "; spinner
Call each Guac extension function for those selected
if [ $INSTALL_LDAP = true ]; then ldapsetup; fi
if [ $INSTALL_TOTP = true ]; then totpsetup; fi
if [ $INSTALL_DUO = true ]; then duosetup; fi
if [ $INSTALL_RADIUS = true ]; then radiussetup; fi
if [ $INSTALL_CAS = true ]; then cassetup; fi
if [ $INSTALL_OPENID = true ]; then openidsetup; fi
if [ $INSTALL_CUST_EXT = true ]; then custsetup; fi
selinuxsettings
}
LDAP SETUP
ldapsetup () {
s_echo "y" "${Bold}Setup the LDAP Extension"
Append LDAP configuration lines to guacamole.properties
{ echo "
LDAP properties
ldap-hostname: ${LDAP_HOSTNAME}
ldap-port: ${LDAP_PORT}" >> /etc/guacamole/${GUAC_CONF}; } &
s_echo "n" "${Reset}-Updating guacamole.properties file for LDAP... "; spinner
LDAPS specific properties
if [ $SECURE_LDAP = true ]; then
{
KS_PATH=$(find "/usr/lib/jvm/" -name "cacerts")
keytool -storepasswd -new ${JKS_CACERT_PASSWD} -keystore ${KS_PATH} -storepass "changeit"
keytool -importcert -alias "ldaps" -keystore ${KS_PATH} -storepass ${JKS_CACERT_PASSWD} -file ${LDAPS_CERT_FULL} -noprompt
fi
Finish appending general LDAP configuration lines to guacamole.properties
{ echo "ldap-user-base-dn: ${LDAP_BASE_DN}
ldap-search-bind-dn: ${LDAP_BIND_DN}
ldap-search-bind-password: ${LDAP_BIND_PW}
ldap-username-attribute: ${LDAP_UNAME_ATTR}
ldap-user-search-filter: ${LDAP_SEARCH_FILTER}
mysql-auto-create-accounts: true" >> /etc/guacamole/${GUAC_CONF}; } &
s_echo "n" "-Finishing updates to the guacamole.properties file for LDAP... "; spinner
if [ $GUAC_SOURCE == "Git" ]; then
# Copy LDAP Extension to Extensions Directory
{ find ./guacamole-client/extensions -name "${GUAC_LDAP}.jar" -exec mv -v {} ${LIB_DIR}extensions/ ;; } &
s_echo "n" "-Moving Guacamole LDAP extension to extensions dir... "; spinner
else # Stable release
# Download LDAP Extension
{ wget "${GUAC_URL}binary/${GUAC_LDAP}.tar.gz" -O ${GUAC_LDAP}.tar.gz; } &
s_echo "n" "-Downloading LDAP extension... "; spinner
fi
}
TOTP SETUP
totpsetup () {
s_echo "y" "${Bold}Setup the TOTP Extension"
Append TOTP configuration lines to guacamole.properties
{ echo "
TOTP properties
totp-issuer: ${TOTP_ISSUER}
totp-digits: ${TOTP_DIGITS}
totp-period: ${TOTP_PER}
totp-mode: ${TOTP_MODE}" >> /etc/guacamole/${GUAC_CONF}; } &
s_echo "n" "${Reset}-Updating guacamole.properties file for TOTP... "; spinner
if [ $GUAC_SOURCE == "Git" ]; then
Copy TOTP Extension to Extensions Directory
{ find ./guacamole-client/extensions -name "${GUAC_TOTP}.jar" -exec mv -v {} ${LIB_DIR}extensions/ ;; } &
s_echo "n" "-Moving Guacamole TOTP extension to extensions dir... "; spinner
else # Stable release
Download TOTP Extension
{ wget "${GUAC_URL}binary/${GUAC_TOTP}.tar.gz" -O ${GUAC_TOTP}.tar.gz; } &
s_echo "n" "-Downloading TOTP extension... "; spinner
Decompress TOTP Extension
{
tar xzvf ${GUAC_TOTP}.tar.gz
rm -f ${GUAC_TOTP}.tar.gz
mv ${GUAC_TOTP} extension
} &
s_echo "n" "-Decompressing Guacamole TOTP Extension... "; spinner
Copy TOTP Extension to Extensions Directory
{ mv -v extension/${GUAC_TOTP}/${GUAC_TOTP}.jar ${LIB_DIR}extensions/; } &
s_echo "n" "-Moving Guacamole TOTP extension to extensions dir... "; spinner
fi
}
DUO SETUP
duosetup () {
# Placehold until extension is added
echo "duosetup"
}
RADIUS SETUP
radiussetup () {
# Placehold until extension is added
echo "radiussetup"
}
CAS SETUP
cassetup () {
# Placehold until extension is added
echo "cassetup"
}
OpenID SETUP
openidsetup () {
# Placehold until extension is added
echo "openidsetup"
}
CUSTOM EXTENSION SETUP
custsetup () {
Copy Custom Extension to Extensions Directory
{ mv -v ${CUST_FULL} ${LIB_DIR}extensions/; } &
s_echo "y" "${Bold}Copying Custom Guacamole Extension to Extensions Dir... "; spinner
}
SELINUX SETTINGS
selinuxsettings () {
{
# Set Booleans
setsebool -P httpd_can_network_connect 1
setsebool -P httpd_can_network_relay 1
setsebool -P tomcat_can_network_connect_db 1
} &
s_echo "y" "${Bold}Setting SELinux Context... "; spinner
Log SEL status
sestatus
firewallsettings
}
FIREWALL SETTINGS
firewallsettings () {
s_echo "y" "${Bold}Firewall Configuration"
chk_installed "firewalld"
Ensure firewalld is enabled and started
{
if [ $RETVAL -eq 0 ]; then
systemctl enable firewalld
systemctl restart firewalld
fi
} &
s_echo "n" "${Reset}-firewalld is installed and started on the system... "; spinner
Backup firewall public zone config
{ cp /etc/firewalld/zones/public.xml $fwbkpfile; } &
s_echo "n" "-Backing up firewall public zone to: $fwbkpfile "; spinner
Open HTTP and HTTPS ports
{
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-service=http"
firewall-cmd --permanent --zone=public --add-service=http
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-service=https"
firewall-cmd --permanent --zone=public --add-service=https
} &
s_echo "n" "-Opening HTTP and HTTPS service ports... "; spinner
Open 8080 and 8443 ports. Need to review if this is required or not
{
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-port=8080/tcp"
firewall-cmd --permanent --zone=public --add-port=8080/tcp
echo -e "Add new rule...\nfirewall-cmd --permanent --zone=public --add-port=8443/tcp"
firewall-cmd --permanent --zone=public --add-port=8443/tcp
} &
s_echo "n" "-Opening ports 8080 and 8443 on TCP... "; spinner
#echo -e "Reload firewall...\nfirewall-cmd --reload\n"
{ firewall-cmd --reload; } &
s_echo "n" "-Reloading firewall... "; spinner
sslcerts
}
SSL CERTIFICATE
sslcerts () {
s_echo "y" "${Bold}SSL Certificate Configuration"
if [ $SSL_CERT_TYPE != "None" ]; then
# Lets Encrypt Setup (If selected)
if [ $SSL_CERT_TYPE = "LetsEncrypt" ]; then
# Install certbot from repo
{ yum install -y certbot python2-certbot-nginx; } &
s_echo "n" "${Reset}-Downloading certboot tool... "; spinner
else # Cert is set to None
s_echo "n" "${Reset}-No SSL Cert selected..."
fi
showmessages
}
COMPLETION MESSAGES
showmessages () {
s_echo "y" "${Bold}Services"
Restart all services and log status
{
systemctl restart ${TOMCAT_VER}
systemctl status ${TOMCAT_VER}
systemctl restart guacd
systemctl status guacd
systemctl restart mariadb
systemctl status mariadb
systemctl restart nginx
systemctl status nginx
} &
s_echo "n" "${Reset}-Restarting all services... "; spinner
Completion messages
s_echo "y" "${Bold}${Green}##### Installation Complete! #####${Reset}"
s_echo "y" "${Bold}Log Files"
s_echo "n" "${Reset}-Log file: ${logfile}"
s_echo "n" "-firewall backup file: ${fwbkpfile}"
Determine Guac server URL for web GUI
if [ ${DOMAIN_NAME} = "localhost" ]; then
GUAC_URL=${GUAC_LAN_IP}${GUAC_URIPATH}
else # Not localhost
GUAC_URL=${DOMAIN_NAME}${GUAC_URIPATH}
fi
Determine if HTTPS is used or not
if [ ${HTTPS_ENABLED} = true ]; then
HTTPS_MSG="${Reset} or ${Bold}https://${GUAC_URL}${Reset}"
else # HTTPS not used
HTTPS_MSG="${Reset}. Without a cert, HTTPS is not forced/available."
fi
Manage Guac
s_echo "y" "${Bold}To manage Guacamole"
s_echo "n" "${Reset}-go to: ${Bold}http://${GUAC_URL}${HTTPS_MSG}"
s_echo "n" "-The default username and password are: ${Red}guacadmin"
Recommendations
s_echo "y" "Important Recommendations${Reset}"
if [ $INSTALL_LDAP = false ]; then
s_echo "n" "-It is highly recommended to create an admin account in Guacamole and delete/disable the default asap!"
else
s_echo "n" "-You should assign at least one AD/LDAP user to have full admin, see the directions on how-to at:"
s_echo "n" "${Green} https://github.com/Zer0CoolX/guacamole-install-rhel-7/wiki/LDAP-or-LDAPS-Authentication#important-manual-steps${Reset}"
s_echo "n" "-Afterwards, it is highly recommended to delete/disable the default admin account and/or create a uniquely named local admin account asap!"
fi
s_echo "y" "${Green}While not technically required, you should consider a reboot after verifying installation${Reset}"
s_echo "y" "${Bold}Contact ${Reset}${ADM_POC}${Bold} with any questions or concerns regarding this script\n"
Log cleanup to remove escape sequences caused by tput for formatting text
sed -i 's/\x1b[[0-9;]*m|\x1b[(]B\x1b[m//g' ${logfile}
tput sgr0 >&3
}
INSTALLATION EXECUTION
Runs the install if the option was selected from the summary menu
if [ ${RUN_INSTALL} = true ]; then
tput sgr0 >&3
clear >&3
reposinstall
if [ $DEL_TMP_VAR = true ]; then
rm "$VAR_FILE"
fi
exit 0
fi
`
You can see parts where i added fwe things to allow running into AlmaLinux 8
Hope it helps
Bye!
The text was updated successfully, but these errors were encountered: