MariaDB / mariadb-docker

Docker Official Image packaging for MariaDB
https://mariadb.org
GNU General Public License v2.0
767 stars 438 forks source link

Add option to explicitly set the uid and gid of the mysql user. #554

Closed bsutton closed 7 months ago

bsutton commented 8 months ago

My project uses host volume mounts for data and log directories.

The problem is that the mysql uid and gid are allocated randomly within the container and as such are 'mapped' to a random user/group on the host ( I guess technically it's not random, just not within my control).

If we could set the uid:gid for the mysql user and group within the container, then we could setup host uid:gid that match and is mapped to a coherent name.

grooverdan commented 8 months ago

What options does your container runtime provide? Is it a rootless mode?

The mysql id of 999 is fixed in the container.

$ ls -la build-mariadb-server-10.11-datadir/
total 111012
drwxr-xr-x.  6 dan  dan        260 Jan 16 09:53 .
drwxrwxrwt. 24 root root       600 Jan 16 09:53 ..
-rw-rw----.  1 dan  dan     417792 Jan 16 09:53 aria_log.00000001
-rw-rw----.  1 dan  dan         52 Jan 16 09:53 aria_log_control
-rw-rw----.  1 dan  dan        910 Jan 16 09:53 ib_buffer_pool
-rw-rw----.  1 dan  dan   12582912 Jan 16 09:51 ibdata1
-rw-rw----.  1 dan  dan  100663296 Jan 16 09:51 ib_logfile0
-rw-rw----.  1 dan  dan          0 Jan 16 09:51 multi-master.info
drwx------.  2 dan  dan       1800 Jan 16 09:51 mysql
-rw-r--r--.  1 dan  dan         15 Jan 16 09:51 mysql_upgrade_info
drwx------.  2 dan  dan         60 Jan 16 09:51 performance_schema
drwx------.  2 dan  dan       2120 Jan 16 09:51 sys
drwx------.  2 dan  dan         60 Jan 16 09:51 test

/tmp 
$ podman run --userns=keep-id:uid=999,gid=999 -v ./build-mariadb-server-10.11-datadir:/var/lib/mysql --rm   mariadb:10.11
2024-01-15 23:01:23+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.6+maria~ubu2204 started.
2024-01-15 23:01:23+00:00 [Note] [Entrypoint]: MariaDB upgrade not required
2024-01-15 23:01:23 0 [Note] Starting MariaDB 10.11.6-MariaDB-1:10.11.6+maria~ubu2204 source revision fecd78b83785d5ae96f2c6ff340375be803cd299 as process 1
...

$ podman exec -ti jolly_jepsen ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
mysql          1       0  0 23:01 ?        00:00:00 mariadbd
mysql         33       0  0 23:03 pts/0    00:00:00 ps -ef

I'm also curious why are host volume mounts used instead of named volumes?

bsutton commented 8 months ago

I don't know what 'rootless mode' is.

The host is running ubuntu.

On the host, 999 gets mapped to whatever app first creates a system user so it is essentially random on the host which is why I'm looking to explicitly control it.

On Tue, Jan 16, 2024 at 10:07 AM Daniel Black @.***> wrote:

What options does your container runtime provide? Is it a rootless mode?

The mysql id of 999 is fixed in the container.

$ ls -la build-mariadb-server-10.11-datadir/ total 111012 drwxr-xr-x. 6 dan dan 260 Jan 16 09:53 . drwxrwxrwt. 24 root root 600 Jan 16 09:53 .. -rw-rw----. 1 dan dan 417792 Jan 16 09:53 aria_log.00000001 -rw-rw----. 1 dan dan 52 Jan 16 09:53 aria_log_control -rw-rw----. 1 dan dan 910 Jan 16 09:53 ib_buffer_pool -rw-rw----. 1 dan dan 12582912 Jan 16 09:51 ibdata1 -rw-rw----. 1 dan dan 100663296 Jan 16 09:51 ib_logfile0 -rw-rw----. 1 dan dan 0 Jan 16 09:51 multi-master.info drwx------. 2 dan dan 1800 Jan 16 09:51 mysql -rw-r--r--. 1 dan dan 15 Jan 16 09:51 mysql_upgrade_info drwx------. 2 dan dan 60 Jan 16 09:51 performance_schema drwx------. 2 dan dan 2120 Jan 16 09:51 sys drwx------. 2 dan dan 60 Jan 16 09:51 test

/tmp $ podman run --userns=keep-id:uid=999,gid=999 -v ./build-mariadb-server-10.11-datadir:/var/lib/mysql --rm mariadb:10.11 2024-01-15 23:01:23+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.11.6+maria~ubu2204 started. 2024-01-15 23:01:23+00:00 [Note] [Entrypoint]: MariaDB upgrade not required 2024-01-15 23:01:23 0 [Note] Starting MariaDB 10.11.6-MariaDB-1:10.11.6+maria~ubu2204 source revision fecd78b83785d5ae96f2c6ff340375be803cd299 as process 1 ...

$ podman exec -ti jolly_jepsen ps -ef UID PID PPID C STIME TTY TIME CMD mysql 1 0 0 23:01 ? 00:00:00 mariadbd mysql 33 0 0 23:03 pts/0 00:00:00 ps -ef

I'm also curious why are host volume mounts used instead of named volumes?

— Reply to this email directly, view it on GitHub https://github.com/MariaDB/mariadb-docker/issues/554#issuecomment-1892857075, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG32OHPJY6UTMHFL4EQCQ3YOWZBVAVCNFSM6AAAAABB33PBWKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOJSHA2TOMBXGU . You are receiving this because you authored the thread.Message ID: @.***>

grooverdan commented 8 months ago

Rootless mode is part of some container runtimes that execute containers without (host) root permissions.

In the example provided I used the keep-id feature of the runtime to map the 999 user inside the container, to the current user dan, so that it could access the volume on the local filesystem. Rootful modes provide also options for explicit mappings,

podman run --uidmap=999:0  --user 999   -v ./build-mariadb-server-10.11-datadir:/var/lib/mysql --rm   mariadb:10.11

Also should have worked (https://github.com/containers/common/issues/1802)

User ID maps are supported by the container runtime, which is why I'm not looking to explicitly implement a mariadb container control for it. Essentially doing so would modify the container at runtime (not supported on runtimes like apptainer) and slow the initialization speed. Also named volumes exist for providing exclusive storage to containers.

Without easy documentation, I can see why you describe it as random, or not within your control. After all we only need to set 1 host -> container uid number correctly, so I'm going to try to document this so every container doesn't need to implement the same thing.

bsutton commented 8 months ago

If I've understood what you are saying, then the problem is that mariadb (partially) ignores the mapping.

On docker, I've tried mapping the user with docker-compose option user 2002:2002 with 2002 being the uid of the host user mysql.

The problem is that they mysql container creates files using the 'mysql' name rather than the uid the container is running with (as per the above user option). The result is that I get some files with the correct permissions (those created with the uid) and some not (those that have the owner set to 'mysql').

The only way I can get it to work is to clone the mariadb docker file and modify the mysql uid/gid. When I do this, it doesn't matter if maria uses the id or the name of the user, the permissions will be correct.

By altering https://github.com/MariaDB/mariadb-docker/blob/master/10.11/Dockerfile

to have

RUN groupadd -g 2002 -r mysql && useradd -u 2002 -r -g mysql mysql --home-dir /var/lib/mysql

Note the addition of the -g and -u switches otherwise the file is original.

This combined with the container mapping gives the desired results but without the custom container I can't get it to work.

bsutton commented 8 months ago

Here is my docker-compose file:

version: '3.3'

services:
  mysql:
    container_name: mysql
    image: onepub/onepub-mariadb:${ONEPUB_VERSION}
    restart: on-failure
    environment:
      # override from env file to be empty, otherwise it prevents proper  initialization of mysql
      MYSQL_ROOT_PASSWORD: ${MYSQL_ADMIN_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_SCHEMA}
      TZ: ${TIME_ZONE-Australia/Melbourne}
      MARIADB_AUTO_UPGRADE: "true"
    command: >
      --lower-case-table-names=1 --bind-address=127.0.0.1 --datadir=/innodb-data/ --innodb_log_group_home_dir=/innodb-logs/ --max-allowed-packet=512M --innodb_buffer_pool_chunk_size=${MYSQL_INNODB_BUFFER_POOL_CHUNK_SIZE-8M} --innodb_buffer_pool_size=${MYSQL_INNODB_BUFFER_POOL_SIZE-512M} --table_open_cache=${MYSQL_TABLE_OPEN_CACHE-512} --max_connections=${MYSQL_MAX_CONNECTIONS-98} --innodb_flush_neighbors=0 --innodb_fast_shutdown=1 --innodb_flush_log_at_trx_commit=1 --innodb_flush_method=fsync --innodb_doublewrite=0  --innodb_use_native_aio=0 --innodb_read_io_threads=10 --innodb_write_io_threads=10 --slow_query_log_file=/tmp/mysql-slow.log --long-query-time=0.3 --slow_query_log --innodb-print-all-deadlocks
    volumes:
      - /db/mysql-innodb-data:/innodb-data
      - /db/mysql-innodb-logs:/innodb-logs
    network_mode: "host"
    logging:
      driver: "journald"
    user: 2002:2002

The full docker file - note that on the above mentioned line has been changed:

# copied from https://github.com/MariaDB/mariadb-docker/blob/master/10.11/Dockerfile
# The only change is that we explicityly set the mysql uid and gid

# vim:set ft=dockerfile:
FROM ubuntu:jammy

# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
#
# ONEPUB - set -g and -u to 2002
#
RUN groupadd -g 2002 -r mysql && useradd -u 2002 -r -g mysql mysql --home-dir /var/lib/mysql

# add gosu for easy step-down from root
# https://github.com/tianon/gosu/releases
# gosu key is B42F6819007F00F88E364FD4036A9C25BF357DD4
ENV GOSU_VERSION 1.17

ARG GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8
# pub   rsa4096 2016-03-30 [SC]
#         177F 4010 FE56 CA33 3630  0305 F165 6F24 C74C D1D8
# uid           [ unknown] MariaDB Signing Key <signing-key@mariadb.org>
# sub   rsa4096 2016-03-30 [E]
# install "libjemalloc2" as it offers better performance in some cases. Use with LD_PRELOAD
# install "pwgen" for randomizing passwords
# install "tzdata" for /usr/share/zoneinfo/
# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files
# install "zstd" for .sql.zst docker-entrypoint-initdb.d files
# hadolint ignore=SC2086
RUN set -eux; \
    apt-get update; \
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
    ca-certificates \
    gpg \
    gpgv \
    libjemalloc2 \
    pwgen \
    tzdata \
    xz-utils \
    zstd ; \
    savedAptMark="$(apt-mark showmanual)"; \
    apt-get install -y --no-install-recommends \
    dirmngr \
    gpg-agent \
    wget; \
    rm -rf /var/lib/apt/lists/*; \
    dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
    wget -q -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
    wget -q -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
    GNUPGHOME="$(mktemp -d)"; \
    export GNUPGHOME; \
    gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
    for key in $GPG_KEYS; do \
    gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \
    done; \
    gpg --batch --export "$GPG_KEYS" > /etc/apt/trusted.gpg.d/mariadb.gpg; \
    if command -v gpgconf >/dev/null; then \
    gpgconf --kill all; \
    fi; \
    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

RUN mkdir /docker-entrypoint-initdb.d

# Ensure the container exec commands handle range of utf8 characters based of
# default locales in base image (https://github.com/docker-library/docs/blob/135b79cc8093ab02e55debb61fdb079ab2dbce87/ubuntu/README.md#locales)
ENV LANG C.UTF-8

# OCI annotations to image
LABEL org.opencontainers.image.authors="MariaDB Community" \
    org.opencontainers.image.title="MariaDB Database" \
    org.opencontainers.image.description="MariaDB Database for relational SQL" \
    org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \
    org.opencontainers.image.base.name="docker.io/library/ubuntu:jammy" \
    org.opencontainers.image.licenses="GPL-2.0" \
    org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \
    org.opencontainers.image.vendor="MariaDB Community" \
    org.opencontainers.image.version="10.11.6" \
    org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker"

# bashbrew-architectures: amd64 arm64v8 ppc64le s390x
ARG MARIADB_VERSION=1:10.11.6+maria~ubu2204
ENV MARIADB_VERSION $MARIADB_VERSION
# release-status:Stable
# release-support-type:Long Term Support
# (https://downloads.mariadb.org/rest-api/mariadb/)

# Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions
ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.11.6/repo/ubuntu/ jammy main main/debug"

RUN set -e;\
    echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \
    { \
    echo 'Package: *'; \
    echo 'Pin: release o=MariaDB'; \
    echo 'Pin-Priority: 999'; \
    } > /etc/apt/preferences.d/mariadb
# add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies
#  libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed

# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql)
# also, we set debconf keys to make APT a little quieter
# hadolint ignore=DL3015
RUN set -ex; \
    { \
    echo "mariadb-server" mysql-server/root_password password 'unused'; \
    echo "mariadb-server" mysql-server/root_password_again password 'unused'; \
    } | debconf-set-selections; \
    apt-get update; \
    # postinst script creates a datadir, so avoid creating it by faking its existance.
    mkdir -p /var/lib/mysql/mysql ; touch /var/lib/mysql/mysql/user.frm ; \
    # mariadb-backup is installed at the same time so that `mysql-common` is only installed once from just mariadb repos
    apt-get install -y --no-install-recommends mariadb-server="$MARIADB_VERSION" mariadb-backup socat \
    ; \
    rm -rf /var/lib/apt/lists/*; \
    # purge and re-create /var/lib/mysql with appropriate ownership
    rm -rf /var/lib/mysql /etc/mysql/mariadb.conf.d/50-mysqld_safe.cnf; \
    mkdir -p /var/lib/mysql /run/mysqld; \
    chown -R mysql:mysql /var/lib/mysql /run/mysqld; \
    # ensure that /run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime
    chmod 1777 /run/mysqld; \
    # comment out a few problematic configuration values
    find /etc/mysql/ -name '*.cnf' -print0 \
    | xargs -0 grep -lZE '^(bind-address|log|user\s)' \
    | xargs -rt -0 sed -Ei 's/^(bind-address|log|user\s)/#&/'; \
    # don't reverse lookup hostnames, they are usually another container
    printf "[mariadb]\nhost-cache-size=0\nskip-name-resolve\n" > /etc/mysql/mariadb.conf.d/05-skipcache.cnf; \
    # Issue #327 Correct order of reading directories /etc/mysql/mariadb.conf.d before /etc/mysql/conf.d (mount-point per documentation)
    if [ -L /etc/mysql/my.cnf ]; then \
    # 10.5+
    sed -i -e '/includedir/ {N;s/\(.*\)\n\(.*\)/\n\2\n\1/}' /etc/mysql/mariadb.cnf; \
    fi

VOLUME /var/lib/mysql

COPY healthcheck.sh /usr/local/bin/healthcheck.sh
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 3306
CMD ["mariadbd"]
grooverdan commented 8 months ago

A slightly simpler form is:

FROM mariadb:10.11

RUN useradd -u 2002 -r localuser --home-dir /var/lib/mysql

As this is all build time, to do this for a prebuild image of a dynamic uid is more complex.

And then in compose for the service user: localuser. The container started as a non-root user will not switch to mysql.

There's also usermode_ns: host, which comes down to dockerd user namespace and userns-remap with the notable text:

This re-mapping is transparent to the container, but introduces some configuration complexity in situations where the container needs access to resources on the Docker host, such as bind mounts into areas of the filesystem that the system user cannot write to. From a security standpoint, it is best to avoid these situations.

bsutton commented 8 months ago

The issue here is that it requires customisation of the container - which I have successfully done - but it would seem preferable that this is a supported feature which doesn't require a container mod.

I can't imagine that I'm the only person trying to mount the db from the host.

On Wed, Jan 17, 2024 at 1:37 PM Daniel Black @.***> wrote:

A slightly simpler form is:

FROM mariadb:10.11

RUN useradd -u 2002 -r localuser --home-dir /var/lib/mysql

As this is all build time, to do this for a prebuild image of a dynamic uid is more complex.

And then in compose for the service user: localuser. The container started as a non-root user will not switch to mysql.

There's also usermode_ns: host https://docs.docker.com/compose/compose-file/compose-file-v3/#userns_mode, which comes down to dockerd user namespace https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-user-namespace-options and userns-remap https://docs.docker.com/engine/security/userns-remap/ with the notable text:

This re-mapping is transparent to the container, but introduces some configuration complexity in situations where the container needs access to resources on the Docker host, such as bind mounts into areas of the filesystem that the system user cannot write to. From a security standpoint, it is best to avoid these situations.

— Reply to this email directly, view it on GitHub https://github.com/MariaDB/mariadb-docker/issues/554#issuecomment-1894842400, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG32OADTSJWHTTMVLA7IU3YO42OTAVCNFSM6AAAAABB33PBWKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOJUHA2DENBQGA . You are receiving this because you authored the thread.Message ID: @.***>

grooverdan commented 8 months ago

The issue here is that it requires customisation of the container - which I have successfully done - but it would seem preferable that this is a supported feature which doesn't require a container mod.

Actually user: 2002 in compose might be sufficient on an unmod container.

I can't imagine that I'm the only person trying to mount the db from the host.

Note, I'm not saying "no", just understanding the domain a bit more in the complexity of multiple runtime implementations, root(full|less) modes, an standard behaviour, OCI, runtime and other containers.

ref: https://github.com/opencontainers/runtime-spec/blob/main/config-linux.md#user-namespace-mappings ref: https://github.com/opencontainers/runtime-spec/blob/main/config.md#configLinuxMountOptions idMap SHOULD be implemented by runtimes

bsutton commented 8 months ago

Actually user: 2002 in compose might be sufficient on an unmod container. I don't believe so, as this is where I started my journey.

The problem is that some of the mariad db processes create some file using the 'mysql' username rather than uid that they are running under. The result is that in the log and data directory you have some files owned by 2002 and some owned by 'mysql' . This ends badly.

On Wed, Jan 17, 2024 at 3:57 PM Daniel Black @.***> wrote:

The issue here is that it requires customisation of the container - which I have successfully done - but it would seem preferable that this is a supported feature which doesn't require a container mod.

Actually user: 2002 in compose might be sufficient on an unmod container.

I can't imagine that I'm the only person trying to mount the db from the host.

Note, I'm not saying "no", just understanding the domain a bit more in the complexity of multiple runtime implementations, root(full|less) modes, an standard behaviour, OCI, runtime and other containers.

ref: https://github.com/opencontainers/runtime-spec/blob/main/config-linux.md#user-namespace-mappings ref: https://github.com/opencontainers/runtime-spec/blob/main/config.md#configLinuxMountOptions idMap SHOULD be implemented by runtimes

— Reply to this email directly, view it on GitHub https://github.com/MariaDB/mariadb-docker/issues/554#issuecomment-1894941598, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG32OHYZYOGKKWQW3433EDYO5K3RAVCNFSM6AAAAABB33PBWKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOJUHE2DCNJZHA . You are receiving this because you authored the thread.Message ID: @.***>

martadinata666 commented 8 months ago

Chim in because out of curiousity, so I tried the compose

version: '3.3'

services:
  mysql:
    container_name: mysql
    image: mariadb:11.0
#    restart: on-failure
    environment:
      # override from env file to be empty, otherwise it prevents proper  initialization of mysql
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: somedbname
      MARIADB_AUTO_UPGRADE: "true"
    command: >
      --lower-case-table-names=1 --bind-address=127.0.0.1 --datadir=/innodb-data/ --innodb_log_group_home_dir=/innodb-logs/ --max-allowed-packet=512M --innodb_buffer_pool_chunk_size=${MYSQL_INNODB_BUFFER_POOL_CHUNK_SIZE-8M} --innodb_buffer_pool_size=${MYSQL_INNODB_BUFFER_POOL_SIZE-512M} --table_open_cache=${MYSQL_TABLE_OPEN_CACHE-512} --max_connections=${MYSQL_MAX_CONNECTIONS-98} --innodb_flush_neighbors=0 --innodb_fast_shutdown=1 --innodb_flush_log_at_trx_commit=1 --innodb_flush_method=fsync --innodb_doublewrite=0  --innodb_use_native_aio=0 --innodb_read_io_threads=10 --innodb_write_io_threads=10 --slow_query_log_file=/tmp/mysql-slow.log --long-query-time=0.3 --slow_query_log --innodb-print-all-deadlocks
    volumes:
      - ./data:/innodb-data
      - ./logs:/innodb-logs
#    network_mode: "host"
    logging:
      driver: "journald"
    user: 2002:2002
❯ docker exec -it mysql ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
2002           1       0  0 05:34 ?        00:00:00 mariadbd --lower-case-table-names=1 --bind-address=127.0.0.1 --datadir=/innodb-data/ --innodb_log_group_home_dir=/innodb-logs/ --max-allowed-packet=512M --innodb_buffer_pool_chunk_size
2002         117       0  0 05:40 pts/0    00:00:00 ps -ef
❯ docker exec -it mysql ls -aln /innodb-data
total 71812
drwxrwxr-x 1 2002 2002      378 Jan 17 05:36 .
drwxr-xr-x 1    0    0     4096 Jan 17 05:34 ..
-rw------- 1 2002 2002      131 Jan 17 05:36 .my-healthcheck.cnf
-rw-rw---- 1 2002 2002 16875520 Jan 17 05:36 aria_log.00000001
-rw-rw---- 1 2002 2002       52 Jan 17 05:36 aria_log_control
-rw-rw---- 1 2002 2002        9 Jan 17 05:36 ddl_recovery.log
-rw-rw---- 1 2002 2002      690 Jan 17 05:36 ib_buffer_pool
-rw-rw---- 1 2002 2002 12582912 Jan 17 05:36 ibdata1
-rw-rw---- 1 2002 2002 12582912 Jan 17 05:36 ibtmp1
-rw-r--r-- 1 2002 2002       14 Jan 17 05:36 mariadb_upgrade_info
-rw-rw---- 1 2002 2002        0 Jan 17 05:36 multi-master.info
drwx------ 1 2002 2002     2718 Jan 17 05:36 mysql
drwx------ 1 2002 2002       12 Jan 17 05:35 performance_schema
drwx------ 1 2002 2002       12 Jan 17 05:36 somedbname
drwx------ 1 2002 2002     6536 Jan 17 05:35 sys
-rw-rw---- 1 2002 2002 10485760 Jan 17 05:36 undo001
-rw-rw---- 1 2002 2002 10485760 Jan 17 05:36 undo002
-rw-rw---- 1 2002 2002 10485760 Jan 17 05:36 undo003

It run as 2002 as expected, I just need to ensure that host path the data and logs writable by 2002. Need more explicit which part that doesn't work?

AmirHosseinKarimi commented 8 months ago

The problem is that the mysql process will run from a user other than root which does not follow the docker patterns. This container is a single process and that process should run from the root user. So the uid and gid mapping will work correctly and the file ownership in the host will be fixed.

martadinata666 commented 8 months ago

No no, docker pattern and security should drop root as soon as possible or even run with specified user that why many rootless docker image mostly run as 1000 or some other user specified.

Jip-Hop commented 8 months ago

Seems to work fine over here with uid and gid explicitly set (besides dropping all capabilities and running the image readonly).

version: "3"

services:
  mariadb:
    container_name: mariadb
    image: mariadb:10.6.16
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    user: 2002:2002
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    read_only: true
    tmpfs:
      - /tmp:noexec
      - /run:noexec
      - /run/mysqld:noexec
    volumes:
      - ./mariadb:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD
      - MYSQL_PASSWORD
      - MYSQL_DATABASE=mariadb
      - MYSQL_USER=mariadb
      - MARIADB_AUTO_UPGRADE=1
      - MARIADB_DISABLE_UPGRADE_BACKUP=0

Running find . ! -user 2002 inside the bind mounted mariadb directory returns 0 files.

grooverdan commented 8 months ago

Thanks @Jip-Hop, for highlighting the read_only mode. tmpfs also highlighting how things like pidfiles and sockets add to the inflexibility of the image (more to fix).

Highlighting cap_drop: all I think is an important aspect as it highlights exactly what capabilities the root user (checked with grep ^Cap /proc/self/status and it seems only root -CapBnd remains when --user specified meaning it needs a filesystem cap label to gain capability. (readable list)

I just read though a number of best practices guides to be sure, and none mention going to a non-root user.

So if we go back to security principles of risk/convenience tradeoff lets look at exactly what's is/needed.

So options:

  1. keep as is, like shown above user: specified by the user can set arbitary uid that map to the host storage (though it need to be documented clearer)
  2. Like #461, a USER mysql is the Dockerfile cannot cope with arbitrary volumes
  3. Any modification of a user -> uid within the container to solve an external volume is an option at build time, but with so many user ids possible we can't make a container for every user.
  4. change mariadbd to capset to drop capabilities, not complain about an euid of 0, mask off the filesystem that it doesn't need somehowe, and then it can run as the default USER root.
grooverdan commented 7 months ago

Are the FAQs sufficient?