From ee9534dcaeb314d6f41e8d88ed51f664bf8b2803 Mon Sep 17 00:00:00 2001 From: Sando Date: Mon, 5 Sep 2022 21:43:53 +0200 Subject: [PATCH 1/7] Include eturnal turn service --- Makefile | 2 +- docker-compose.yml | 24 +++++++++ env.example | 21 ++++++++ eturnal/Dockerfile | 53 +++++++++++++++++++ eturnal/rootfs/usr/sbin/run.sh | 79 ++++++++++++++++++++++++++++ web/rootfs/defaults/default | 23 ++++++-- web/rootfs/defaults/nginx.conf | 3 ++ web/rootfs/defaults/turn | 40 ++++++++++++++ web/rootfs/etc/cont-init.d/10-config | 11 ++-- 9 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 eturnal/Dockerfile create mode 100644 eturnal/rootfs/usr/sbin/run.sh create mode 100644 web/rootfs/defaults/turn diff --git a/Makefile b/Makefile index b59fc01c24..738aa80a27 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ JITSI_BUILD ?= unstable JITSI_REPO ?= jitsi NATIVE_ARCH ?= $(shell uname -m) -JITSI_SERVICES := base base-java web prosody jicofo jvb jigasi jibri +JITSI_SERVICES := base base-java web prosody jicofo jvb jigasi jibri eturnal ifeq ($(NATIVE_ARCH),x86_64) TARGETPLATFORM := linux/amd64 diff --git a/docker-compose.yml b/docker-compose.yml index dfabc5a988..113735109b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,7 @@ services: ports: - '${HTTP_PORT}:80' - '${HTTPS_PORT}:443' + - '${TURN_PORT}:3478' volumes: - ${CONFIG}/web:/config:Z - ${CONFIG}/web/crontabs:/var/spool/cron/crontabs:Z @@ -125,6 +126,8 @@ services: - TESTING_OCTO_PROBABILITY - TOKEN_AUTH_URL - TOOLBAR_BUTTONS + - TURN_HOST + - TURNS_HOST - TZ - VIDEOQUALITY_BITRATE_H264_LOW - VIDEOQUALITY_BITRATE_H264_STANDARD @@ -336,6 +339,27 @@ services: networks: meet.jitsi: + # turn service + eturnal: + image: jitsi/eturnal:${JITSI_IMAGE_VERSION:-unstable} + restart: ${RESTART_POLICY:-unless-stopped} + ports: + - '${TURN_RELAY_MIN_PORT:-50000}-${TURN_RELAY_MAX_PORT:-50500}:${TURN_RELAY_MIN_PORT:-50000}-${TURN_RELAY_MAX_PORT:-50500}/udp' + volumes: + - ${CONFIG}/eturnal:/opt/eturnal/etc:Z + - ${CONFIG}/web/acme-certs:/etc/eturnal/tls:Z + environment: + - TURN_CREDENTIALS + - TURN_RELAY_MIN_PORT + - TURN_RELAY_MAX_PORT + - DOCKER_HOST_ADDRESS + - JVB_DISABLE_STUN + depends_on: + - prosody + - web + networks: + meet.jitsi: + # Custom network so all services can communicate using a FQDN networks: meet.jitsi: diff --git a/env.example b/env.example index 4595f1076b..1116fb50b4 100644 --- a/env.example +++ b/env.example @@ -177,6 +177,27 @@ ETHERPAD_SKIN_VARIANTS="super-light-toolbar super-light-editor light-background # Wether to use starttls, implies LDAPv3 and requires ldap:// instead of ldaps:// # LDAP_START_TLS=1 +# +# eturnal TURN Server configuration +# + +# TURN_CREDENTIALS=super-secret-password + +# currently hard coded to 'turn.$LETSENCRYPT_DOMAIN' +# TURN_HOST=turn.example.com + +# currently hard coded +# TURN_PORT=3478 + +# currently hard coded to 'turn.$LETSENCRYPT_DOMAIN' +# TURNS_HOST=turn.example.com + +# currently hard coded +# TURNS_PORT=443 + +# TURN relay port range +# TURN_RELAY_MIN_PORT=50000 +# TURN_RELAY_MAX_PORT=50500 # # Security diff --git a/eturnal/Dockerfile b/eturnal/Dockerfile new file mode 100644 index 0000000000..d90bd0c4f9 --- /dev/null +++ b/eturnal/Dockerfile @@ -0,0 +1,53 @@ +FROM debian:bullseye-slim as prepare +# BUILD: define image build arguments +ARG ETURNAL_VERSION=1.10.1 +ARG TINI_VERSION=0.19.0 + +RUN set -x \ + && apt-get update && apt-get install curl -y \ +# RUNTIME: install eturnal binary with installer + && ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/;s/armv7l/arm/;s/s390x/s390x/;s/ppc64le/ppc64le/') \ + && curl -O https://eturnal.net/download/linux/installer/eturnal-$ETURNAL_VERSION-linux-$ARCH.run \ + && chmod +x eturnal-*.run \ + && ./eturnal-*.run \ + && rm -rf eturnal-*.run /opt/eturnal/etc/* /etc/eturnal.yml \ +# RUNTIME: create rootfs with eturnal + && mkdir -p /rootfs/opt/eturnal/log /rootfs/opt/eturnal/run /rootfs/opt/eturnal/tls \ + && cp -r /opt/eturnal /rootfs/opt \ +# RUNTIME: install runtime init + && ARCH=$(uname -m | sed -e 's/x86_64/amd64/;s/aarch64/arm64/;s/armv7l/arm/;s/s390x/s390x/;s/ppc64le/ppc64le/') \ + && curl -fL -o /rootfs/tini https://github.com/krallin/tini/releases/download/v$TINI_VERSION/tini-$ARCH \ + && chmod +x /rootfs/tini +# RUNTIME: copy entrypoint script +COPY rootfs /rootfs + +FROM busybox:stable-glibc AS eturnal +# BUILD: copy eturnal +COPY --from=prepare --chown=9000:9000 /rootfs / +ARG HOME=/opt/eturnal + +RUN set -x \ +# RUNTIME: add runtime group and user + && echo "eturnal:x:9000:eturnal" >> /etc/group \ + && echo "eturnal:x:9000:9000:Linux User,,,:/opt/eturnal:/bin/sh" >> /etc/passwd \ +# RUNTIME: create symbolic links, entrypoint script and minimal configuration file + && ln -s $HOME/bin/eturnalctl /usr/sbin/eturnalctl \ + && ln -s $HOME/bin/stun /usr/sbin/stun \ + && chmod +x /usr/sbin/* + +FROM gcr.io/distroless/base-debian11 AS runtime +# BUILD: copy eturnal +COPY --from=eturnal --chown=9000:9000 / / +ARG HOME=/opt/eturnal +# RUNTIME: define container runtime environment variables +ENV ERL_DIST_PORT=3470 \ + PIPE_DIR=$HOME/run/pipe/ \ + STUN_SERVICE="stun.conversations.im 3478" + +# RUNTIME: define container runtime parameters +WORKDIR $HOME +#USER eturnal +VOLUME ["$HOME"] +EXPOSE 3478 3478/udp +ENTRYPOINT ["/tini","--","run.sh"] +CMD ["eturnalctl", "foreground"] \ No newline at end of file diff --git a/eturnal/rootfs/usr/sbin/run.sh b/eturnal/rootfs/usr/sbin/run.sh new file mode 100644 index 0000000000..7f1acac207 --- /dev/null +++ b/eturnal/rootfs/usr/sbin/run.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# eturnal config +#DOCKER_INTERNAL_IP=$(cat /etc/hosts | grep $(hostname) | awk '{ print $1 }') +cat > /opt/eturnal/etc/eturnal.yml < ${TURN_RELAY_MIN_PORT-50000} is greater or equal than maximum port -> ${TURN_RELAY_MAX_PORT-50500}" + echo " [INFO] Starting eturnal with relay port range 50000 - 50500" + echo "" + export ETURNAL_RELAY_MIN_PORT=50000 + export ETURNAL_RELAY_MAX_PORT=50500 + fi +else + export ETURNAL_RELAY_MIN_PORT=50000 + export ETURNAL_RELAY_MAX_PORT=50500 +fi + +# discover public IP addresses +if [ ! -z $DOCKER_HOST_ADDRESS ] +then + export ETURNAL_RELAY_IPV4_ADDR=$DOCKER_HOST_ADDRESS +else + if [ -z "$JVB_DISABLE_STUN" ] + then + export ETURNAL_RELAY_IPV4_ADDR=${ETURNAL_RELAY_IPV4_ADDR-$(stun -4 $STUN_SERVICE)} + fi +fi +exec "$@" \ No newline at end of file diff --git a/web/rootfs/defaults/default b/web/rootfs/defaults/default index 37f2c20bb7..a66cad8861 100644 --- a/web/rootfs/defaults/default +++ b/web/rootfs/defaults/default @@ -12,15 +12,32 @@ server { {{ end }} } -{{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }} +{{ if .Env.TURNS_HOST }} + {{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }} server { - listen 443 ssl http2; + listen 8443 ssl http2 proxy_protocol; {{ if .Env.ENABLE_IPV6 | default "1" | toBool }} - listen [::]:443 ssl http2; + listen [::]:8443 ssl http2; + {{ end }} + + include /config/nginx/ssl.conf; + include /config/nginx/meet.conf; +} {{ end }} +{{ end }} + +{{ if not .Env.TURNS_HOST }} + {{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }} +server { + listen 443 ssl http2; + + {{ if .Env.ENABLE_IPV6 | default "1" | toBool }} + listen [::]:443 ssl http2; + {{ end }} include /config/nginx/ssl.conf; include /config/nginx/meet.conf; } + {{ end }} {{ end }} diff --git a/web/rootfs/defaults/nginx.conf b/web/rootfs/defaults/nginx.conf index 862688767f..baefaeaf7b 100644 --- a/web/rootfs/defaults/nginx.conf +++ b/web/rootfs/defaults/nginx.conf @@ -67,5 +67,8 @@ http { include /config/nginx/site-confs/*; } +stream { + include /config/nginx/stream/*; +} daemon off; diff --git a/web/rootfs/defaults/turn b/web/rootfs/defaults/turn new file mode 100644 index 0000000000..f8b61fb47d --- /dev/null +++ b/web/rootfs/defaults/turn @@ -0,0 +1,40 @@ +{{ if or .Env.TURN_HOST .Env.TURNS_HOST }} + {{ if .Env.TURN_HOST }} + server { + listen 3478; + proxy_pass eturnal:3478; + proxy_protocol on; + } + + server { + listen 3478 udp; + proxy_pass eturnal:3478; + } +{{ end }} + {{ if .Env.TURNS_HOST }} + map $ssl_preread_server_name $name { + turndomainname eturnaltls; + {{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }} + default web; + {{ end }} + } + + upstream eturnaltls { + server eturnal:3478; + } + + {{ if not (.Env.DISABLE_HTTPS | default "0" | toBool) }} + upstream web { + server 127.0.0.1:8443; + } + {{ end }} + + server { + listen 443; + proxy_pass $name; + ssl_preread on; + proxy_protocol on; + #include /config/nginx/ssl.conf; + } + {{ end }} +{{ end }} \ No newline at end of file diff --git a/web/rootfs/etc/cont-init.d/10-config b/web/rootfs/etc/cont-init.d/10-config index 424ae87619..e260950ea5 100644 --- a/web/rootfs/etc/cont-init.d/10-config +++ b/web/rootfs/etc/cont-init.d/10-config @@ -2,7 +2,7 @@ # make our folders mkdir -p \ - /config/{nginx/site-confs,keys} \ + /config/{nginx/{site-confs,stream},keys} \ /run \ /var/lib/nginx/tmp/client_body \ /var/tmp/nginx @@ -27,7 +27,7 @@ if [[ $DISABLE_HTTPS -ne 1 ]]; then --standalone \ --pre-hook "if [[ -d /var/run/s6/services/nginx ]]; then s6-svc -d /var/run/s6/services/nginx; fi" \ --post-hook "if [[ -d /var/run/s6/services/nginx ]]; then s6-svc -u /var/run/s6/services/nginx; fi" \ - -d $LETSENCRYPT_DOMAIN + -d $LETSENCRYPT_DOMAIN -d turn.$LETSENCRYPT_DOMAIN rc=$? if [[ $rc -eq 1 ]]; then echo "Failed to obtain a certificate from the Let's Encrypt CA." @@ -40,7 +40,7 @@ if [[ $DISABLE_HTTPS -ne 1 ]]; then if [[ $rc -eq 0 ]]; then mkdir -p /config/acme-certs/$LETSENCRYPT_DOMAIN if ! /config/acme.sh/acme.sh \ - --install-cert -d $LETSENCRYPT_DOMAIN \ + --install-cert -d $LETSENCRYPT_DOMAIN -d turn.$LETSENCRYPT_DOMAIN \ --key-file /config/acme-certs/$LETSENCRYPT_DOMAIN/key.pem \ --fullchain-file /config/acme-certs/$LETSENCRYPT_DOMAIN/fullchain.pem ; then echo "Failed to install certificate." @@ -74,6 +74,11 @@ fi tpl /defaults/ssl.conf > /config/nginx/ssl.conf tpl /defaults/default > /config/nginx/site-confs/default +tpl /defaults/turn > /config/nginx/stream/turn + +if [[ $ENABLE_LETSENCRYPT -eq 1 ]]; then + sed -i -e "s|turndomainname|turn.$LETSENCRYPT_DOMAIN|g" /config/nginx/stream/turn +fi tpl /defaults/system-config.js > /config/config.js tpl /defaults/settings-config.js >> /config/config.js From 21cfba6308652c97b5e295f40a2e717c82e6aa91 Mon Sep 17 00:00:00 2001 From: Sando Date: Tue, 6 Sep 2022 12:48:08 +0200 Subject: [PATCH 2/7] Dockerfile eturnal: remove openssl and co from distroless because openssl and co are statically shipped with eturnal binary --- eturnal/Dockerfile | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/eturnal/Dockerfile b/eturnal/Dockerfile index d90bd0c4f9..1e27043bb8 100644 --- a/eturnal/Dockerfile +++ b/eturnal/Dockerfile @@ -35,9 +35,21 @@ RUN set -x \ && ln -s $HOME/bin/stun /usr/sbin/stun \ && chmod +x /usr/sbin/* -FROM gcr.io/distroless/base-debian11 AS runtime +FROM gcr.io/distroless/base-debian11 AS cleanup # BUILD: copy eturnal COPY --from=eturnal --chown=9000:9000 / / +# remove libssl and openssl from distroless image +# as they are statically built within eturnal binary +RUN find -type f -name 'libcrypt*' -exec rm -rv {} + \ + && find -type d -name 'libcrypt*' -exec rm -rv {} + \ + && find -type f -name 'libssl*' -exec rm -rv {} + \ + && find -type d -name 'libssl*' -exec rm -rv {} + \ + && find -type f -name 'openssl*' -exec rm -rv {} + \ + && find -type d -name 'openssl*' -exec rm -rv {} + + +FROM scratch AS runtime +# BUILD: copy eturnal +COPY --from=cleanup --chown=9000:9000 / / ARG HOME=/opt/eturnal # RUNTIME: define container runtime environment variables ENV ERL_DIST_PORT=3470 \ From 39c94e701051fb5dc3e4482e46608f494195ccc7 Mon Sep 17 00:00:00 2001 From: Sando Date: Tue, 6 Sep 2022 18:28:05 +0200 Subject: [PATCH 3/7] Remove UPD listener and use recommended blacklist --- eturnal/rootfs/usr/sbin/run.sh | 6 +----- web/rootfs/defaults/turn | 5 ----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/eturnal/rootfs/usr/sbin/run.sh b/eturnal/rootfs/usr/sbin/run.sh index 7f1acac207..d0bc0c6ad9 100644 --- a/eturnal/rootfs/usr/sbin/run.sh +++ b/eturnal/rootfs/usr/sbin/run.sh @@ -4,10 +4,6 @@ cat > /opt/eturnal/etc/eturnal.yml < Date: Wed, 7 Sep 2022 15:03:32 +0200 Subject: [PATCH 4/7] Copy valid certs from LE jitsi web at startup cronjob to renew certs is not yet implemented. --- docker-compose.yml | 1 + eturnal/Dockerfile | 2 +- eturnal/rootfs/usr/sbin/run.sh | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 113735109b..13f8f49a44 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -352,6 +352,7 @@ services: - TURN_CREDENTIALS - TURN_RELAY_MIN_PORT - TURN_RELAY_MAX_PORT + - TURNS_HOST - DOCKER_HOST_ADDRESS - JVB_DISABLE_STUN depends_on: diff --git a/eturnal/Dockerfile b/eturnal/Dockerfile index 1e27043bb8..3617d2a7cd 100644 --- a/eturnal/Dockerfile +++ b/eturnal/Dockerfile @@ -16,7 +16,7 @@ RUN set -x \ && cp -r /opt/eturnal /rootfs/opt \ # RUNTIME: install runtime init && ARCH=$(uname -m | sed -e 's/x86_64/amd64/;s/aarch64/arm64/;s/armv7l/arm/;s/s390x/s390x/;s/ppc64le/ppc64le/') \ - && curl -fL -o /rootfs/tini https://github.com/krallin/tini/releases/download/v$TINI_VERSION/tini-$ARCH \ + && curl -fL -o /rootfs/tini https://github.com/krallin/tini/releases/download/v$TINI_VERSION/tini-$ARCH \ && chmod +x /rootfs/tini # RUNTIME: copy entrypoint script COPY rootfs /rootfs diff --git a/eturnal/rootfs/usr/sbin/run.sh b/eturnal/rootfs/usr/sbin/run.sh index d0bc0c6ad9..81b06325ea 100644 --- a/eturnal/rootfs/usr/sbin/run.sh +++ b/eturnal/rootfs/usr/sbin/run.sh @@ -32,8 +32,35 @@ eturnal: # port: 8081 # This is the default. # tls: false # This is the default. # vm_metrics: true # This is the default. + EOF +# tls certificates +TLS_CERT_FILE=$(find /etc/ -name fullchain.pem) +TLS_KEY_FILE=$(find /etc/ -name key.pem) +if [ ! -z $TLS_CERT_FILE ] || [ ! -z $TLS_KEY_FILE ]; then + echo " ## TLS certificate/key files (must be readable by 'eturnal' user!):" >> /opt/eturnal/etc/eturnal.yml + if [ ! -z $TLS_CERT_FILE ]; then + cp -p $TLS_CERT_FILE /opt/eturnal/tls + echo " tls_crt_file: /opt/eturnal/tls/fullchain.pem" >> /opt/eturnal/etc/eturnal.yml + fi + if [ ! -z $TLS_KEY_FILE ]; then + cp -p $TLS_KEY_FILE /opt/eturnal/tls + echo " tls_key_file: /opt/eturnal/tls/key.pem" >> /opt/eturnal/etc/eturnal.yml + fi +fi + +# change file permissions +chown 9000:9000 /opt/eturnal/etc/eturnal.yml +chmod 640 /opt/eturnal/etc/eturnal.yml +chown 9000:9000 /opt/eturnal/tls/* + +# start certificate renewal cronjob +#if [ ! -z $TURNS_HOST ] +#then +# crond -b -d +#fi + # TURN credentials if [ ! -z $TURN_CREDENTIALS ] then From a2a1458710032e9aef2581f8724b1970e58f436a Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 11 Sep 2022 11:53:09 +0200 Subject: [PATCH 5/7] Update Dockerfile and include cronjob including s6 overlay to docker image plus implementing the cronjob to update certs in eturnal turn server. eturnal reloads certificates without interrupting/closing existing sessions. --- docker-compose.yml | 2 + eturnal/Dockerfile | 30 ++++----- .../sbin/run.sh => etc/cont-init.d/10-config} | 62 +++---------------- eturnal/rootfs/etc/services.d/cron/run | 47 ++++++++++++++ eturnal/rootfs/etc/services.d/eturnal/run | 43 +++++++++++++ 5 files changed, 116 insertions(+), 68 deletions(-) rename eturnal/rootfs/{usr/sbin/run.sh => etc/cont-init.d/10-config} (54%) create mode 100644 eturnal/rootfs/etc/services.d/cron/run create mode 100644 eturnal/rootfs/etc/services.d/eturnal/run diff --git a/docker-compose.yml b/docker-compose.yml index 13f8f49a44..b3eb365b55 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -345,6 +345,8 @@ services: restart: ${RESTART_POLICY:-unless-stopped} ports: - '${TURN_RELAY_MIN_PORT:-50000}-${TURN_RELAY_MAX_PORT:-50500}:${TURN_RELAY_MIN_PORT:-50000}-${TURN_RELAY_MAX_PORT:-50500}/udp' + security_opt: + - no-new-privileges:true volumes: - ${CONFIG}/eturnal:/opt/eturnal/etc:Z - ${CONFIG}/web/acme-certs:/etc/eturnal/tls:Z diff --git a/eturnal/Dockerfile b/eturnal/Dockerfile index 3617d2a7cd..d6bfce4ce0 100644 --- a/eturnal/Dockerfile +++ b/eturnal/Dockerfile @@ -2,9 +2,10 @@ FROM debian:bullseye-slim as prepare # BUILD: define image build arguments ARG ETURNAL_VERSION=1.10.1 ARG TINI_VERSION=0.19.0 +ARG S6_VERSION=v3.1.2.1 RUN set -x \ - && apt-get update && apt-get install curl -y \ + && apt-get update && apt-get install apt-transport-https apt-utils ca-certificates curl wget xz-utils -y \ # RUNTIME: install eturnal binary with installer && ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/;s/armv7l/arm/;s/s390x/s390x/;s/ppc64le/ppc64le/') \ && curl -O https://eturnal.net/download/linux/installer/eturnal-$ETURNAL_VERSION-linux-$ARCH.run \ @@ -15,15 +16,16 @@ RUN set -x \ && mkdir -p /rootfs/opt/eturnal/log /rootfs/opt/eturnal/run /rootfs/opt/eturnal/tls \ && cp -r /opt/eturnal /rootfs/opt \ # RUNTIME: install runtime init - && ARCH=$(uname -m | sed -e 's/x86_64/amd64/;s/aarch64/arm64/;s/armv7l/arm/;s/s390x/s390x/;s/ppc64le/ppc64le/') \ - && curl -fL -o /rootfs/tini https://github.com/krallin/tini/releases/download/v$TINI_VERSION/tini-$ARCH \ - && chmod +x /rootfs/tini -# RUNTIME: copy entrypoint script + && ARCH=$(uname -m) \ + && wget -qO - https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-noarch.tar.xz | tar xfJ - -C /rootfs \ + && wget -qO - https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-$ARCH.tar.xz | tar xfJ - -C /rootfs +# RUNTIME: copy s6 scripts COPY rootfs /rootfs -FROM busybox:stable-glibc AS eturnal +FROM gcr.io/distroless/base-debian11 AS eturnal # BUILD: copy eturnal COPY --from=prepare --chown=9000:9000 /rootfs / +COPY --from=busybox:stable-glibc /bin /bin ARG HOME=/opt/eturnal RUN set -x \ @@ -33,11 +35,8 @@ RUN set -x \ # RUNTIME: create symbolic links, entrypoint script and minimal configuration file && ln -s $HOME/bin/eturnalctl /usr/sbin/eturnalctl \ && ln -s $HOME/bin/stun /usr/sbin/stun \ - && chmod +x /usr/sbin/* + && chmod +x /etc/cont-init.d/* /etc/services.d/*/run -FROM gcr.io/distroless/base-debian11 AS cleanup -# BUILD: copy eturnal -COPY --from=eturnal --chown=9000:9000 / / # remove libssl and openssl from distroless image # as they are statically built within eturnal binary RUN find -type f -name 'libcrypt*' -exec rm -rv {} + \ @@ -49,10 +48,11 @@ RUN find -type f -name 'libcrypt*' -exec rm -rv {} + \ FROM scratch AS runtime # BUILD: copy eturnal -COPY --from=cleanup --chown=9000:9000 / / +COPY --from=eturnal / / ARG HOME=/opt/eturnal -# RUNTIME: define container runtime environment variables -ENV ERL_DIST_PORT=3470 \ +# RUNTIME: define environment variables +ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \ + ERL_DIST_PORT=3470 \ PIPE_DIR=$HOME/run/pipe/ \ STUN_SERVICE="stun.conversations.im 3478" @@ -61,5 +61,5 @@ WORKDIR $HOME #USER eturnal VOLUME ["$HOME"] EXPOSE 3478 3478/udp -ENTRYPOINT ["/tini","--","run.sh"] -CMD ["eturnalctl", "foreground"] \ No newline at end of file +ENTRYPOINT ["/init"] +#CMD ["eturnalctl", "foreground"] \ No newline at end of file diff --git a/eturnal/rootfs/usr/sbin/run.sh b/eturnal/rootfs/etc/cont-init.d/10-config similarity index 54% rename from eturnal/rootfs/usr/sbin/run.sh rename to eturnal/rootfs/etc/cont-init.d/10-config index 81b06325ea..6baf4cc944 100644 --- a/eturnal/rootfs/usr/sbin/run.sh +++ b/eturnal/rootfs/etc/cont-init.d/10-config @@ -1,4 +1,4 @@ -#!/bin/sh +#!/command/with-contenv /bin/sh # eturnal config #DOCKER_INTERNAL_IP=$(cat /etc/hosts | grep $(hostname) | awk '{ print $1 }') cat > /opt/eturnal/etc/eturnal.yml <> /opt/eturnal/etc/eturnal.yml if [ ! -z $TLS_CERT_FILE ]; then cp -p $TLS_CERT_FILE /opt/eturnal/tls - echo " tls_crt_file: /opt/eturnal/tls/fullchain.pem" >> /opt/eturnal/etc/eturnal.yml + sed -i -e "s|#tls_crt_file:|tls_crt_file:|g" /opt/eturnal/etc/eturnal.yml fi if [ ! -z $TLS_KEY_FILE ]; then cp -p $TLS_KEY_FILE /opt/eturnal/tls - echo " tls_key_file: /opt/eturnal/tls/key.pem" >> /opt/eturnal/etc/eturnal.yml + sed -i -e "s|#tls_key_file:|tls_key_file:|g" /opt/eturnal/etc/eturnal.yml fi + chown 9000:9000 /opt/eturnal/tls/* fi # change file permissions -chown 9000:9000 /opt/eturnal/etc/eturnal.yml +chown -R 9000:9000 /opt/eturnal/etc chmod 640 /opt/eturnal/etc/eturnal.yml -chown 9000:9000 /opt/eturnal/tls/* - -# start certificate renewal cronjob -#if [ ! -z $TURNS_HOST ] -#then -# crond -b -d -#fi - -# TURN credentials -if [ ! -z $TURN_CREDENTIALS ] -then -export ETURNAL_SECRET=$TURN_CREDENTIALS -fi - -# TURN relay port range -if [ ! -z $TURN_RELAY_MIN_PORT ] || [ ! -z $TURN_RELAY_MAX_PORT ] -then - if [ ${TURN_RELAY_MIN_PORT-50000} \< ${TURN_RELAY_MAX_PORT-50500} ] - then - export ETURNAL_RELAY_MIN_PORT=${TURN_RELAY_MIN_PORT-50000} - export ETURNAL_RELAY_MAX_PORT=${TURN_RELAY_MAX_PORT-50500} - else - echo "" - echo " Configuration check:" - echo "" - echo " [WARNING] Defined TURN range minimum port -> ${TURN_RELAY_MIN_PORT-50000} is greater or equal than maximum port -> ${TURN_RELAY_MAX_PORT-50500}" - echo " [INFO] Starting eturnal with relay port range 50000 - 50500" - echo "" - export ETURNAL_RELAY_MIN_PORT=50000 - export ETURNAL_RELAY_MAX_PORT=50500 - fi -else - export ETURNAL_RELAY_MIN_PORT=50000 - export ETURNAL_RELAY_MAX_PORT=50500 -fi - -# discover public IP addresses -if [ ! -z $DOCKER_HOST_ADDRESS ] -then - export ETURNAL_RELAY_IPV4_ADDR=$DOCKER_HOST_ADDRESS -else - if [ -z "$JVB_DISABLE_STUN" ] - then - export ETURNAL_RELAY_IPV4_ADDR=${ETURNAL_RELAY_IPV4_ADDR-$(stun -4 $STUN_SERVICE)} - fi -fi -exec "$@" \ No newline at end of file diff --git a/eturnal/rootfs/etc/services.d/cron/run b/eturnal/rootfs/etc/services.d/cron/run new file mode 100644 index 0000000000..a888b8a904 --- /dev/null +++ b/eturnal/rootfs/etc/services.d/cron/run @@ -0,0 +1,47 @@ +#!/command/with-contenv /bin/sh + +# only run the script if TURNS is enabled (and if acme.sh is used in web container) +if [ ! -z $TURNS_HOST ] || ([ ! -z $TURNS_HOST ] && [ $ENABLE_LETSENCRYPT -eq 1 ]); then + + while true; do + # sleep a sufficient time to give the web container's acme.sh script a chance to obtain certificates + sleep 60s + + # mounted certs from web container + TLS_CERT_FILE=$(find /etc/ -name fullchain.pem) + TLS_KEY_FILE=$(find /etc/ -name key.pem) + + # check if files have changed + if [ ! -z $TLS_CERT_FILE ] || [ ! -z $TLS_KEY_FILE ]; then + current=$(md5sum /opt/eturnal/tls/fullchain.pem | awk '{ print $1 }') + last_modified=$(md5sum $TLS_CERT_FILE | awk '{ print $1 }') + + # copy certs to eturnal, adjust configuration file + if [ "$current" != "$last_modified" ]; then + echo " $(date) [Info] TLS certificates have been renewed, copy certs to eturnal and reload" + + if [ ! -z $TLS_CERT_FILE ]; then + cp -p $TLS_CERT_FILE /opt/eturnal/tls + sed -i -e "s|#tls_crt_file:|tls_crt_file:|g" /opt/eturnal/etc/eturnal.yml + fi + + if [ ! -z $TLS_KEY_FILE ]; then + cp -p $TLS_KEY_FILE /opt/eturnal/tls + sed -i -e "s|#tls_key_file:|tls_key_file:|g" /opt/eturnal/etc/eturnal.yml + fi + + # fix ownership and reload the service (reloading eturnal does not stop/break any active sessions) + chown 9000:9000 /opt/eturnal/tls/* + eturnalctl reload + + else + echo " $(date) [Info] CronJob: TLS certificates have not been renewed, check again in 5 minutes" + fi + sleep 240s + fi + done + +# don't repeatedly run the cron job, if eturnal does not serve TURNS +else + s6-svc -O /var/run/s6/legacy-services/cron +fi \ No newline at end of file diff --git a/eturnal/rootfs/etc/services.d/eturnal/run b/eturnal/rootfs/etc/services.d/eturnal/run new file mode 100644 index 0000000000..ba7572356a --- /dev/null +++ b/eturnal/rootfs/etc/services.d/eturnal/run @@ -0,0 +1,43 @@ +#!/command/with-contenv /bin/sh + +# TURN credentials +if [ ! -z $TURN_CREDENTIALS ] +then +export ETURNAL_SECRET=$TURN_CREDENTIALS +fi + +# TURN relay port range +if [ ! -z $TURN_RELAY_MIN_PORT ] || [ ! -z $TURN_RELAY_MAX_PORT ] +then + if [ ${TURN_RELAY_MIN_PORT-50000} \< ${TURN_RELAY_MAX_PORT-50500} ] + then + export ETURNAL_RELAY_MIN_PORT=${TURN_RELAY_MIN_PORT-50000} + export ETURNAL_RELAY_MAX_PORT=${TURN_RELAY_MAX_PORT-50500} + else + echo "" + echo " $(date) [INFO] Configuration check:" + echo "" + echo " $(date) [WARNING] Defined TURN range minimum port -> ${TURN_RELAY_MIN_PORT-50000} is greater or equal than maximum port -> ${TURN_RELAY_MAX_PORT-50500}" + echo " $(date) [INFO] Starting eturnal with relay port range 50000 - 50500" + echo "" + export ETURNAL_RELAY_MIN_PORT=50000 + export ETURNAL_RELAY_MAX_PORT=50500 + fi +else + export ETURNAL_RELAY_MIN_PORT=50000 + export ETURNAL_RELAY_MAX_PORT=50500 +fi + +# discover public IP addresses +if [ ! -z $DOCKER_HOST_ADDRESS ] +then + export ETURNAL_RELAY_IPV4_ADDR=$DOCKER_HOST_ADDRESS +else + if [ -z "$JVB_DISABLE_STUN" ] + then + export ETURNAL_RELAY_IPV4_ADDR=${ETURNAL_RELAY_IPV4_ADDR-$(stun -4 $STUN_SERVICE)} + export ETURNAL_RELAY_IPV6_ADDR=${ETURNAL_RELAY_IPV6_ADDR-$(stun -6 $STUN_SERVICE)} + fi +fi + +exec eturnalctl foreground From b6cf144d5c7f0f6ce8ee2e6742d889be120e97a6 Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 11 Sep 2022 14:12:44 +0200 Subject: [PATCH 6/7] Let generate password also generate TURN_CREDENTIALS --- env.example | 49 +++++++++++++++++++++++++----------------------- gen-passwords.sh | 2 ++ 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/env.example b/env.example index 1116fb50b4..e5dd4e927c 100644 --- a/env.example +++ b/env.example @@ -177,28 +177,6 @@ ETHERPAD_SKIN_VARIANTS="super-light-toolbar super-light-editor light-background # Wether to use starttls, implies LDAPv3 and requires ldap:// instead of ldaps:// # LDAP_START_TLS=1 -# -# eturnal TURN Server configuration -# - -# TURN_CREDENTIALS=super-secret-password - -# currently hard coded to 'turn.$LETSENCRYPT_DOMAIN' -# TURN_HOST=turn.example.com - -# currently hard coded -# TURN_PORT=3478 - -# currently hard coded to 'turn.$LETSENCRYPT_DOMAIN' -# TURNS_HOST=turn.example.com - -# currently hard coded -# TURNS_PORT=443 - -# TURN relay port range -# TURN_RELAY_MIN_PORT=50000 -# TURN_RELAY_MAX_PORT=50500 - # # Security # @@ -224,6 +202,31 @@ JIBRI_RECORDER_PASSWORD= # XMPP password for Jibri client connections JIBRI_XMPP_PASSWORD= +# defines the shared authentication secret used to derive the passwords for ephemeral TURN user names +# TURN_CREDENTIALS= + + +# +# eturnal TURN Server configuration +# + +# currently hard coded to 'turn.$LETSENCRYPT_DOMAIN' (in web container) +# TURN_HOST=turn.example.com + +# currently hard coded (in web container) +# TURN_PORT=3478 + +# currently hard coded to 'turn.$LETSENCRYPT_DOMAIN' (in web container) +# TURNS_HOST=turn.example.com + +# currently hard coded (in web container) +# TURNS_PORT=443 + +# TURN relay port range +# TURN_RELAY_MIN_PORT=50000 +# TURN_RELAY_MAX_PORT=50500 + + # # Docker Compose options # @@ -232,4 +235,4 @@ JIBRI_XMPP_PASSWORD= #RESTART_POLICY=unless-stopped # Jitsi image version (useful for local development) -#JITSI_IMAGE_VERSION=latest +#JITSI_IMAGE_VERSION=latest \ No newline at end of file diff --git a/gen-passwords.sh b/gen-passwords.sh index 29aec9b785..c0852f8966 100755 --- a/gen-passwords.sh +++ b/gen-passwords.sh @@ -9,6 +9,7 @@ JVB_AUTH_PASSWORD=$(generatePassword) JIGASI_XMPP_PASSWORD=$(generatePassword) JIBRI_RECORDER_PASSWORD=$(generatePassword) JIBRI_XMPP_PASSWORD=$(generatePassword) +TURN_CREDENTIALS=$(generatePassword) sed -i.bak \ -e "s#JICOFO_AUTH_PASSWORD=.*#JICOFO_AUTH_PASSWORD=${JICOFO_AUTH_PASSWORD}#g" \ @@ -16,4 +17,5 @@ sed -i.bak \ -e "s#JIGASI_XMPP_PASSWORD=.*#JIGASI_XMPP_PASSWORD=${JIGASI_XMPP_PASSWORD}#g" \ -e "s#JIBRI_RECORDER_PASSWORD=.*#JIBRI_RECORDER_PASSWORD=${JIBRI_RECORDER_PASSWORD}#g" \ -e "s#JIBRI_XMPP_PASSWORD=.*#JIBRI_XMPP_PASSWORD=${JIBRI_XMPP_PASSWORD}#g" \ + -e "s#TURN_CREDENTIALS=.*#TURN_CREDENTIALS=${TURN_CREDENTIALS}#g" \ "$(dirname "$0")/.env" From 9516bf98fc21416915598b4b7f2efca8e196f185 Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 11 Sep 2022 17:13:30 +0200 Subject: [PATCH 7/7] Add port 443 udp listener and include libcap binaries and libraries into the docker image to enable linux capabilities. --- docker-compose.yml | 1 + eturnal/Dockerfile | 12 +++++++++--- eturnal/rootfs/etc/cont-init.d/10-config | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b3eb365b55..69841caca2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -344,6 +344,7 @@ services: image: jitsi/eturnal:${JITSI_IMAGE_VERSION:-unstable} restart: ${RESTART_POLICY:-unless-stopped} ports: + - 443:443/udp - '${TURN_RELAY_MIN_PORT:-50000}-${TURN_RELAY_MAX_PORT:-50500}:${TURN_RELAY_MIN_PORT:-50000}-${TURN_RELAY_MAX_PORT:-50500}/udp' security_opt: - no-new-privileges:true diff --git a/eturnal/Dockerfile b/eturnal/Dockerfile index d6bfce4ce0..2a5204edf2 100644 --- a/eturnal/Dockerfile +++ b/eturnal/Dockerfile @@ -5,7 +5,7 @@ ARG TINI_VERSION=0.19.0 ARG S6_VERSION=v3.1.2.1 RUN set -x \ - && apt-get update && apt-get install apt-transport-https apt-utils ca-certificates curl wget xz-utils -y \ + && apt-get update && apt-get install apt-transport-https apt-utils ca-certificates curl wget xz-utils libcap2-bin gcc -y \ # RUNTIME: install eturnal binary with installer && ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/;s/armv7l/arm/;s/s390x/s390x/;s/ppc64le/ppc64le/') \ && curl -O https://eturnal.net/download/linux/installer/eturnal-$ETURNAL_VERSION-linux-$ARCH.run \ @@ -18,7 +18,12 @@ RUN set -x \ # RUNTIME: install runtime init && ARCH=$(uname -m) \ && wget -qO - https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-noarch.tar.xz | tar xfJ - -C /rootfs \ - && wget -qO - https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-$ARCH.tar.xz | tar xfJ - -C /rootfs + && wget -qO - https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-$ARCH.tar.xz | tar xfJ - -C /rootfs \ +# RUNTIME: copy libcap binaries and libraries + && gccMultiarch="$(gcc -print-multiarch)" \ + && mkdir -p /rootfs/sbin /rootfs/lib/$gccMultiarch/ \ + && cp -r /sbin/capsh /sbin/getcap /sbin/getpcaps /sbin/setcap /rootfs/sbin \ + && cp -r /lib/$gccMultiarch/libcap*.so.* /rootfs/lib/$gccMultiarch/ # RUNTIME: copy s6 scripts COPY rootfs /rootfs @@ -35,7 +40,8 @@ RUN set -x \ # RUNTIME: create symbolic links, entrypoint script and minimal configuration file && ln -s $HOME/bin/eturnalctl /usr/sbin/eturnalctl \ && ln -s $HOME/bin/stun /usr/sbin/stun \ - && chmod +x /etc/cont-init.d/* /etc/services.d/*/run + && chmod +x /etc/cont-init.d/* /etc/services.d/*/run \ + && setcap 'cap_net_bind_service=+ep' $(find $HOME -name beam.smp) # remove libssl and openssl from distroless image # as they are statically built within eturnal binary diff --git a/eturnal/rootfs/etc/cont-init.d/10-config b/eturnal/rootfs/etc/cont-init.d/10-config index 6baf4cc944..33ef5ff592 100644 --- a/eturnal/rootfs/etc/cont-init.d/10-config +++ b/eturnal/rootfs/etc/cont-init.d/10-config @@ -4,6 +4,10 @@ cat > /opt/eturnal/etc/eturnal.yml <