#!/bin/bash ####################################################################################################################### # Guacamole MySQL backend install script. (For split DB and guacamole application layers. # For Ubuntu / Debian / Raspbian # David Harrop # September 2023 ####################################################################################################################### # This script is for separating the Guacamole architecture into a scaled out three tiered system. # Layer 1 = DATABASE - This script # Layer 2 = GUAC SERVER & APPLICATION - use the main setup script, and select remote MYSQL DB option. # Layer 3 = FRONT END REV PROXY (Potentially load balanced & HA) - Up to you! ####################################################################################################################### # Script pre-flight checks and settings ############################################################################### ####################################################################################################################### clear # Prepare text output colours GREY='\033[0;37m' DGREY='\033[0;90m' GREYB='\033[1;37m' LRED='\033[0;91m' LGREEN='\033[0;92m' LYELLOW='\033[0;93m' NC='\033[0m' #No Colour # Check if user is root or sudo if ! [[ $(id -u) = 0 ]]; then echo echo -e "${LRED}Please run this script as sudo or root${NC}" 1>&2 exit 1 fi # Check to see if any previous version of build/install files exist, if so stop and check to be safe. if [[ "$(find . -maxdepth 1 \( -name 'guacamole-*' -o -name 'mysql-connector-j-*' \))" != "" ]]; then echo echo -e "${LRED}Possible previous install files detected. Please review and remove old guacamole install files before proceeding.${GREY}" 1>&2 echo exit 1 fi ####################################################################################################################### # Initial environment setup ########################################################################################### ####################################################################################################################### #Setup download and temp directory paths USER_HOME_DIR=$(eval echo ~${SUDO_USER}) DOWNLOAD_DIR=$USER_HOME_DIR/guac-setup # Setup directory locations mkdir -p $DOWNLOAD_DIR chown -R $SUDO_USER:root $DOWNLOAD_DIR # Version of Guacamole auth jdbc database schema to use GUAC_VERSION="1.5.5" # Set preferred Apache CDN download link) GUAC_SOURCE_LINK="http://apache.org/dyn/closer.cgi?action=download&filename=guacamole/${GUAC_VERSION}" # Install log Location INSTALL_LOG="${DOWNLOAD_DIR}/mysql_install.log" clear # Script branding header echo echo -e "${GREYB}Guacamole Backend MySQL Setup." echo -e " ${LGREEN}Powered by Itiligent" echo echo ####################################################################################################################### # Setup options. ###################################################################################################### ####################################################################################################################### BACKEND_MYSQL="true" # True: For separated MySQL layer. False/blank: Add MySQL to existing guac server (replace XML user map) FRONTEND_NET="" # IPs guac server can login from. Blank = any IP or wildcard 192.168.1.% (ignored if BACKEND_SQL="false") MYSQL_BIND_ADDR="0.0.0.0" # Binds MySQL instance to this IP. (127.0.0.1, a specific IP or 0.0.0.0) (ignored if BACKEND_SQL="false") SECURE_MYSQL="true" # Apply the mysql secure configuration tool (true/false) MYSQL_PORT="3306" # Default is 3306 GUAC_DB="guacamole_db" # Default is guacamole_db GUAC_USER="guacamole_user" # Default is guacamole_user GUAC_PWD="test" # Requires an entry MYSQL_ROOT_PWD="test" # Requires an entry. DB_TZ=$(cat /etc/timezone) # Typically system default (cat /etc/timezone) or change to "UTC" if required. MYSQL_VERSION="" # Blank "" will use distro default MySQL packages. Enter a specific MySQL version for official Maria repo eg. 11.1.2. See https://mariadb.org/mariadb/all-releases/ for available versions. # For a remotely accessed back end DB instance, keep this script set to BACKEND_MYSQL="true". # Other options are fairly straight forward. For a typical back end server only the $FRONTEND_NET and $MYSQL_BIND_ADDR # values may need closer attention. # This script can also accommodate DR or migration scenarios: E.g Migration away from XML user mappings, PostGres to MySQL etc). # To install a new MySQL database on the same server as the Guacamole application, set BACKEND_MYSQL="false" & # MYSQL_BIND_ADDR="127.0.0.1". See bottom of this script for some remaining DB migration actions. ####################################################################################################################### # Start install actions ############################################################################################## ####################################################################################################################### # Standardise on a lexicon for the different MySQL package options if [[ -z "${MYSQL_VERSION}" ]]; then # Use Linux distro default version. MYSQLPKG="default-mysql-server default-mysql-client mysql-common" DB_CMD="mysql" # mysql command is depricated else # Use official mariadb.org repo MYSQLPKG="mariadb-server mariadb-client mariadb-common" DB_CMD="mariadb" # mysql command is depricated on newer versions fi # Update everything but don't do the annoying prompts during apt installs echo -e "${GREY}Updating base Linux OS..." export DEBIAN_FRONTEND=noninteractive apt-get update -qq &>>${INSTALL_LOG} apt-get upgrade -qq -y &>>${INSTALL_LOG} if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed. See ${INSTALL_LOG}${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi cd $DOWNLOAD_DIR # Add the official MariaDB repo if [[ -n "${MYSQL_VERSION}" ]]; then apt-get -qq -y install curl gnupg2 &>>${INSTALL_LOG} curl -LsS -O https://downloads.mariadb.com/MariaDB/mariadb_repo_setup &>>${INSTALL_LOG} bash mariadb_repo_setup --mariadb-server-version=$MYSQL_VERSION &>>${INSTALL_LOG} fi # Download and extract the Guacamole SQL authentication extension containing the database schema echo -e "${GREY}Downloading Guacamole database source files..." wget -q --show-progress -O guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz ${GUAC_SOURCE_LINK}/binary/guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed to download guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz" 1>&2 echo -e "${GUAC_SOURCE_LINK}/binary/guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz" exit 1 else tar -xzf guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz fi echo -e "${LGREEN}Downloaded guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz${GREY}" echo echo -e "${GREY}Installing MySQL packages..." apt-get -qq -y install ${MYSQLPKG} &>>${INSTALL_LOG} if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed. See ${INSTALL_LOG}${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Set the MySQL root password without a reliance on debconf (may not be present in all distros). echo -e "${GREY}Setting MySQL root password..." SQLCODE=" FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '$MYSQL_ROOT_PWD';" echo ${SQLCODE} | $DB_CMD -u root if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed. See ${INSTALL_LOG}${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # A simple method to find the correct file containing the default MySQL timezone setting from a potential list of candidates. # and then update that timzone value. Add to this array if your distro uses a different path to the .cnf contaiing the default_time_zone value. for x in /etc/mysql/mariadb.conf.d/50-server.cnf \ /etc/mysql/mysql.conf.d/mysqld.cnf \ /etc/mysql/my.cnf; do # Check inside each candidate to see if a [mysqld] or [mariadbd] section exists, assign $x the correct filename. if [[ -e "${x}" ]]; then if grep -qE '^\[(mysqld|mariadbd)\]$' "${x}"; then mysqlconfig="${x}" # Reduce any duplicated section names, then sanitise the [ ] special characters for sed below) config_section=$(grep -m 1 -E '^\[(mysqld|mariadbd)\]$' "${x}" | sed 's/\[\(.*\)\]/\1/') break fi fi done # Set the MySQL Timezone if [[ -z "${mysqlconfig}" ]]; then echo -e "${GREY}Couldn't detect MySQL config file - you will need to manually configure database timezone settings" else # Is there already a timzeone value configured? if grep -q "^default_time_zone[[:space:]]=" "${mysqlconfig}"; then echo -e "MySQL database timezone defined in ${mysqlconfig}" else timezone=${DB_TZ} if [[ -z "${DB_TZ}" ]]; then echo -e "Couldn't find system timezone, using UTC$" timezone="UTC" fi echo -e "Setting MySQL database timezone as ${timezone}${GREY}" mysql_tzinfo_to_sql /usr/share/zoneinfo 2>/dev/null | ${DB_CMD} -u root -D mysql -p${MYSQL_ROOT_PWD} # Add the timzone value to the sanitsed server file section name. sed -i -e "/^\[${config_section}\]/a default_time_zone = ${timezone}" "${mysqlconfig}" fi fi if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Establish the appropriate form of Guacamole user account access (remote or localhost login permissions) echo -e "${GREY}Setting up database access parameters for the Guacamole user ..." if [[ "${BACKEND_MYSQL}" = true ]] && [[ -z "${FRONTEND_NET}" ]]; then echo -e "${LYELLOW}${GUAC_USER} is set to accept db logins from any host, you may wish to limit this to specific IPs.${GREY}" GUAC_USERHost="%" # Allow guacamole access from all IPs where $FRONTEND_NET is left blank elif [[ "${BACKEND_MYSQL}" = true ]] && [[ -n "${FRONTEND_NET}" ]]; then echo -e "${LYELLOW}${GUAC_USER} is set to accept db logins from ${FRONTEND_NET}.${GREY}" GUAC_USERHost="${FRONTEND_NET}" # Allow guacamole access from the given value in $FRONTEND_NET elif [[ "${BACKEND_MYSQL}" = false ]] || [[ -z "${BACKEND_MYSQL}" ]]; then echo -e "${LYELLOW}${GUAC_USER} is set to accept db logins from localhost only.${GREY}" GUAC_USERHost=localhost # Assume a localhost only install MYSQL_BIND_ADDR="127.0.0.1" else echo -e "${LYELLOW}${GUAC_USER} is set to accept db logins from localhost only.${GREY}" GUAC_USERHost=localhost # Assume a localhost only install fi if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Set the MySQL binding IP address according to setup variables given. echo -e "${GREY}Setting MySQL IP address binding to ${MYSQL_BIND_ADDR}..." sed -i "s/^bind-address[[:space:]]*=[[:space:]]*.*/bind-address = ${MYSQL_BIND_ADDR}/g" ${mysqlconfig} if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Create the new Guacamole database echo -e "${GREY}Creating the Guacamole database..." SQLCODE=" DROP DATABASE IF EXISTS ${GUAC_DB}; CREATE DATABASE IF NOT EXISTS ${GUAC_DB}; CREATE USER IF NOT EXISTS '${GUAC_USER}'@'${GUAC_USERHost}' IDENTIFIED BY \"${GUAC_PWD}\"; GRANT SELECT,INSERT,UPDATE,DELETE ON ${GUAC_DB}.* TO '${GUAC_USER}'@'${GUAC_USERHost}'; FLUSH PRIVILEGES;" # Execute SQL code echo ${SQLCODE} | $DB_CMD -u root -D mysql -p${MYSQL_ROOT_PWD} if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Add Guacamole's schema code to newly created database echo -e "${GREY}Adding the Guacamole database schema..." cat guacamole-auth-jdbc-${GUAC_VERSION}/mysql/schema/*.sql | $DB_CMD -u root -D ${GUAC_DB} -p${MYSQL_ROOT_PWD} if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Apply Secure MySQL installation settings if [[ "${SECURE_MYSQL}" = true ]]; then apt-get -qq -y install expect &>>${INSTALL_LOG} echo -e "${GREY}Applying mysql_secure_installation settings...${DGREY}" SECURE_MYSQL=$(expect -c " set timeout 10 spawn mysql_secure_installation expect \"Enter current password for root (enter for none):\" send \"$MYSQL_ROOT_PWD\r\" expect \"Switch to unix_socket authentication\" send \"n\r\" expect \"Change the root password?\" send \"n\r\" expect \"Remove anonymous users?\" send \"y\r\" expect \"Disallow root login remotely?\" send \"y\r\" expect \"Remove test database and access to it?\" send \"y\r\" expect \"Reload privilege tables now?\" send \"y\r\" expect eof ") echo "$SECURE_MYSQL" if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed. See ${INSTALL_LOG}${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi fi # Restart & enable MySQL service at boot echo -e "${GREY}Restarting MySQL service & enable at boot..." systemctl enable mysql systemctl restart mysql if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Cleanup echo -e "${GREY}Cleaning up install files...${GREY}" apt-get -y remove expect &>>${INSTALL_LOG} apt-get -y autoremove &>>${INSTALL_LOG} rm -rf guacamole-* if [[ $? -ne 0 ]]; then echo -e "${LRED}Failed. See ${LOG_LOCATION}${GREY}" 1>&2 exit 1 else echo -e "${LGREEN}OK${GREY}" echo fi # Done echo printf "${LGREEN}Guacamole ${GUAC_VERSION} MySQL backend install complete! \n${NC}" echo -e ${NC} ####################################################################################################################### # Additional migration steps for adding MySQL to an existing Guacamole application server ####################################################################################################################### # Download and upgrade Guacamole SQL authentication extension #wget -q --show-progress -O guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz ${GUAC_SOURCE_LINK}/binary/guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz #tar -xzf guacamole-auth-jdbc-${GUAC_VERSION}.tar.gz #rm /etc/guacamole/extensions/guacamole-auth-jdbc-*.jar #mv -f guacamole-auth-jdbc-${GUAC_VERSION}/mysql/guacamole-auth-jdbc-mysql-${GUAC_VERSION}.jar /etc/guacamole/extensions/ #chmod 664 /etc/guacamole/extensions/guacamole-auth-jdbc-mysql-${GUAC_VERSION}.jar # Download MySQL connector/j # MYSQLJCON="8.1.0" #wget -q --show-progress -O mysql-connector-j-${MYSQLJCON}.tar.gz https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-${MYSQLJCON}.tar.gz #tar -xzf mysql-connector-j-${MYSQLJCON}.tar.gz #rm /etc/guacamole/lib/mysql-connector-java.jar #mv -f mysql-connector-j-${MYSQLJCON}/mysql-connector-j-${MYSQLJCON}.jar /etc/guacamole/lib/mysql-connector-java.jar # Configure guacamole.properties file #rm -f /etc/guacamole/guacamole.properties #touch /etc/guacamole/guacamole.properties #echo "mysql-hostname: ${MYSQL_HOST}" >>/etc/guacamole/guacamole.properties #echo "mysql-port: ${MYSQL_PORT}" >>/etc/guacamole/guacamole.properties #echo "mysql-database: ${GUAC_DB}" >>/etc/guacamole/guacamole.properties #echo "mysql-username: ${GUAC_USER}" >>/etc/guacamole/guacamole.properties #echo "mysql-password: ${GUAC_PWD}" >>/etc/guacamole/guacamole.properties