Skip to content

Commit 6011918

Browse files
authored
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
1 parent d56816f commit 6011918

File tree

3 files changed

+128
-100
lines changed

3 files changed

+128
-100
lines changed

2.3.1/Dockerfile

Lines changed: 82 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,110 +19,118 @@ RUN groupadd -g 5984 -r couchdb && useradd -u 5984 -d /opt/couchdb -g couchdb co
1919

2020
# be sure GPG and apt-transport-https are available and functional
2121
RUN set -ex; \
22-
apt-get update; \
23-
apt-get install -y --no-install-recommends \
24-
apt-transport-https \
25-
ca-certificates \
26-
dirmngr \
27-
gnupg \
28-
; \
29-
rm -rf /var/lib/apt/lists/*
22+
apt-get update; \
23+
apt-get install -y --no-install-recommends \
24+
apt-transport-https \
25+
ca-certificates \
26+
dirmngr \
27+
gnupg \
28+
; \
29+
rm -rf /var/lib/apt/lists/*
3030

3131
# grab gosu for easy step-down from root and tini for signal handling and zombie reaping
3232
# see https://github.com/apache/couchdb-docker/pull/28#discussion_r141112407
3333
ENV GOSU_VERSION 1.11
3434
ENV TINI_VERSION 0.18.0
3535
RUN set -ex; \
36-
\
37-
apt-get update; \
38-
apt-get install -y --no-install-recommends wget; \
39-
rm -rf /var/lib/apt/lists/*; \
40-
\
41-
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
42-
\
36+
\
37+
apt-get update; \
38+
apt-get install -y --no-install-recommends wget; \
39+
rm -rf /var/lib/apt/lists/*; \
40+
\
41+
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
42+
\
4343
# install gosu
44-
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-$dpkgArch"; \
45-
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
46-
export GNUPGHOME="$(mktemp -d)"; \
47-
echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
48-
for server in $(shuf -e pgpkeys.mit.edu \
49-
ha.pool.sks-keyservers.net \
50-
hkp://p80.pool.sks-keyservers.net:80 \
51-
pgp.mit.edu) ; do \
52-
gpg --batch --keyserver $server --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && break || : ; \
53-
done; \
54-
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
55-
rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
56-
chmod +x /usr/local/bin/gosu; \
57-
gosu nobody true; \
44+
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-$dpkgArch"; \
45+
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
46+
export GNUPGHOME="$(mktemp -d)"; \
47+
echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
48+
for server in $(shuf -e pgpkeys.mit.edu \
49+
ha.pool.sks-keyservers.net \
50+
hkp://p80.pool.sks-keyservers.net:80 \
51+
pgp.mit.edu) ; do \
52+
gpg --batch --keyserver $server --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && break || : ; \
53+
done; \
54+
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
55+
rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \
56+
chmod +x /usr/local/bin/gosu; \
57+
gosu nobody true; \
5858
\
5959
# install tini
60-
wget -O /usr/local/bin/tini "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch"; \
61-
wget -O /usr/local/bin/tini.asc "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch.asc"; \
62-
export GNUPGHOME="$(mktemp -d)"; \
63-
echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
64-
for server in $(shuf -e pgpkeys.mit.edu \
65-
ha.pool.sks-keyservers.net \
66-
hkp://p80.pool.sks-keyservers.net:80 \
67-
pgp.mit.edu) ; do \
68-
gpg --batch --keyserver $server --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 && break || : ; \
69-
done; \
70-
gpg --batch --verify /usr/local/bin/tini.asc /usr/local/bin/tini; \
71-
rm -rf "$GNUPGHOME" /usr/local/bin/tini.asc; \
72-
chmod +x /usr/local/bin/tini; \
73-
apt-get purge -y --auto-remove wget; \
74-
tini --version
60+
wget -O /usr/local/bin/tini "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch"; \
61+
wget -O /usr/local/bin/tini.asc "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-$dpkgArch.asc"; \
62+
export GNUPGHOME="$(mktemp -d)"; \
63+
echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
64+
for server in $(shuf -e pgpkeys.mit.edu \
65+
ha.pool.sks-keyservers.net \
66+
hkp://p80.pool.sks-keyservers.net:80 \
67+
pgp.mit.edu) ; do \
68+
gpg --batch --keyserver $server --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 && break || : ; \
69+
done; \
70+
gpg --batch --verify /usr/local/bin/tini.asc /usr/local/bin/tini; \
71+
rm -rf "$GNUPGHOME" /usr/local/bin/tini.asc; \
72+
chmod +x /usr/local/bin/tini; \
73+
apt-get purge -y --auto-remove wget; \
74+
tini --version
7575

7676
# http://docs.couchdb.org/en/latest/install/unix.html#installing-the-apache-couchdb-packages
7777
ENV GPG_COUCH_KEY \
7878
# gpg: key D401AB61: public key "Bintray (by JFrog) <[email protected]> imported
79-
8756C4F765C9AC3CB6B85D62379CE192D401AB61
79+
8756C4F765C9AC3CB6B85D62379CE192D401AB61
8080
RUN set -xe; \
81-
export GNUPGHOME="$(mktemp -d)"; \
82-
echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
83-
for server in $(shuf -e pgpkeys.mit.edu \
84-
ha.pool.sks-keyservers.net \
85-
hkp://p80.pool.sks-keyservers.net:80 \
86-
pgp.mit.edu) ; do \
87-
gpg --batch --keyserver $server --recv-keys $GPG_COUCH_KEY && break || : ; \
88-
done; \
89-
gpg --batch --export $GPG_COUCH_KEY > /etc/apt/trusted.gpg.d/couchdb.gpg; \
90-
command -v gpgconf && gpgconf --kill all || :; \
91-
rm -rf "$GNUPGHOME"; \
92-
apt-key list
81+
export GNUPGHOME="$(mktemp -d)"; \
82+
echo "disable-ipv6" >> ${GNUPGHOME}/dirmngr.conf; \
83+
for server in $(shuf -e pgpkeys.mit.edu \
84+
ha.pool.sks-keyservers.net \
85+
hkp://p80.pool.sks-keyservers.net:80 \
86+
pgp.mit.edu) ; do \
87+
gpg --batch --keyserver $server --recv-keys $GPG_COUCH_KEY && break || : ; \
88+
done; \
89+
gpg --batch --export $GPG_COUCH_KEY > /etc/apt/trusted.gpg.d/couchdb.gpg; \
90+
command -v gpgconf && gpgconf --kill all || :; \
91+
rm -rf "$GNUPGHOME"; \
92+
apt-key list
9393

9494
ENV COUCHDB_VERSION 2.3.1
9595

9696
RUN echo "deb https://apache.bintray.com/couchdb-deb stretch main" > /etc/apt/sources.list.d/couchdb.list
9797

9898
# https://github.com/apache/couchdb-pkg/blob/master/debian/README.Debian
9999
RUN set -xe; \
100-
apt-get update; \
101-
\
102-
echo "couchdb couchdb/mode select none" | debconf-set-selections; \
100+
apt-get update; \
101+
\
102+
echo "couchdb couchdb/mode select none" | debconf-set-selections; \
103103
# we DO want recommends this time
104-
DEBIAN_FRONTEND=noninteractive apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages \
105-
couchdb="$COUCHDB_VERSION"~stretch \
106-
; \
104+
DEBIAN_FRONTEND=noninteractive apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages \
105+
couchdb="$COUCHDB_VERSION"~stretch \
106+
; \
107107
# Undo symlinks to /var/log and /var/lib
108-
rmdir /var/lib/couchdb /var/log/couchdb; \
109-
rm /opt/couchdb/data /opt/couchdb/var/log; \
110-
mkdir -p /opt/couchdb/data /opt/couchdb/var/log; \
111-
chown couchdb:couchdb /opt/couchdb/data /opt/couchdb/var/log; \
112-
chmod 777 /opt/couchdb/data /opt/couchdb/var/log; \
108+
rmdir /var/lib/couchdb /var/log/couchdb; \
109+
rm /opt/couchdb/data /opt/couchdb/var/log; \
110+
mkdir -p /opt/couchdb/data /opt/couchdb/var/log; \
111+
chown couchdb:couchdb /opt/couchdb/data /opt/couchdb/var/log; \
112+
chmod 777 /opt/couchdb/data /opt/couchdb/var/log; \
113113
# Remove file that sets logging to a file
114-
rm /opt/couchdb/etc/default.d/10-filelog.ini; \
115-
rm -rf /var/lib/apt/lists/*
114+
rm /opt/couchdb/etc/default.d/10-filelog.ini; \
115+
# Check we own everything in /opt/couchdb. Matches the command in dockerfile_entrypoint.sh
116+
find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +; \
117+
# Setup directories and permissions for config. Technically these could be 555 and 444 respectively
118+
# but we keep them as 755 and 644 for consistency with CouchDB defaults and the dockerfile_entrypoint.sh.
119+
find /opt/couchdb/etc -type d ! -perm 0755 -exec chmod -f 0755 '{}' +; \
120+
find /opt/couchdb/etc -type f ! -perm 0644 -exec chmod -f 0644 '{}' +; \
121+
# only local.d needs to be writable for the docker_entrypoint.sh
122+
chmod -f 0777 /opt/couchdb/etc/local.d; \
123+
# apt clean-up
124+
rm -rf /var/lib/apt/lists/*;
116125

117126
# Add configuration
118-
COPY 10-docker-default.ini /opt/couchdb/etc/default.d/
119-
COPY vm.args /opt/couchdb/etc/
127+
COPY --chown=couchdb:couchdb 10-docker-default.ini /opt/couchdb/etc/default.d/
128+
COPY --chown=couchdb:couchdb vm.args /opt/couchdb/etc/
129+
120130
COPY docker-entrypoint.sh /usr/local/bin
121131
RUN ln -s usr/local/bin/docker-entrypoint.sh /docker-entrypoint.sh # backwards compat
122132
ENTRYPOINT ["tini", "--", "/docker-entrypoint.sh"]
123133

124-
# Setup directories and permissions
125-
RUN find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +
126134
VOLUME /opt/couchdb/data
127135

128136
# 5984: Main CouchDB endpoint

2.3.1/docker-entrypoint.sh

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,36 +25,44 @@ if [ "$1" = 'couchdb' ]; then
2525
fi
2626

2727
if [ "$1" = '/opt/couchdb/bin/couchdb' ]; then
28-
# Check that we own everything in /opt/couchdb and fix if necessary. We also
29-
# add the `-f` flag in all the following invocations because there may be
30-
# cases where some of these ownership and permissions issues are non-fatal
31-
# (e.g. a config file owned by root with o+r is actually fine), and we don't
32-
# to be too aggressive about crashing here ...
33-
find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +
28+
# this is where runtime configuration changes will be written.
29+
# we need to explicitly touch it here in case /opt/couchdb/etc has
30+
# been mounted as an external volume, in which case it won't exist.
31+
# If running as the couchdb user (i.e. container starts as root),
32+
# write permissions will be granted below.
33+
touch /opt/couchdb/etc/local.d/docker.ini
34+
35+
# if user is root, assume running under the couchdb user (default)
36+
# and ensure it is able to access files and directories that may be mounted externally
37+
if [ "$(id -u)" = '0' ]; then
38+
# Check that we own everything in /opt/couchdb and fix if necessary. We also
39+
# add the `-f` flag in all the following invocations because there may be
40+
# cases where some of these ownership and permissions issues are non-fatal
41+
# (e.g. a config file owned by root with o+r is actually fine), and we don't
42+
# to be too aggressive about crashing here ...
43+
find /opt/couchdb \! \( -user couchdb -group couchdb \) -exec chown -f couchdb:couchdb '{}' +
3444

35-
# Ensure that data files have the correct permissions. We were previously
36-
# preventing any access to these files outside of couchdb:couchdb, but it
37-
# turns out that CouchDB itself does not set such restrictive permissions
38-
# when it creates the files. The approach taken here ensures that the
39-
# contents of the datadir have the same permissions as they had when they
40-
# were initially created. This should minimize any startup delay.
41-
find /opt/couchdb/data -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
42-
find /opt/couchdb/data -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
45+
# Ensure that data files have the correct permissions. We were previously
46+
# preventing any access to these files outside of couchdb:couchdb, but it
47+
# turns out that CouchDB itself does not set such restrictive permissions
48+
# when it creates the files. The approach taken here ensures that the
49+
# contents of the datadir have the same permissions as they had when they
50+
# were initially created. This should minimize any startup delay.
51+
find /opt/couchdb/data -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
52+
find /opt/couchdb/data -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
4353

44-
# Do the same thing for configuration files and directories. Technically
45-
# CouchDB only needs read access to the configuration files as all online
46-
# changes will be applied to the "docker.ini" file below, but we set 644
47-
# for the sake of consistency.
48-
find /opt/couchdb/etc -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
49-
find /opt/couchdb/etc -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
54+
# Do the same thing for configuration files and directories. Technically
55+
# CouchDB only needs read access to the configuration files as all online
56+
# changes will be applied to the "docker.ini" file below, but we set 644
57+
# for the sake of consistency.
58+
find /opt/couchdb/etc -type d ! -perm 0755 -exec chmod -f 0755 '{}' +
59+
find /opt/couchdb/etc -type f ! -perm 0644 -exec chmod -f 0644 '{}' +
60+
fi
5061

5162
if [ ! -z "$NODENAME" ] && ! grep "couchdb@" /opt/couchdb/etc/vm.args; then
5263
echo "-name couchdb@$NODENAME" >> /opt/couchdb/etc/vm.args
5364
fi
5465

55-
# Ensure that CouchDB will write custom settings in this file
56-
touch /opt/couchdb/etc/local.d/docker.ini
57-
5866
if [ "$COUCHDB_USER" ] && [ "$COUCHDB_PASSWORD" ]; then
5967
# Create admin only if not already present
6068
if ! grep -Pzoqr "\[admins\]\n$COUCHDB_USER =" /opt/couchdb/etc/local.d/*.ini; then
@@ -69,7 +77,9 @@ if [ "$1" = '/opt/couchdb/bin/couchdb' ]; then
6977
fi
7078
fi
7179

72-
chown -f couchdb:couchdb /opt/couchdb/etc/local.d/docker.ini || true
80+
if [ "$(id -u)" = '0' ]; then
81+
chown -f couchdb:couchdb /opt/couchdb/etc/local.d/docker.ini || true
82+
fi
7383

7484
# if we don't find an [admins] section followed by a non-comment, display a warning
7585
if ! grep -Pzoqr '\[admins\]\n[^;]\w+' /opt/couchdb/etc/default.d/*.ini /opt/couchdb/etc/local.d/*.ini; then
@@ -88,8 +98,9 @@ if [ "$1" = '/opt/couchdb/bin/couchdb' ]; then
8898
EOWARN
8999
fi
90100

91-
92-
exec gosu couchdb "$@"
101+
if [ "$(id -u)" = '0' ]; then
102+
exec gosu couchdb "$@"
103+
fi
93104
fi
94105

95106
exec "$@"

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,15 @@ file = /opt/couchdb/log/couch.log
170170

171171
It is recommended to then mount this path to a directory on the host, as CouchDB logging can be quite voluminous.
172172

173+
## Running under a custom UID
174+
175+
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:
176+
177+
```
178+
docker run --name my-couchdb --user myuser -v /home/couchdb/data:/opt/couchdb/data %%IMAGE%%:tag
179+
```
180+
181+
173182
-----
174183

175184
# Development images

0 commit comments

Comments
 (0)