在Docker中运行app作为非root用户

时间:2014-06-19 14:13:19

标签: node.js docker lxc

yesterday's news of Shocker之后,看起来Docker容器中的应用程序不应该以root身份运行。我尝试更新我的Dockerfile以创建应用用户,但是更改应用文件的权限(仍然是root用户)似乎不起作用。我猜这是因为某些LXC权限没有被授予root用户吗?

这是我的Dockerfile:

# Node.js app Docker file

FROM dockerfile/nodejs
MAINTAINER Thom Nichols "thom@thomnichols.org"

RUN useradd -ms /bin/bash node

ADD . /data
# This next line doesn't seem to have any effect:
RUN chown -R node /data 

ENV HOME /home/node
USER node

RUN cd /data && npm install

EXPOSE 8888

WORKDIR /data

CMD ["npm", "start"]

非常简单,但当我ls -l时,所有内容仍由root拥有:

[ node@ed7ae33e76e1:/data {docker-nonroot-user} ]$ ls -l /data
total 64K
-rw-r--r--  1 root root  383 Jun 18 20:32 Dockerfile
-rw-r--r--  1 root root  862 Jun 18 16:23 Gruntfile.js
-rw-r--r--  1 root root 1.2K Jun 18 15:48 README.md
drwxr-xr-x  4 root root 4.0K May 30 14:24 assets/
-rw-r--r--  1 root root  416 Jun  3 14:22 bower.json
-rw-r--r--  1 root root  930 May 30 01:50 config.js
drwxr-xr-x  4 root root 4.0K Jun 18 16:08 lib/
drwxr-xr-x 42 root root 4.0K Jun 18 16:04 node_modules/
-rw-r--r--  1 root root 2.0K Jun 18 16:04 package.json
-rw-r--r--  1 root root  118 May 30 18:35 server.js
drwxr-xr-x  3 root root 4.0K May 30 02:17 static/
drwxr-xr-x  3 root root 4.0K Jun 18 20:13 test/
drwxr-xr-x  3 root root 4.0K Jun  3 17:38 views/

My updated dockerfile works great感谢@ creak澄清了卷的工作原理。初始文件chown后,npm install作为非root用户运行。并且由于postinstall挂钩,npm运行bower install && grunt assets,它负责剩余的安装步骤,并且无需npm install -g任何节点cli工具,如bower,grunt或coffeescript。

5 个答案:

答案 0 :(得分:26)

查看此帖子:http://www.yegor256.com/2014/08/29/docker-non-root.htmlrultor.com中,我们在自己的Docker容器中运行所有构建。每次在容器内运行脚本之前,我们都会切换到非root用户。这是如何:

adduser --disabled-password --gecos '' r
adduser r sudo
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
su -m r -c /home/r/script.sh

r是我们正在使用的用户。

答案 1 :(得分:18)

更新2015-09-28

我注意到这篇文章引起了一些关注。对于有可能对此类事情感兴趣的任何人的建议。我会尝试使用Python或其他语言作为脚本执行的包装器。做本机bash脚本我试图通过各种参数传递给我的容器时遇到了问题。具体而言,shell的“和'字符的解释/转义存在问题。


我需要更改用户的原因略有不同。

我创建了一个 docker image ,其中包含 ImageMagick Ffmpeg 的全功能安装,希望我可以对图像/视频进行转换在我的主机OS中。我的问题是这些是命令行工具,因此通过docker执行它们然后将结果返回到主机操作系统稍微麻烦一些。我设法通过安装docker音量允许这个。这似乎没有用,除了图像/视频输出是由 root (即docker容器正在运行的用户)所拥有的,而不是执行命令的用户。

我看了@FrançoisZaninotto在answer中提到的方法(你可以看到完整的make脚本here)。这真的很酷,但我更喜欢创建一个bash shell脚本的选项,然后我将在我的路径上注册。我从Makefile方法(特别是用户/组创建)中获取了一些概念,然后创建了shell脚本。

以下是我的 dockermagick shell脚本的示例:

#!/bin/bash

### VARIABLES

DOCKER_IMAGE='acleancoder/imagemagick-full:latest'
CONTAINER_USERNAME='dummy'
CONTAINER_GROUPNAME='dummy'
HOMEDIR='/home/'$CONTAINER_USERNAME
GROUP_ID=$(id -g)
USER_ID=$(id -u)

### FUNCTIONS

create_user_cmd()
{
  echo \
    groupadd -f -g $GROUP_ID $CONTAINER_GROUPNAME '&&' \
    useradd -u $USER_ID -g $CONTAINER_GROUPNAME $CONTAINER_USERNAME '&&' \
    mkdir --parent $HOMEDIR '&&' \
    chown -R $CONTAINER_USERNAME:$CONTAINER_GROUPNAME $HOMEDIR
}

