From 0317da0390420ee0e4023bf1f9419f73976c30c5 Mon Sep 17 00:00:00 2001 From: David Heaps Date: Sat, 3 Feb 2024 14:12:05 -0800 Subject: [PATCH 1/5] Combined the master and base docker images to create a minimized (app and dependency only) image based and the latest Debian images Moved from from tar to cp and shell scripting for consistency and correct racing conditions documented in the shell script Added erlang-base, curl, and ca-certificates Copied ca-certificates, so Curl functions properly (including internally to freeswitch) Fixed sound file downloading Increased the complexity of the default generated password Merged sudo process, but moved to su-exec from gosu, to clear vulnerabilities Update Debian distro before freeswitch install, to keep dependencies fully up to date Updated to the latest Busybox --- docker/master-min/Dockerfile | 92 +++++++ docker/master-min/README.md | 103 ++++++++ .../master-min/build/freeswitch.limits.conf | 15 ++ docker/master-min/docker-entrypoint.sh | 141 +++++++++++ docker/master-min/freeswitch-config.patch | 30 +++ docker/master-min/healthcheck.sh | 41 ++++ docker/master-min/hooks/build | 7 + docker/master-min/make_root_fs.sh | 230 ++++++++++++++++++ docker/master-min/sounds_version.txt | 11 + 9 files changed, 670 insertions(+) create mode 100644 docker/master-min/Dockerfile create mode 100644 docker/master-min/README.md create mode 100644 docker/master-min/build/freeswitch.limits.conf create mode 100755 docker/master-min/docker-entrypoint.sh create mode 100644 docker/master-min/freeswitch-config.patch create mode 100755 docker/master-min/healthcheck.sh create mode 100644 docker/master-min/hooks/build create mode 100755 docker/master-min/make_root_fs.sh create mode 100644 docker/master-min/sounds_version.txt diff --git a/docker/master-min/Dockerfile b/docker/master-min/Dockerfile new file mode 100644 index 0000000000..0856ed955f --- /dev/null +++ b/docker/master-min/Dockerfile @@ -0,0 +1,92 @@ +# vim:set ft=dockerfile: +ARG DEBIAN_VERSION=bookworm +FROM debian:${DEBIAN_VERSION} as stage +ENV LANG en_US.utf8 + +# ARGs are cleared after every FROM +# see: https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact +ARG DEBIAN_VERSION +ARG TOKEN + +# By default, install the full set of FreeSWITCH packages. Specify an alternative with: +# --build-arg="FS_META_PACKAGE=freeswitch-meta-vanilla" +# alternatives include: +# freeswitch-meta-bare +# freeswitch-meta-vanilla +# freeswitch-meta-sorbet +# freeswitch-meta-all-dbg +ARG FS_META_PACKAGE=freeswitch-meta-all + +# Source Dockerfile: +# https://github.com/docker-library/postgres/blob/master/9.4/Dockerfile + +# make the "en_US.UTF-8" locale so freeswitch will be utf-8 enabled by default +RUN apt-get update -qq && \ + apt-get dist-upgrade && \ + apt-get install -y --no-install-recommends locales ca-certificates gnupg2 gcc libc-dev patch wget curl && \ + localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \ + curl -o /busybox.deb http://ftp.us.debian.org/debian/pool/main/b/busybox/busybox_1.36.1-6_amd64.deb && \ + dpkg -i /busybox.deb && rm /busybox.deb && \ + curl -o /usr/local/bin/su-exec.c https://raw.githubusercontent.com/ncopa/su-exec/master/su-exec.c && \ + gcc -Wall /usr/local/bin/su-exec.c -o/usr/local/bin/su-exec && \ + chown root:root /usr/local/bin/su-exec && \ + chmod 0755 /usr/local/bin/su-exec && \ + rm /usr/local/bin/su-exec.c + +# https://freeswitch.org/confluence/display/FREESWITCH/Debian +# https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/Installation/Linux/Debian_67240088/ +RUN wget --no-verbose --http-user=signalwire --http-password=${TOKEN} \ + -O /usr/share/keyrings/signalwire-freeswitch-repo.gpg \ + https://freeswitch.signalwire.com/repo/deb/debian-release/signalwire-freeswitch-repo.gpg \ + && echo "machine freeswitch.signalwire.com login signalwire password ${TOKEN}" > /etc/apt/auth.conf \ + && echo "deb [signed-by=/usr/share/keyrings/signalwire-freeswitch-repo.gpg] https://freeswitch.signalwire.com/repo/deb/debian-release/ ${DEBIAN_VERSION} main" > /etc/apt/sources.list.d/freeswitch.list \ + && apt-get -qq update \ + && apt-get install -y ${FS_META_PACKAGE} \ + && rm /etc/apt/auth.conf \ + && apt-get purge -y --auto-remove wget gcc libc-dev \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +#Create the new root in a separate layer +COPY make_root_fs.sh freeswitch-config.patch / +RUN sh /make_root_fs.sh + +FROM scratch +ENV LANG en_US.utf8 + +COPY --from=stage /tmp/freeswitch / +COPY docker-entrypoint.sh healthcheck.sh sounds_version.txt / + +# explicitly set user/group IDs +ARG FREESWITCH_UID=499 +ARG FREESWITCH_GID=499 +RUN groupadd -r freeswitch --gid=${FREESWITCH_GID} && useradd -r -g freeswitch --uid=${FREESWITCH_UID} freeswitch && \ + mkdir -p /var/log/freeswitch && mkdir -p /var/run/freeswitch + +## Ports +# Document ports used by this container +### 8021 fs_cli, 5060 5061 5080 5081 sip and sips, 5066 ws, 7443 wss, 8081 8082 verto, 16384-32768, 64535-65535 rtp +EXPOSE 8021/tcp +EXPOSE 5060/tcp 5060/udp 5080/tcp 5080/udp +EXPOSE 5061/tcp 5061/udp 5081/tcp 5081/udp +EXPOSE 5066/tcp +EXPOSE 7443/tcp +EXPOSE 8081/tcp 8082/tcp +EXPOSE 64535-65535/udp +EXPOSE 16384-32768/udp + +# Volumes +## Freeswitch Configuration +VOLUME ["/etc/freeswitch"] +## Tmp so we can get core dumps out +VOLUME ["/tmp"] + +# Limits Configuration +COPY build/freeswitch.limits.conf /etc/security/limits.d/ + +# Healthcheck to make sure the service is running +SHELL ["/bin/bash", "-c"] +HEALTHCHECK --interval=15s --timeout=5s \ + CMD fs_cli -x status | grep -q ^UP || exit 1 + +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["freeswitch"] diff --git a/docker/master-min/README.md b/docker/master-min/README.md new file mode 100644 index 0000000000..1293966804 --- /dev/null +++ b/docker/master-min/README.md @@ -0,0 +1,103 @@ +About +----- + +This is an updated, minimized, official FreeSwitch docker image. +Container designed to run on host network. +Size of image decreased to 120MB (54MB compressed) +Significantly increased security: +1) removed all libs except libc, busybox, erlang, ca-certificates, gnupg2, passwd, curl, freeswitch and dependent libs. +2) removed 'system' API command from vanila config +3) updated FreeSwitch default SIP password to random value + +Used environment variables +-------------------------- + +1) ```SOUND_RATES``` - rates of sound files that must be downloaded and installed. Available values ```8000```, ```16000```, ```32000```, ```48000```. May defined multiply values using semicolon as delimiter. Example ```SOUND_RATES=8000:16000```; +2) ```SOUND_TYPES``` - types of sound files that must be downloaded and installed. Available values music, ```en-us-callie```, ```en-us-allison```, ```ru-RU-elena```, ```en-ca-june```, ```fr-ca-june```, ```pt-BR-karina```, ```sv-se-jakob```, ```zh-cn-sinmei```, ```zh-hk-sinmei```. Example ```SOUND_TYPES=music:en-us-callie```; +3) ```EPMD``` - start epmd daemon, useful when you use mod_erlang and mod_kazoo FreeSwitch modules. Available values ```true```, ```false```. + +Usage container +--------------- + +1) Creating volume for sound files. This may be skipped if you not use freeswitch MOH and other sound files. +```sh +docker volume create --name freeswitch-sounds +``` + +2) Stating container +```sh +docker run --net=host --name freeswitch \ + -e SOUND_RATES=8000:16000 \ + -e SOUND_TYPES=music:en-us-callie \ + -v freeswitch-sounds:/usr/share/freeswitch/sounds \ + -v /etc/freeswitch/:/etc/freeswitch \ + dheaps/freeswitch +``` + +systemd unit file +----------------- +You can use this systemd unit file on your hosts. +```sh +$ cat /etc/systemd/system/freeswitch-docker.service +[Unit] +Description=freeswitch Container +After=docker.service network-online.target +Requires=docker.service + + +[Service] +Restart=always +TimeoutStartSec=0 +#One ExecStart/ExecStop line to prevent hitting bugs in certain systemd versions +ExecStart=/bin/sh -c 'docker rm -f freeswitch; \ + docker run -t --net=host --name freeswitch \ + -e SOUND_RATES=8000:16000 \ + -e SOUND_TYPES=music:en-us-callie \ + -v freeswitch-sounds:/usr/share/freeswitch/sounds \ + -v /etc/kazoo/freeswitch/:/etc/freeswitch \ + dheaps/freeswitch' +ExecStop=-/bin/sh -c '/usr/bin/docker stop freeswitch; \ + /usr/bin/docker rm -f freeswitch;' + +[Install] +WantedBy=multi-user.target +``` +Unit file can be placed to ```/etc/systemd/system/freeswitch-docker.service``` and enabled by command +```sh +systemd start freeswitch-docker.service +systemd enable freeswitch-docker.service +``` + +.bashrc file +------------ +To simplify freeswitch management you can add alias for ```fs_cli``` to ```.bashrc``` file as example bellow. +```sh +alias fs_cli='docker exec -i -t freeswitch /usr/bin/fs_cli' +``` + +How to create custom container +------------------------------ +This container created from scratch image by addiding required freeswitch files packaged to tar.gz archive. +To create custom container: + +1. clone freeswitch repo +```sh +git clone https://github.com/signalwire/freeswitch.git +``` +2. modify ```freeswitch/docker/master-min/Dockerfile``` with customizations + - Stage files are not inlcuded by default, but is the place to add additional packages/dependancies +3. modify ```freeswitch/docker/master-min/make_root_fs.sh``` with customizations + - If files/packages were added to the stage image add them here + - Additional installed packages should be added to the PACKAGES variable in fs_files_debian() + - Additinoal installed files should be added in make_new_root() +4. build custom container +```sh +docker build -t freeswitch_custom . +``` + +Read more +--------- + +[Dockerfile of older official FreeSwitch image](https://github.com/signalwire/freeswitch/tree/master/docker/release) +[Dockerfile of the updated FreeSwitch image that this image is based on](https://github.com/signalwire/freeswitch/tree/master/docker/master) +[Dockerfile of minimized base image FreeSwitch image that this image is based on](https://github.com/signalwire/freeswitch/tree/master/docker/base_image) diff --git a/docker/master-min/build/freeswitch.limits.conf b/docker/master-min/build/freeswitch.limits.conf new file mode 100644 index 0000000000..d6568ebe4a --- /dev/null +++ b/docker/master-min/build/freeswitch.limits.conf @@ -0,0 +1,15 @@ +freeswitch soft core unlimited +freeswitch soft data unlimited +freeswitch soft fsize unlimited +freeswitch soft memlock unlimited +freeswitch soft nofile 999999 +freeswitch soft rss unlimited +freeswitch hard stack 240 +freeswitch soft cpu unlimited +freeswitch soft nproc unlimited +freeswitch soft as unlimited +freeswitch soft priority -11 +freeswitch soft locks unlimited +freeswitch soft sigpending unlimited +freeswitch soft msgqueue unlimited +freeswitch soft nice -11 diff --git a/docker/master-min/docker-entrypoint.sh b/docker/master-min/docker-entrypoint.sh new file mode 100755 index 0000000000..35ca4fcdb0 --- /dev/null +++ b/docker/master-min/docker-entrypoint.sh @@ -0,0 +1,141 @@ +#!/bin/sh +# +# FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +# Copyright (C) 2005-2016, Anthony Minessale II +# +# Version: MPL 1.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/F +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +# +# The Initial Developer of the Original Code is +# Michael Jerris +# Portions created by the Initial Developer are Copyright (C) +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Sergey Safarov +# + +if [ "$1" = 'freeswitch' ]; then + BASEURL=https://files.freeswitch.org/releases/sounds/ + PID_FILE=/var/run/freeswitch/freeswitch.pid + + get_password() { + < /dev/urandom tr -dc _A-Z-a-z-0-9\!\^\*\$\#\@\% | head -c${1:-24};echo; + } + + get_sound_version() { + local SOUND_TYPE=$1 + grep "$SOUND_TYPE" sounds_version.txt | sed -E "s/$SOUND_TYPE\s+//" + } + + wget_helper() { + local SOUND_FILE=$1 + grep -q $SOUND_FILE /usr/share/freeswitch/sounds/soundfiles_present.txt 2> /dev/null + if [ "$?" -eq 0 ]; then + echo "Skipping download of $SOUND_FILE. Already present" + return + fi + curl "$BASEURL/$SOUND_FILE" > "$SOUND_FILE" + if [ -f $SOUND_FILE ]; then + echo $SOUND_FILE >> /usr/share/freeswitch/sounds/soundfiles_present.txt + fi + } + + download_sound_rates() { + local i + local f + local SOUND_TYPE=$1 + local SOUND_VERSION=$2 + + for i in $SOUND_RATES + do + f=freeswitch-sounds-$SOUND_TYPE-$i-$SOUND_VERSION.tar.gz + echo "Downloading $f" + wget_helper $f + done + } + + download_sound_types() { + local i + local SOUND_VERSION + for i in $SOUND_TYPES + do + SOUND_VERSION=$(get_sound_version $i) + download_sound_rates $i $SOUND_VERSION + done + } + + extract_sound_files() { + local SOUND_FILES=freeswitch-sounds-*.tar.gz + for f in $SOUND_FILES + do + if [ -f $f ]; then + echo "Extracting file $f" + tar xzf "$f" -C /usr/share/freeswitch/sounds/ + fi + done + } + + delete_archives() { + local FILES_COUNT=$(ls -1 freeswitch-sounds-*.tar.gz 2> /dev/null | wc -l) + if [ "$FILES_COUNT" -ne 0 ]; then + echo "Removing downloaded 'tar.gz' archives" + rm -f freeswitch-sounds-*.tar.gz + fi + } + + SOUND_RATES=$(echo "$SOUND_RATES" | sed -e 's/:/\n/g') + SOUND_TYPES=$(echo "$SOUND_TYPES" | sed -e 's/:/\n/g') + + if [ -z "$SOUND_RATES" -o -z "$SOUND_TYPES" ]; then + echo "Environment variables 'SOUND_RATES' or 'SOUND_TYPES' not defined. Skipping sound files checking." + else + download_sound_types + extract_sound_files + delete_archives + fi + + if [ "$EPMD" = "true" ]; then + /usr/bin/epmd -daemon + fi + + if [ ! -f "/etc/freeswitch/freeswitch.xml" ]; then + SIP_PASSWORD=$(get_password) + mkdir -p /etc/freeswitch + cp -varf /usr/share/freeswitch/conf/vanilla/* /etc/freeswitch/ + sed -i -e "s/default_password=.*\?/default_password=$SIP_PASSWORD\"/" /etc/freeswitch/vars.xml + echo "New FreeSwitch password for SIP calls set to '$SIP_PASSWORD'" + fi + + chown -R freeswitch:freeswitch /etc/freeswitch + chown -R freeswitch:freeswitch /var/lib/freeswitch + chown -R freeswitch:freeswitch /var/run/freeswitch + chown -R freeswitch:freeswitch /var/log/freeswitch + + trap '/usr/bin/freeswitch -stop' TERM + + if [ -d /docker-entrypoint.d ]; then + for f in /docker-entrypoint.d/*.sh; do + [ -f "$f" ] && . "$f" + done + fi + su-exec freeswitch:freeswitch /usr/bin/freeswitch -nonat -c & + pid="$!" + + wait $pid + exit 0 +fi + +exec "$@" \ No newline at end of file diff --git a/docker/master-min/freeswitch-config.patch b/docker/master-min/freeswitch-config.patch new file mode 100644 index 0000000000..e20d51a37a --- /dev/null +++ b/docker/master-min/freeswitch-config.patch @@ -0,0 +1,30 @@ +diff -ur a/usr/share/freeswitch/conf/vanilla/autoload_configs/logfile.conf.xml b/usr/share/freeswitch/conf/vanilla/autoload_configs/logfile.conf.xml +--- a/usr/share/freeswitch/conf/vanilla/autoload_configs/logfile.conf.xml 2017-06-13 13:15:43.000000000 +0000 ++++ b/usr/share/freeswitch/conf/vanilla/autoload_configs/logfile.conf.xml 2017-07-02 18:38:58.000000000 +0000 +@@ -25,5 +25,15 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + +diff -ur a/usr/share/freeswitch/conf/vanilla/vars.xml b/usr/share/freeswitch/conf/vanilla/vars.xml +--- a/usr/share/freeswitch/conf/vanilla/vars.xml 2017-06-13 13:15:43.000000000 +0000 ++++ b/usr/share/freeswitch/conf/vanilla/vars.xml 2017-07-02 18:38:58.000000000 +0000 +@@ -13,6 +13,7 @@ + WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + --> + ++ + +