diff --git a/alpine/Dockerfile b/alpine/Dockerfile index 73ef1034a..61cca3761 100644 --- a/alpine/Dockerfile +++ b/alpine/Dockerfile @@ -11,38 +11,10 @@ RUN set -eux; \ apk add --no-cache \ # add tzdata for https://github.com/docker-library/redis/issues/138 tzdata \ +# we need setpriv package as busybox provides very limited functionality + setpriv \ ; -# grab gosu for easy step-down from root -# https://github.com/tianon/gosu/releases -ENV GOSU_VERSION=1.17 -RUN set -eux; \ - apk add --no-cache --virtual .gosu-fetch gnupg; \ - arch="$(apk --print-arch)"; \ - case "$arch" in \ - 'x86_64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-amd64'; sha256='bbc4136d03ab138b1ad66fa4fc051bafc6cc7ffae632b069a53657279a450de3' ;; \ - 'aarch64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-arm64'; sha256='c3805a85d17f4454c23d7059bcb97e1ec1af272b90126e79ed002342de08389b' ;; \ - 'armhf') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armhf'; sha256='e5866286277ff2a2159fb9196fea13e0a59d3f1091ea46ddb985160b94b6841b' ;; \ - 'x86') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-i386'; sha256='087dbb8fe479537e64f9c86fa49ff3b41dee1cbd28739a19aaef83dc8186b1ca' ;; \ - 'ppc64le') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-ppc64el'; sha256='1891acdcfa70046818ab6ed3c52b9d42fa10fbb7b340eb429c8c7849691dbd76' ;; \ - 'riscv64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-riscv64'; sha256='38a6444b57adce135c42d5a3689f616fc7803ddc7a07ff6f946f2ebc67a26ba6' ;; \ - 's390x') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-s390x'; sha256='69873bab588192f760547ca1f75b27cfcf106e9f7403fee6fd0600bc914979d0' ;; \ - 'armv7') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armhf'; sha256='e5866286277ff2a2159fb9196fea13e0a59d3f1091ea46ddb985160b94b6841b' ;; \ - *) echo >&2 "error: unsupported gosu architecture: '$arch'"; exit 1 ;; \ - esac; \ - wget -O /usr/local/bin/gosu.asc "$url.asc"; \ - wget -O /usr/local/bin/gosu "$url"; \ - echo "$sha256 */usr/local/bin/gosu" | sha256sum -c -; \ - export GNUPGHOME="$(mktemp -d)"; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - apk del --no-network .gosu-fetch; \ - chmod +x /usr/local/bin/gosu; \ - gosu --version; \ - gosu nobody true - ENV REDIS_DOWNLOAD_URL=https://github.com/redis/redis/archive/refs/tags/8.0-m04.tar.gz ENV REDIS_DOWNLOAD_SHA=6902a938c629a33f14d49881b1b60e6621c29e445554f882ce7ec48f2743d516 RUN set -eux; \ diff --git a/alpine/docker-entrypoint.sh b/alpine/docker-entrypoint.sh index 15e6c02c1..ab5befbf8 100755 --- a/alpine/docker-entrypoint.sh +++ b/alpine/docker-entrypoint.sh @@ -1,16 +1,37 @@ #!/bin/sh set -e +has_cap() { + /usr/bin/setpriv -d | grep -q 'Capability bounding set:.*\b'$1'\b' +} + # first arg is `-f` or `--some-option` # or first arg is `something.conf` if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then set -- redis-server "$@" fi -# allow the container to be started with `--user` -if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then +CMD=$(realpath $(command -v "$1") 2>/dev/null || :) +# drop privileges only if our uid is 0 (container started without explicit --user) +# and we have capabilities required to drop privs +if has_cap setuid && has_cap setgid && \ + [ \( "$CMD" = '/usr/local/bin/redis-server' -o "$CMD" = '/usr/local/bin/redis-sentinel' \) -a "$(id -u)" = '0' ]; then find . \! -user redis -exec chown redis '{}' + - exec gosu redis "$0" "$@" + CAPS_TO_KEEP="" + if has_cap sys_resource; then + # we have sys_resource capability, keep it available for redis + # as redis may use it to increase open files limit + CAPS_TO_KEEP=",+sys_resource" + fi + exec /usr/bin/setpriv \ + --reuid redis \ + --regid redis \ + --clear-groups \ + --nnp \ + --inh-caps=-all$CAPS_TO_KEEP \ + --ambient-caps=-all$CAPS_TO_KEEP \ + --bounding-set=-all$CAPS_TO_KEEP \ + "$0" "$@" fi # set an appropriate umask (if one isn't set already) @@ -56,4 +77,4 @@ if [ "$1" = 'redis-server' ]; then fi -exec "$@" \ No newline at end of file +exec "$@" diff --git a/debian/Dockerfile b/debian/Dockerfile index 69ee90fbd..8a6f78900 100644 --- a/debian/Dockerfile +++ b/debian/Dockerfile @@ -14,45 +14,8 @@ RUN set -eux; \ ; \ rm -rf /var/lib/apt/lists/* -# grab gosu for easy step-down from root -# https://github.com/tianon/gosu/releases -ENV GOSU_VERSION=1.17 -RUN set -eux; \ - savedAptMark="$(apt-mark showmanual)"; \ - apt-get update; \ - apt-get install -y --no-install-recommends ca-certificates gnupg wget; \ - rm -rf /var/lib/apt/lists/*; \ - arch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ - case "$arch" in \ - 'amd64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-amd64'; sha256='bbc4136d03ab138b1ad66fa4fc051bafc6cc7ffae632b069a53657279a450de3' ;; \ - 'arm64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-arm64'; sha256='c3805a85d17f4454c23d7059bcb97e1ec1af272b90126e79ed002342de08389b' ;; \ - 'armel') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armel'; sha256='f9969910fa141140438c998cfa02f603bf213b11afd466dcde8fa940e700945d' ;; \ - 'i386') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-i386'; sha256='087dbb8fe479537e64f9c86fa49ff3b41dee1cbd28739a19aaef83dc8186b1ca' ;; \ - 'mips64el') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-mips64el'; sha256='87140029d792595e660be0015341dfa1c02d1181459ae40df9f093e471d75b70' ;; \ - 'ppc64el') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-ppc64el'; sha256='1891acdcfa70046818ab6ed3c52b9d42fa10fbb7b340eb429c8c7849691dbd76' ;; \ - 'riscv64') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-riscv64'; sha256='38a6444b57adce135c42d5a3689f616fc7803ddc7a07ff6f946f2ebc67a26ba6' ;; \ - 's390x') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-s390x'; sha256='69873bab588192f760547ca1f75b27cfcf106e9f7403fee6fd0600bc914979d0' ;; \ - 'armhf') url='https://github.com/tianon/gosu/releases/download/1.17/gosu-armhf'; sha256='e5866286277ff2a2159fb9196fea13e0a59d3f1091ea46ddb985160b94b6841b' ;; \ - *) echo >&2 "error: unsupported gosu architecture: '$arch'"; exit 1 ;; \ - esac; \ - wget -O /usr/local/bin/gosu.asc "$url.asc"; \ - wget -O /usr/local/bin/gosu "$url"; \ - echo "$sha256 */usr/local/bin/gosu" | sha256sum -c -; \ - export GNUPGHOME="$(mktemp -d)"; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - apt-mark auto '.*' > /dev/null; \ - [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ - chmod +x /usr/local/bin/gosu; \ - gosu --version; \ - gosu nobody true - ENV REDIS_DOWNLOAD_URL=https://github.com/redis/redis/archive/refs/tags/8.0-m04.tar.gz ENV REDIS_DOWNLOAD_SHA=6902a938c629a33f14d49881b1b60e6621c29e445554f882ce7ec48f2743d516 - RUN set -eux; \ \ savedAptMark="$(apt-mark showmanual)"; \ diff --git a/debian/docker-entrypoint.sh b/debian/docker-entrypoint.sh index 15e6c02c1..ab5befbf8 100755 --- a/debian/docker-entrypoint.sh +++ b/debian/docker-entrypoint.sh @@ -1,16 +1,37 @@ #!/bin/sh set -e +has_cap() { + /usr/bin/setpriv -d | grep -q 'Capability bounding set:.*\b'$1'\b' +} + # first arg is `-f` or `--some-option` # or first arg is `something.conf` if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then set -- redis-server "$@" fi -# allow the container to be started with `--user` -if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then +CMD=$(realpath $(command -v "$1") 2>/dev/null || :) +# drop privileges only if our uid is 0 (container started without explicit --user) +# and we have capabilities required to drop privs +if has_cap setuid && has_cap setgid && \ + [ \( "$CMD" = '/usr/local/bin/redis-server' -o "$CMD" = '/usr/local/bin/redis-sentinel' \) -a "$(id -u)" = '0' ]; then find . \! -user redis -exec chown redis '{}' + - exec gosu redis "$0" "$@" + CAPS_TO_KEEP="" + if has_cap sys_resource; then + # we have sys_resource capability, keep it available for redis + # as redis may use it to increase open files limit + CAPS_TO_KEEP=",+sys_resource" + fi + exec /usr/bin/setpriv \ + --reuid redis \ + --regid redis \ + --clear-groups \ + --nnp \ + --inh-caps=-all$CAPS_TO_KEEP \ + --ambient-caps=-all$CAPS_TO_KEEP \ + --bounding-set=-all$CAPS_TO_KEEP \ + "$0" "$@" fi # set an appropriate umask (if one isn't set already) @@ -56,4 +77,4 @@ if [ "$1" = 'redis-server' ]; then fi -exec "$@" \ No newline at end of file +exec "$@"