execute_as_cmd()
{
  echo \
    sudo -u $CONTAINER_USERNAME HOME=$HOMEDIR
}

full_container_cmd()
{
  echo "'$(create_user_cmd) && $(execute_as_cmd) $@'"
}

### MAIN

eval docker run \
    --rm=true \
    -a stdout \
    -v $(pwd):$HOMEDIR \
    -w $HOMEDIR \
    $DOCKER_IMAGE \
    /bin/bash -ci $(full_container_cmd $@)

此脚本绑定到'acleancoder / imagemagick-full'图像,但可以通过编辑脚本顶部的变量来更改。

它基本上是做什么的:

  • 容器中创建用户ID和组,以匹配从主机操作系统执行脚本的用户。
  • 主机操作系统的当前工作目录(使用docker卷)安装到我们在执行 docker容器主目录中>
  • 将tmp目录设置为容器的工作目录。
  • 传递传递给脚本的所有参数,然后由执行 docker container 的' / bin / bash '执行。

现在,我可以对主机操作系统上的文件运行 ImageMagick / Ffmpeg 命令。例如,假设我想将图像 MyImage.jpeg 转换为 PNG 文件,我现在可以执行以下操作:

$ cd ~/MyImages
$ ls
  MyImage.jpeg
$ dockermagick convert MyImage.jpeg Foo.png
$ ls
  Foo.png MyImage.jpeg

我还附加了'stdout',因此我可以运行ImageMagick识别命令来获取主机上图像的信息,例如:

$ dockermagick identify MyImage.jpeg
  MyImage.jpeg JPEG 640x426 640x426+0+0 8-bit DirectClass 78.6KB 0.000u 0:00.000

安装当前目录并允许传递任意命令定义以执行时,存在明显的危险。但是也有很多方法可以使脚本更加安全/可靠。我在我自己的非生产个人环境中执行此操作,所以这些对我来说并不是最受关注的。但如果您选择扩展此脚本,我强烈建议您考虑危险。值得一提的是,这个脚本不考虑OS X主机。我从中窃取想法/概念的make file确实将此考虑在内,因此您可以扩展此脚本来执行此操作。

需要注意的另一个限制是我只能引用当前在我执行脚本的路径中的文件。这是因为我安装卷的方式,所以以下方法不起作用:

$ cd ~/MyImages
$ ls
  MyImage.jpeg
$ dockermagick convert ~/DifferentDirectory/AnotherImage.jpeg Foo.png
$ ls
  MyImage.jpeg

最好只是转到包含图像的目录并直接执行它。当然,我确信有办法解决这个限制,但对我和我目前的需求,这样做。

答案 2 :(得分:14)

这个有点棘手,实际上是由于你开始的图像。

如果您look at the source,您会注意到/data/是一个卷。因此,您在Dockerfile中执行的所有操作都将被丢弃并在运行时被安装的卷覆盖。

您可以在运行时通过将CMD更改为CMD chown -R node /data && npm start

之类的方式来播放

答案 3 :(得分:3)

注意我在这里回答是因为,鉴于通用标题,当你寻找解决方案时,谷歌会弹出这个问题,以及在非根目录下在Docker中运行应用程序用户&#34 ;.希望它可以帮助那些滞留在这里的人。

使用 Alpine Linux,您可以创建如下系统用户:

RUN adduser -D -H -S -s /bin/false -u 1000 myuser

此行之后Dockerfile中的所有内容都以myuser执行。

myuser用户有:

  • 未分配密码
  • no home dir
  • 没有登录shell
  • 没有 root 访问权。

这来自adduser --help

-h DIR      Home directory
-g GECOS    GECOS field
-s SHELL    Login shell
-G GRP      Add user to existing group
-S          Create a system user
-D          Don't assign a password
-H          Don't create home directory
-u UID      User id
-k SKEL     Skeleton directory (/etc/skel)

答案 4 :(得分:0)

注意这个答案是因为许多寻找非root用户的人都会在这里结束。请注意,这并没有解决导致问题的问题,而是解决了@ yegor256给出的答案的标题和澄清,它使用了容器内的非root用户。这个答案解释了如何为非debian /非ubuntu用例完成此操作。这不是解决卷的问题。

在基于Red Hat的系统上,例如Fedora和CentOS,可以通过以下方式完成:

RUN adduser user && \
    echo "user ALL=(root) NOPASSWD:ALL" | tee -a /etc/sudoers.d/user && \
    chmod 0440 /etc/sudoers.d/user

在Dockerfile中,您可以通过执行以下操作来运行命令:

RUN su - user -c "echo Hello $HOME"

该命令可以运行:

CMD ["su","-","user","-c","/bin/bash"]

这方面的一个例子可以在这里找到: https://github.com/gbraad/docker-dev/commit/644c51002f4b8e6fe5bb745638542a4c3d908b16