简介
- 所有人都建议容器内的进程不应该以root身份运行
- (除了
kubernetes
),似乎没有很好的devops/配置即代码方法来设置正确的所有者/权限,使得(非root)用户无法写入卷
那么,在将容器进程作为非root
用户运行并且想要写入(cloudstor,aws-ebs)docker卷时,什么是良好的实践呢?
长话短说
在docker容器内(和外部),将进程以root用户身份运行被视为不良实践(参见ref1,ref2等)。这可能会带来安全隐患。
但是,当我们开始使用docker卷并且非root用户尝试向卷写入内容时,问题就出现了。我无法找到一个干净的解决方案,在云基础架构上能够工作,而且不需要手动干预。我找到的可行解决方案似乎都有某些缺点(安全性,可维护性,...)。
顺便提一下,我们正在使用docker-swarm
来部署,并使用cloudstor
来提供aws-ebs
卷。我们希望有一天能够迁移到kubernetes,但我们还没有kubernetes,因此我们试图找到我们设置的替代解决方案。
可考虑的解决方案/变通方法
1. 在docker镜像内预先创建卷
正如此处所提出的,如果docker-compose
创建了一个新的卷,则图像内部目录上的权限将被传播。
缺点:
- 如果该卷之前存在或者是磁盘上的文件夹,则无法使用此方法。
- 如果使用
cloudstor
配置此卷,则此方法可能无效,因为不是docker-compose
创建该卷(未经测试)。
2. 使用volumes-provisioner
hasnat创建了一个volumes-provisioner镜像,可以在真正的容器启动之前设置正确的文件夹权限。
缺点:
- 需要在docker堆栈中添加一个额外的服务。这项服务几乎会立即停止(设置权限后)。
- 真正的容器需要依赖于volumes_provisioner。当重新部署相同的堆栈(在配置更改后)时,执行顺序不能保证
ebs
卷只能挂载在单个docker容器上,这导致了许多部署问题
3.使用docker run
来更正文件权限
一旦真正的容器与挂载的卷一起运行(但仍具有错误的权限),我们调用
docker run --rm -u root -v ${MOUNT}:${TARGET} { real_image } chown -R user:group ${TARGET}
缺点:
ebs
卷只能在一个容器中挂载,因此这将创建冲突。- 此命令只能在docker-stack部署后运行(否则卷尚未被配置),因此实际容器启动和正确权限之间会有延迟。这意味着,在启动时,真正的容器会发现权限不正确的卷,因此只有服务一直检查权限是否已被更正,才能正常工作。
4. 启动容器时更改所有权
这意味着:
- 以
root
用户身份启动进程(否则我们没有更改目录所有者/权限的权限) - 更改所有权/权限
- 切换到
非root
用户
缺点:
- 仍然存在(轻微?)时间段,容器进程正在以root身份运行(安全隐患?)
- 需要修改官方镜像的entrypoints、覆盖用户等等才能使其正常工作
5. 以root身份直接运行
这是最简单的解决方案,但安全性如何?而且每个人都建议不要这样做?6. 使用kubernetes
如此处建议的那样,我们可以使用kubernetes为卷分配组ID。这似乎在kubernetes pod文档中得到了确认。 缺点:
- (遗憾的是)我们还没有使用
kubernetes
。 - (未经测试)。
确保文件系统上存在具有正确所有者/权限的目录。 缺点:
- 这不是云存储...如果容器切换到另一个节点怎么办?或者服务器崩溃了?(这就是为什么我们使用
cloudstor
,它甚至允许我们切换可用区域) - 看起来不太像“配置即代码”
docker-compose
环境,我们创建所有内容而不启动服务(docker-compose up --no-start
),然后设置权限(docker run --rm -it --volumes-from ... --entrypoint chown alpine:3 -R 1000:1000 /data
),最后启动服务。对于k8s常见做法是使用initContainers。 - masseyb