allow running as arbitrary uid (#151)
* Adds guards around entrypoints commands that require root
* Broaden permissions within the container filesystem to allow
access by non-couchdb users.
* Added an example to the documentation which specifies `--user`.
Fixes #147
diff --git a/2.3.1/Dockerfile b/2.3.1/Dockerfile
index a266ed8..f8ad0c9 100644
--- a/2.3.1/Dockerfile
+++ b/2.3.1/Dockerfile
@@ -19,77 +19,77 @@
# be sure GPG and apt-transport-https are available and functional
RUN set -ex; \
- apt-get update; \
- apt-get install -y --no-install-recommends \
- apt-transport-https \
- ca-certificates \
- dirmngr \
- gnupg \
- ; \
- rm -rf /var/lib/apt/lists/*
+ apt-get update; \
+ apt-get install -y --no-install-recommends \
+ apt-transport-https \
+ ca-certificates \
+ dirmngr \
+ gnupg \
+ ; \
+ rm -rf /var/lib/apt/lists/*
# grab gosu for easy step-down from root and tini for signal handling and zombie reaping
# see https://github.com/apache/couchdb-docker/pull/28#discussion_r141112407
ENV GOSU_VERSION 1.11
ENV TINI_VERSION 0.18.0
RUN set -ex; \
- \
- apt-get update; \
- apt-get install -y --no-install-recommends wget; \
- rm -rf /var/lib/apt/lists/*; \
- \
- dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
- \
+ \
+ apt-get update; \
+ apt-get install -y --no-install-recommends wget; \
+ rm -rf /var/lib/apt/lists/*; \
+ \
+ dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
+ \
# install gosu
- wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-$dpkgArch"; \
- wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
- export GNUPGHOME="$(mktemp -d)"; \
- echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
- for server in $(shuf -e pgpkeys.mit.edu \
- ha.pool.sks-keyservers.net \
- hkp://p80.pool.sks-keyservers.net:80 \
- pgp.mit.edu) ; do \
- gpg --batch --keyserver $server --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && break || : ; \
- done; \
- gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
- rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
- chmod +x /usr/local/bin/gosu; \
- gosu nobody true; \
+ wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-$dpkgArch"; \
+ wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
+ export GNUPGHOME="$(mktemp -d)"; \
+ echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
+ for server in $(shuf -e pgpkeys.mit.edu \
+ ha.pool.sks-keyservers.net \
+ hkp://p80.pool.sks-keyservers.net:80 \
+ pgp.mit.edu) ; do \
+ gpg --batch --keyserver $server --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && break || : ; \
+ done; \
+ gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
+ rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
+ chmod +x /usr/local/bin/gosu; \
+ gosu nobody true; \
\
# install tini
- wget -O /usr/local/bin/tini "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch"; \
- wget -O /usr/local/bin/tini.asc "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch.asc"; \
- export GNUPGHOME="$(mktemp -d)"; \
- echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
- for server in $(shuf -e pgpkeys.mit.edu \
- ha.pool.sks-keyservers.net \
- hkp://p80.pool.sks-keyservers.net:80 \
- pgp.mit.edu) ; do \
- gpg --batch --keyserver $server --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 && break || : ; \
- done; \
- gpg --batch --verify /usr/local/bin/tini.asc /usr/local/bin/tini; \
- rm -rf "$GNUPGHOME" /usr/local/bin/tini.asc; \
- chmod +x /usr/local/bin/tini; \
- apt-get purge -y --auto-remove wget; \
- tini --version
+ wget -O /usr/local/bin/tini "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch"; \
+ wget -O /usr/local/bin/tini.asc "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch.asc"; \
+ export GNUPGHOME="$(mktemp -d)"; \
+ echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
+ for server in $(shuf -e pgpkeys.mit.edu \
+ ha.pool.sks-keyservers.net \
+ hkp://p80.pool.sks-keyservers.net:80 \
+ pgp.mit.edu) ; do \
+ gpg --batch --keyserver $server --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 && break || : ; \
+ done; \
+ gpg --batch --verify /usr/local/bin/tini.asc /usr/local/bin/tini; \
+ rm -rf "$GNUPGHOME" /usr/local/bin/tini.asc; \
+ chmod +x /usr/local/bin/tini; \
+ apt-get purge -y --auto-remove wget; \
+ tini --version
# http://docs.couchdb.org/en/latest/install/unix.html#installing-the-apache-couchdb-packages
ENV GPG_COUCH_KEY \
# gpg: key D401AB61: public key "Bintray (by JFrog) <bintray@bintray.com> imported
- 8756C4F765C9AC3CB6B85D62379CE192D401AB61
+ 8756C4F765C9AC3CB6B85D62379CE192D401AB61
RUN set -xe; \
- export GNUPGHOME="$(mktemp -d)"; \
- echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
- for server in $(shuf -e pgpkeys.mit.edu \
- ha.pool.sks-keyservers.net \
- hkp://p80.pool.sks-keyservers.net:80 \
- pgp.mit.edu) ; do \
- gpg --batch --keyserver $server --recv-keys $GPG_COUCH_KEY && break || : ; \
- done; \
- gpg --batch --export $GPG_COUCH_KEY > /etc/apt/trusted.gpg.d/couchdb.gpg; \
- command -v gpgconf && gpgconf --kill all || :; \
- rm -rf "$GNUPGHOME"; \
- apt-key list
+ export GNUPGHOME="$(mktemp -d)"; \
+ echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
+ for server in $(shuf -e pgpkeys.mit.edu \
+ ha.pool.sks-keyservers.net \
+ hkp://p80.pool.sks-keyservers.net:80 \
+ pgp.mit.edu) ; do \
+ gpg --batch --keyserver $server --recv-keys $GPG_COUCH_KEY && break || : ; \
+ done; \
+ gpg --batch --export $GPG_COUCH_KEY > /etc/apt/trusted.gpg.d/couchdb.gpg; \
+ command -v gpgconf && gpgconf --kill all || :; \
+ rm -rf "$GNUPGHOME"; \
+ apt-key list
ENV COUCHDB_VERSION 2.3.1
@@ -97,32 +97,40 @@
# https://github.com/apache/couchdb-pkg/blob/master/debian/README.Debian
RUN set -xe; \
- apt-get update; \
- \
- echo "couchdb couchdb/mode select none" | debconf-set-selections; \
+ apt-get update; \
+ \
+ echo "couchdb couchdb/mode select none" | debconf-set-selections; \
# we DO want recommends this time
- DEBIAN_FRONTEND=noninteractive apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages \
- couchdb="$COUCHDB_VERSION"~stretch \
- ; \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages \
+ couchdb="$COUCHDB_VERSION"~stretch \
+ ; \
# Undo symlinks to /var/log and /var/lib
- rmdir /var/lib/couchdb /var/log/couchdb; \
- rm /opt/couchdb/data /opt/couchdb/var/log; \
- mkdir -p /opt/couchdb/data /opt/couchdb/var/log; \
- chown couchdb:couchdb /opt/couchdb/data /opt/couchdb/var/log; \
- chmod 777 /opt/couchdb/data /opt/couchdb/var/log; \
+ rmdir /var/lib/couchdb /var/log/couchdb; \
+ rm /opt/couchdb/data /opt/couchdb/var/log; \
+ mkdir -p /opt/couchdb/data /opt/couchdb/var/log; \
+ chown couchdb:couchdb /opt/couchdb/data /opt/couchdb/var/log; \
+ chmod 777 /opt/couchdb/data /opt/couchdb/var/log; \
# Remove file that sets logging to a file
- rm /opt/couchdb/etc/default.d/10-filelog.ini; \
- rm -rf /var/lib/apt/lists/*
+ rm /opt/couchdb/etc/default.d/10-filelog.ini; \
+# Check we own everything in /opt/couchdb. Matches the command in dockerfile_entrypoint.sh
+ find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +; \
+# Setup directories and permissions for config. Technically these could be 555 and 444 respectively
+# but we keep them as 755 and 644 for consistency with CouchDB defaults and the dockerfile_entrypoint.sh.
+ find /opt/couchdb/etc -type d ! -perm 0755 -exec chmod -f 0755 '{}' +; \
+ find /opt/couchdb/etc -type f ! -perm 0644 -exec chmod -f 0644 '{}' +; \
+# only local.d needs to be writable for the docker_entrypoint.sh
+ chmod -f 0777 /opt/couchdb/etc/local.d; \
+# apt clean-up
+ rm -rf /var/lib/apt/lists/*;
# Add configuration
-COPY 10-docker-default.ini /opt/couchdb/etc/default.d/
-COPY vm.args /opt/couchdb/etc/
+COPY --chown=couchdb:couchdb 10-docker-default.ini /opt/couchdb/etc/default.d/
+COPY --chown=couchdb:couchdb vm.args /opt/couchdb/etc/
+
COPY docker-entrypoint.sh /usr/local/bin
RUN ln -s usr/local/bin/docker-entrypoint.sh /docker-entrypoint.sh # backwards compat
ENTRYPOINT ["tini", "--", "/docker-entrypoint.sh"]
-# Setup directories and permissions
-RUN find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +
VOLUME /opt/couchdb/data
# 5984: Main CouchDB endpoint
diff --git a/2.3.1/docker-entrypoint.sh b/2.3.1/docker-entrypoint.sh
index 7fdb04b..be9e099 100755
--- a/2.3.1/docker-entrypoint.sh
+++ b/2.3.1/docker-entrypoint.sh
@@ -25,36 +25,44 @@
fi
if [ "$1" = '/opt/couchdb/bin/couchdb' ]; then
- # Check that we own everything in /opt/couchdb and fix if necessary. We also
- # add the `-f` flag in all the following invocations because there may be
- # cases where some of these ownership and permissions issues are non-fatal
- # (e.g. a config file owned by root with o+r is actually fine), and we don't
- # to be too aggressive about crashing here ...
- find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +
+ # this is where runtime configuration changes will be written.
+ # we need to explicitly touch it here in case /opt/couchdb/etc has
+ # been mounted as an external volume, in which case it won't exist.
+ # If running as the couchdb user (i.e. container starts as root),
+ # write permissions will be granted below.
+ touch /opt/couchdb/etc/local.d/docker.ini
- # Ensure that data files have the correct permissions. We were previously
- # preventing any access to these files outside of couchdb:couchdb, but it
- # turns out that CouchDB itself does not set such restrictive permissions
- # when it creates the files. The approach taken here ensures that the
- # contents of the datadir have the same permissions as they had when they
- # were initially created. This should minimize any startup delay.
- find /opt/couchdb/data -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
- find /opt/couchdb/data -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
+ # if user is root, assume running under the couchdb user (default)
+ # and ensure it is able to access files and directories that may be mounted externally
+ if [ "$(id -u)" = '0' ]; then
+ # Check that we own everything in /opt/couchdb and fix if necessary. We also
+ # add the `-f` flag in all the following invocations because there may be
+ # cases where some of these ownership and permissions issues are non-fatal
+ # (e.g. a config file owned by root with o+r is actually fine), and we don't
+ # to be too aggressive about crashing here ...
+ find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +
- # Do the same thing for configuration files and directories. Technically
- # CouchDB only needs read access to the configuration files as all online
- # changes will be applied to the "docker.ini" file below, but we set 644
- # for the sake of consistency.
- find /opt/couchdb/etc -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
- find /opt/couchdb/etc -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
+ # Ensure that data files have the correct permissions. We were previously
+ # preventing any access to these files outside of couchdb:couchdb, but it
+ # turns out that CouchDB itself does not set such restrictive permissions
+ # when it creates the files. The approach taken here ensures that the
+ # contents of the datadir have the same permissions as they had when they
+ # were initially created. This should minimize any startup delay.
+ find /opt/couchdb/data -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
+ find /opt/couchdb/data -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
+
+ # Do the same thing for configuration files and directories. Technically
+ # CouchDB only needs read access to the configuration files as all online
+ # changes will be applied to the "docker.ini" file below, but we set 644
+ # for the sake of consistency.
+ find /opt/couchdb/etc -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
+ find /opt/couchdb/etc -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
+ fi
if [ ! -z "$NODENAME" ] && ! grep "couchdb@" /opt/couchdb/etc/vm.args; then
echo "-name couchdb@$NODENAME" >> /opt/couchdb/etc/vm.args
fi
- # Ensure that CouchDB will write custom settings in this file
- touch /opt/couchdb/etc/local.d/docker.ini
-
if [ "$COUCHDB_USER" ] && [ "$COUCHDB_PASSWORD" ]; then
# Create admin only if not already present
if ! grep -Pzoqr "\[admins\]\n$COUCHDB_USER =" /opt/couchdb/etc/local.d/*.ini; then
@@ -69,7 +77,9 @@
fi
fi
- chown -f couchdb:couchdb /opt/couchdb/etc/local.d/docker.ini || true
+ if [ "$(id -u)" = '0' ]; then
+ chown -f couchdb:couchdb /opt/couchdb/etc/local.d/docker.ini || true
+ fi
# if we don't find an [admins] section followed by a non-comment, display a warning
if ! grep -Pzoqr '\[admins\]\n[^;]\w+' /opt/couchdb/etc/default.d/*.ini /opt/couchdb/etc/local.d/*.ini; then
@@ -88,8 +98,9 @@
EOWARN
fi
-
- exec gosu couchdb "$@"
+ if [ "$(id -u)" = '0' ]; then
+ exec gosu couchdb "$@"
+ fi
fi
exec "$@"
diff --git a/README.md b/README.md
index 42f0a93..7f7d73a 100644
--- a/README.md
+++ b/README.md
@@ -170,6 +170,15 @@
It is recommended to then mount this path to a directory on the host, as CouchDB logging can be quite voluminous.
+## Running under a custom UID
+
+By default, CouchDB will run as the `couchdb` user with UID 5984. Running under a different UID is supported, so long as any volume mounts have appropriate read/write permissions. For example, assuming user `myuser` has write access to `/home/couchdb/data`, the following command will run CouchDB as that user:
+
+```
+docker run --name my-couchdb --user myuser -v /home/couchdb/data:/opt/couchdb/data %%IMAGE%%:tag
+```
+
+
-----
# Development images