Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added alpine based dockerfile and mysql database setup via docker run… #940

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions Dockerfile.alpine
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

#
# Dockerfile for guacamole-client
#

# Use args for Tomcat image label to allow image builder to choose alternatives
# such as `--build-arg TOMCAT_JRE=jre8-alpine`
#
ARG TOMCAT_VERSION=8.5
ARG TOMCAT_JRE=jdk8

# Use official maven image for the build
FROM maven:3-eclipse-temurin-8-focal AS builder

# Use Mozilla's Firefox PPA (newer Ubuntu lacks a "firefox-esr" package and
# provides only a transitional "firefox" package that actually requires Snap
# and thus can't be used within Docker)

RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y software-properties-common \
&& add-apt-repository -y ppa:mozillateam/ppa

# Explicitly prefer packages from the Firefox PPA
COPY guacamole-docker/mozilla-firefox.pref /etc/apt/preferences.d/

# Install firefox browser for sake of JavaScript unit tests
RUN apt-get update && apt-get install -y firefox

# Install firefox browser for sake of JavaScript unit tests
# Arbitrary arguments that can be passed to the maven build. By default, an
# argument will be provided to explicitly unskip any skipped tests. To, for
# example, allow the building of the RADIUS auth extension, pass a build profile
# as well: `--build-arg MAVEN_ARGUMENTS="-P lgpl-extensions -DskipTests=false"`.
ARG MAVEN_ARGUMENTS="-DskipTests=false"

# Versions of JDBC drivers to bundle within image
ARG MSSQL_JDBC_VERSION=9.4.1
ARG MYSQL_JDBC_VERSION=8.0.33
ARG PGSQL_JDBC_VERSION=42.6.0

# Build environment variables
ENV \
BUILD_DIR=/tmp/guacamole-docker-BUILD

# Add configuration scripts
COPY guacamole-docker/bin/ /opt/guacamole/bin/

# Copy source to container for sake of build
COPY . "$BUILD_DIR"

# Run the build itself
RUN /opt/guacamole/bin/build-guacamole.sh "$BUILD_DIR" /opt/guacamole

# For the runtime image, we start with the official Tomcat distribution

FROM alpine

COPY --from=builder /opt/guacamole /opt/guacamole

ENV TOMCAT_MAJOR=9 \
TOMCAT_VERSION=9.0.78 \
CATALINA_HOME=/opt/guacamole

RUN \
apk add --update --no-cache \
openjdk8-jre curl mariadb-client bash openssl busybox-extras && \
apk add paxctl --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community && \
curl -jkSL -o /tmp/apache-tomcat.tar.gz \
http://archive.apache.org/dist/tomcat/tomcat-${TOMCAT_MAJOR}/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
gunzip /tmp/apache-tomcat.tar.gz && \
tar -C /opt -xf /tmp/apache-tomcat.tar && \
ln -s /opt/apache-tomcat-$TOMCAT_VERSION /usr/local/tomcat && \
chmod -R a+rx /usr/local/tomcat/

