问题引入

默认情况下,容器中的进程以 root 用户执行,并且这个 root 用户和宿主机中的 root 是同一个用户,这意味着:

  • 容器中运行的进程,在合适的机会下,有权限控制宿主机中的一切;
  • 容器中运行的进程,以 root 用户执行,外界很难追溯到真实的用户;
  • 容器进程生成的文件,是 root用户所有,普通用户没有权限读取修改。

可知,以 root 权限执行是很不方便且很不安全的。

解决方法

  1. 在容器内创建用户并且切换用户;
  • 增加一个新用户,名为user

  • 让这个用户有root权限;

  • 置其密码为 password

  • Container启动后以user登录,并且直接到userhome目录下;

将下面代码片段放到Dockerfile里面。

1
2
3
4
5
6
RUN useradd --create-home --no-log-init --shell /bin/bash user \
&& RUN adduser user sudo \
&& RUN echo 'user:password' | chpasswd

USER user
WORKDIR /home/user
  1. 使用fixuid修改容器中非root用户的uidgid;

    用上面的代码新建非 root 用户后,该用户的 uidgid 一般是 1000:1000

    docker 和宿主机共享一套内核,内核控制的 uidgid 则仍然只有一套。换句话说,我们在容器里以新建的 docker 用户(uid 1000)执行进程,宿主机会认为该进程是宿主机上 uid1000 的用户执行的,而这个用户不一定是我们的账户,相当于我们冒名顶替了别人的用户,这样难以追溯到真实用户。

    要解决这个问题可以在添加用户时指定 uid 为用户的 uid,例如1002;

    1
    2
    RUN addgroup --gid 1002 docker && \
    adduser --uid 1002 --ingroup docker --home /home/docker --shell /bin/sh --gecos "" docker

    但是其它人用这个镜像的时候,uid 可能又不一样,这样写死很不方便,所以更好的解决方法是用 fixuid来在容器启动的时候切换 uid

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 新建用户代码和上面一样
    RUN useradd --create-home --no-log-init --shell /bin/bash user\
    && adduser user sudo \
    && echo 'user:password' | chpasswd

    # 安装配置 fixuid
    RUN USER=user && \
    GROUP=docker && \
    curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.4.1/fixuid-0.4.1-linux-amd64.tar.gz | tar -C /usr/local/bin -xzf - && \
    chown root:root /usr/local/bin/fixuid && \
    chmod 4755 /usr/local/bin/fixuid && \
    mkdir -p /etc/fixuid && \
    printf "user: $USER\ngroup: $GROUP\n" > /etc/fixuid/config.yml

    USER user:docker
    ENTRYPOINT ["fixuid"]

    此时启动容器时需要指定 uidgid,命令如下:

    1
    docker run --rm -it -u $(id -u):$(id -g) image-name bash

联系作者