diff --git a/compose/cryostat.yml b/compose/cryostat.yml index c42fb185d..f77c3167a 100644 --- a/compose/cryostat.yml +++ b/compose/cryostat.yml @@ -14,6 +14,7 @@ services: image: ${CRYOSTAT_IMAGE:-quay.io/cryostat/cryostat:3.0.0-snapshot} volumes: - ${XDG_RUNTIME_DIR}/podman/podman.sock:/run/user/1000/podman/podman.sock:Z + - jmxtls_cfg:/truststore:U security_opt: - label:disable hostname: cryostat3 @@ -39,3 +40,7 @@ services: retries: 3 start_period: 30s timeout: 5s + +volumes: + jmxtls_cfg: + external: true diff --git a/smoketest.bash b/smoketest.bash index a9701add4..6b2b99536 100755 --- a/smoketest.bash +++ b/smoketest.bash @@ -177,6 +177,8 @@ cleanup() { ${container_engine} rm localstack_cfg_helper || true ${container_engine} volume rm localstack_cfg || true fi + ${container_engine} rm jmxtls_cfg_helper || true + ${container_engine} volume rm jmxtls_cfg || true truncate -s 0 "${HOSTSFILE}" for i in "${PIDS[@]}"; do kill -0 "${i}" && kill "${i}" @@ -209,6 +211,13 @@ if [ "${s3}" = "localstack" ]; then createLocalstackCfgVolume fi +createJmxTlsCertVolume() { + "${container_engine}" volume create jmxtls_cfg + "${container_engine}" container create --name jmxtls_cfg_helper -v jmxtls_cfg:/truststore busybox + "${container_engine}" cp "${DIR}/truststore" jmxtls_cfg_helper:/truststore +} +createJmxTlsCertVolume + setupUserHosts() { # This requires https://github.com/figiel/hosts to work. See README. truncate -s 0 "${HOSTSFILE}" diff --git a/src/main/docker/Dockerfile.jvm b/src/main/docker/Dockerfile.jvm index 8f5b902da..db1431403 100644 --- a/src/main/docker/Dockerfile.jvm +++ b/src/main/docker/Dockerfile.jvm @@ -88,11 +88,26 @@ LABEL io.cryostat.component=cryostat3 ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" -ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ] +ENTRYPOINT [ "/deployments/app/entrypoint.bash", "/opt/jboss/container/java/run/run-java.sh" ] # We make distinct layers so if there are application changes the library layers can be re-used COPY --chown=185 src/main/docker/include/cryostat.jfc /usr/lib/jvm/jre/lib/jfr/ +COPY --chown=185 src/main/docker/include/genpass.bash /deployments/app/ +COPY --chown=185 src/main/docker/include/entrypoint.bash /deployments/app/ +COPY --chown=185 src/main/docker/include/truststore-setup.bash /deployments/app/ COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ COPY --chown=185 target/quarkus-app/*.jar /deployments/ COPY --chown=185 target/quarkus-app/app/ /deployments/app/ COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ + +ENV CONF_DIR=/opt/cryostat.d +ENV SSL_TRUSTSTORE=$CONF_DIR/truststore.p12 \ + SSL_TRUSTSTORE_PASS_FILE=$CONF_DIR/truststore.pass + +USER root +RUN mkdir -p $CONF_DIR \ + && chmod -R g=u $CONF_DIR \ + && chown jboss:root $CONF_DIR +USER 185 + +RUN /deployments/app/truststore-setup.bash diff --git a/src/main/docker/include/entrypoint.bash b/src/main/docker/include/entrypoint.bash new file mode 100755 index 000000000..1b0b46a32 --- /dev/null +++ b/src/main/docker/include/entrypoint.bash @@ -0,0 +1,83 @@ +#!/bin/bash + +set -e + +DIR="$(dirname "$(realpath "$0")")" +source "${DIR}/genpass.bash" + +function banner() { + echo "+------------------------------------------+" + printf "| %-40s |\n" "$(date)" + echo "| |" + printf "| %-40s |\n" "$@" + echo "+------------------------------------------+" +} + +USRFILE="/tmp/jmxremote.access" +PWFILE="/tmp/jmxremote.password" +function createJmxCredentials() { + if [ -z "$CRYOSTAT_RJMX_USER" ]; then + CRYOSTAT_RJMX_USER="cryostat" + fi + if [ -z "$CRYOSTAT_RJMX_PASS" ]; then + CRYOSTAT_RJMX_PASS="$(genpass)" + fi + + echo -n "$CRYOSTAT_RJMX_USER $CRYOSTAT_RJMX_PASS" > "$PWFILE" + chmod 400 "$PWFILE" + echo -n "$CRYOSTAT_RJMX_USER readwrite" > "$USRFILE" + chmod 400 "$USRFILE" +} + +function importTrustStores() { + echo "Running as id:$(id -u) group:$(id -g)" + if [ -z "$CONF_DIR" ]; then + CONF_DIR="/opt/cryostat.d" + fi + if [ -z "$SSL_TRUSTSTORE_DIR" ]; then + SSL_TRUSTSTORE_DIR="/truststore" + fi + + if [ ! -d "$SSL_TRUSTSTORE_DIR" ]; then + banner "$SSL_TRUSTSTORE_DIR does not exist; no certificates to import" + return 0 + elif [ ! "$(ls -A "$SSL_TRUSTSTORE_DIR")" ]; then + banner "$SSL_TRUSTSTORE_DIR is empty; no certificates to import" + return 0 + fi + + SSL_TRUSTSTORE_PASS="$(cat "${SSL_TRUSTSTORE_PASS_FILE:-$CONF_DIR/truststore.pass}")" + + find "$SSL_TRUSTSTORE_DIR" -type f | while IFS= read -r cert; do + echo "Importing certificate $cert ..." + + keytool -importcert -v \ + -noprompt \ + -alias "imported-$(basename "$cert")" \ + -trustcacerts \ + -keystore "${SSL_TRUSTSTORE:-$CONF_DIR/truststore.p12}" \ + -file "$cert"\ + -storepass "$SSL_TRUSTSTORE_PASS" + done + + FLAGS+=( + "-Djavax.net.ssl.trustStore=$SSL_TRUSTSTORE" + "-Djavax.net.ssl.trustStorePassword=$SSL_TRUSTSTORE_PASS" + ) +} + +FLAGS=() +importTrustStores + +if [ "$CRYOSTAT_DISABLE_JMX_AUTH" = "true" ]; then + banner "JMX Auth Disabled" + FLAGS+=("-Dcom.sun.management.jmxremote.authenticate=false") +else + createJmxCredentials + FLAGS+=("-Dcom.sun.management.jmxremote.authenticate=true") + FLAGS+=("-Dcom.sun.management.jmxremote.password.file=$PWFILE") + FLAGS+=("-Dcom.sun.management.jmxremote.access.file=$USRFILE") +fi + +export JAVA_OPTS_APPEND="${JAVA_OPTS_APPEND} ${FLAGS[*]}" +exec $1 diff --git a/src/main/docker/include/genpass.bash b/src/main/docker/include/genpass.bash new file mode 100755 index 000000000..ba1557267 --- /dev/null +++ b/src/main/docker/include/genpass.bash @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +genpass() { + < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c32 +} diff --git a/src/main/docker/include/truststore-setup.bash b/src/main/docker/include/truststore-setup.bash new file mode 100755 index 000000000..ab4d80cfa --- /dev/null +++ b/src/main/docker/include/truststore-setup.bash @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -e + +DIR="$(dirname "$(realpath "$0")")" +source "${DIR}/genpass.bash" + +SSL_TRUSTSTORE_PASS="$(genpass)" + +echo "$SSL_TRUSTSTORE_PASS" > "$SSL_TRUSTSTORE_PASS_FILE" + +trap "cd -" EXIT +cd "$CONF_DIR" + +keytool -importkeystore \ + -noprompt \ + -storetype PKCS12 \ + -srckeystore /usr/lib/jvm/jre-17-openjdk/lib/security/cacerts \ + -srcstorepass changeit \ + -destkeystore "$SSL_TRUSTSTORE" \ + -deststorepass "$SSL_TRUSTSTORE_PASS" + +chmod 664 "${SSL_TRUSTSTORE}" +chmod 640 "${SSL_TRUSTSTORE_PASS_FILE}"