# cleanup
RUN paxctl -c /usr/lib/jvm/java-1.8-openjdk/bin/java && \
paxctl -C /usr/lib/jvm/java-1.8-openjdk/bin/java && \
paxctl -mps /usr/lib/jvm/java-1.8-openjdk/bin/java && \
apk del curl && \
apk del paxctl && \
rm -rf /tmp/* /var/cache/apk/* /usr/local/tomcat/webapps/*


# Create a new user guacamole
ARG UID=1001
ARG GID=1001
RUN addgroup -g $GID guacamole
RUN adduser -S -D -s /usr/sbin/nologin -u $UID guacamole --ingroup guacamole

# Run with user guacamole
USER guacamole

EXPOSE 8080

WORKDIR $CATALINA_HOME

# Start Guacamole under Tomcat, listening on 0.0.0.0:8080
EXPOSE 8080
CMD ["/opt/guacamole/bin/start.sh" ]
101 changes: 101 additions & 0 deletions guacamole-docker/bin/check_database.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

# Setting up mysql database if not exists

if [ "$SLEEP_SHORT" == "" ]; then
SLEEP_SHORT=5
fi

if [ "$SLEEP_LONG" == "" ]; then
SLEEP_LONG=10
fi

if [ "$RETRIES" == "" ]; then
RETRIES=5
fi
Comment on lines +23 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If new environment variables are to be supported by this image, the naming should be more specific. SLEEP_SHORT, SLEEP_LONG, and RETRIES are too broad.


if [[ "$MYSQL_USER" != "" && "$MYSQL_PASSWORD" != "" && "$MYSQL_DATABASE" != "" && "$MYSQL_HOSTNAME" != "" ]]; then

if [ "$MYSQL_PORT" == "" ]; then
DB_PORT=3306;
else
DB_PORT=$MYSQL_PORT;
fi

DB_HOST=$MYSQL_HOSTNAME;
DB_NAME=$MYSQL_DATABASE;
DB_USER=$MYSQL_USER;
DB_PASSWORD=$MYSQL_PASSWORD;
DB_ENGINE="/usr/bin/mariadb"


UUID=$(openssl rand -hex 16)
SALT=$(echo ${UUID:0:8}-${UUID:8:4}-${UUID:12:4}-${UUID:16:4}-${UUID:20:12} | openssl sha256 -hex | awk '{print toupper($2)}');
HASH=$(echo -n "$ADMIN_PASSWORD$SALT" | openssl sha256 -hex | awk '{print toupper($2)}')
cp /opt/guacamole/mysql/schema/*.sql /tmp/
sed -i "s/guacadmin/$ADMIN_NAME/g" /tmp/002-create-admin-user.sql
sed -i "s/FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264/$SALT/" /tmp/002-create-admin-user.sql
sed -i "s/CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960/$HASH/" /tmp/002-create-admin-user.sql
Comment on lines +35 to +56
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would need to be implemented for each supported database, not just MySQL/MariaDB.



# Check database access
for retries in $(seq 0 $((RETRIES+ 1))); do
RESPONSE=$(echo "exit" | timeout $SLEEP_SHORT telnet $DB_HOST $DB_PORT|grep Connected);
echo "RESPONSE: $RESPONSE";
if [ "$RESPONSE" == "" ]; then
if [[ $retries -le $RETRIES ]] ; then
echo "Retired $retries";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by "retired"?

echo "Expected $DB_HOST currently not available, wait $SLEEP_SHORT seconds.";
sleep $SLEEP_SHORT;
else
for retries2 in $(seq 0 $((RETRIES+ 1))); do
RESPONSE=$(echo "exit" | timeout $SLEEP_SHORT telnet $DB_HOST $DB_PORT|grep Connected);
if [ "$RESPONSE" == "" ]; then
if [[ $retries2 -le $RETRIES ]] ; then
echo "Retired $retries2";
echo "Expected $DB_HOST currently not available, wait $SLEEP_LONG seconds.";
sleep $SLEEP_LONG;
else
echo "Expected $DB_HOST currently not available, and reached all reries limit, exiting";
exit 1;
fi
else
echo "Expected $DB_HOST accessed successfuly, continue database init processes."
break;
fi
done
fi
else
echo "Expected $DB_HOST accessed successfuly, continue database init processes."
break;
fi
done
Comment on lines +59 to +90
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The logic here feels overcomplicated for what it is intended to achieve (wait for the database to come up). Why so many nested loops and layers of retrying?
  2. I'm on the fence on building this functionality into the Docker image. Perhaps adding automatic initialization into the database support within the webapp itself would make more sense? That would also allow for automatic application of schema updates while maintaining separation of concerns.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps adding automatic initialization into the database support within the webapp itself would make more sense?

+1


for i in $(ls /tmp/*.sql); do
CREATE_DATABASE=$($DB_ENGINE -u $DB_USER -p$DB_PASSWORD $DB_NAME -h $DB_HOST --port $DB_PORT < $i);
if [[ "$(echo $?)" == "1" ]]; then
echo "Database already exists";
exit 2;
else
echo "Database automaticaly initialized." ;
fi
done
Comment on lines +92 to +100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dangerous. Should a user ever manage to write a file to /tmp with a .sql extension, that file would be automatically run at subsequent startup as a privileged database user. Merely writing files to /tmp is not a privileged operation, so this would be privilege escalation.

fi
28 changes: 24 additions & 4 deletions guacamole-docker/bin/start.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash -e
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
Expand Down Expand Up @@ -562,11 +562,11 @@ END

set_optional_property \
"sqlserver-auto-create-accounts" \
"$SQLSERVER_AUTO_CREATE_ACCOUNTS"
"$SQLSERVERQL_AUTO_CREATE_ACCOUNTS"

set_optional_property \
"sqlserver-instance" \
"$SQLSERVER_INSTANCE"
"$SQLSERVERQL_INSTANCE"
Comment on lines +565 to +569
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these renamed?


# Add required .jar files to GUACAMOLE_LIB and GUACAMOLE_EXT
ln -s /opt/guacamole/sqlserver/mssql-jdbc-*.jar "$GUACAMOLE_LIB"
Expand Down Expand Up @@ -1023,7 +1023,10 @@ associate_apisessiontimeout() {
start_guacamole() {

# User-only writable CATALINA_BASE
CATALINA_BASE=$HOME/tomcat
CATALINA_HOME=/usr/local/tomcat
export CATALINA_BASE=$HOME/tomcat
export CATALINA_HOME=/usr/local/tomcat
for dir in logs temp webapps work; do
mkdir -p $CATALINA_BASE/$dir
done
Expand All @@ -1039,7 +1042,7 @@ start_guacamole() {

# Start tomcat
cd /usr/local/tomcat
exec catalina.sh run
exec bin/catalina.sh run

}

Expand Down Expand Up @@ -1246,8 +1249,25 @@ if [ -n "$LOGBACK_LEVEL" ]; then
sed -i "s/level=\"info\"/level=\"$LOGBACK_LEVEL\"/" $GUACAMOLE_HOME/logback.xml
fi

# Initialise database if not exists

/opt/guacamole/bin/check_database.sh

RESPONSE=$(echo $?);

if [ "$RESPONSE" == "1" ]; then
echo "No any database accessible, exiting."
exit 1;
elif [ "$RESPONSE" == "2" ]; then
echo "Database exists, continue running."
else
echo "Database init was successsfully."
fi

#
# Finally start Guacamole (under Tomcat)
#



start_guacamole