如何防止Jenkins非root容器通过Docker Socket控制宿主机环境?
问题
我发现即使以非root身份启动Jenkins容器,当挂载/var/run/docker.sock作为卷时,Jenkins仍能以root身份在宿主机环境中启动容器,甚至可操作/etc目录。
我创建了将jenkins用户加入docker组的容器,启动配置如下:
version: '3.9' services: jenkins: image: jenkins:docker build: ./.docker/ user: "${ID_USER}:${ID_GROUP}" env_file: - .env ports: - "8080:8080" volumes: - $PWD/jenkins_home:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock networks: - jenkins-net networks: jenkins-net:
.docker目录下的Dockerfile内容为:
FROM jenkins/jenkins:latest USER root RUN apt-get update && apt-get install -y lsb-release RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \ https://download.docker.com/linux/debian/gpg RUN echo "deb [arch=$(dpkg --print-architecture) \ signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \ https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list RUN apt-get update && apt-get install -y docker-ce-cli COPY ./.env .env RUN groupadd docker && export $(cat ./.env) && \ groupmod -g $ID_GROUP docker && usermod -aG docker jenkins USER jenkins
.env文件内容:
ID_USER=1000 ID_GROUP=999
其中ID_GROUP为宿主机中docker组的ID。
测试发现jenkins用户可正常管理容器,但进入容器执行以下命令后,能无阻碍地在宿主机/etc目录创建文件:
docker run --rm -it -w /app -v /etc:/app ubuntu:latest touch test
请问是否有办法防止控制Jenkins容器的人以root身份在宿主机启动容器并操作其文件系统?
解决方案
以下是几种可行的限制方案,从不同层面降低风险:
1. 启用Docker用户命名空间映射
开启Docker的用户命名空间功能,将容器内的root用户映射到宿主机的普通用户,这样即使容器内用root操作,在宿主机上也仅拥有普通用户权限,无法修改/etc这类敏感目录。
- 配置步骤:
- 编辑Docker守护进程配置文件
/etc/docker/daemon.json,添加:{ "userns-remap": "default" } - 重启Docker服务:
systemctl restart docker
注意:启用后需重新处理现有容器和镜像,因为用户ID映射会改变文件权限关系。
- 编辑Docker守护进程配置文件
2. 使用Docker Socket Proxy过滤命令
不要直接挂载/var/run/docker.sock,改用Docker Socket Proxy作为中间层,过滤Jenkins能执行的Docker命令,禁止创建挂载宿主机敏感目录的容器。
- 示例docker-compose配置:
此配置下Jenkins只能执行代理允许的命令,无法创建挂载宿主机敏感目录的容器。services: docker-proxy: image: tecnativa/docker-socket-proxy volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - CONTAINERS=1 - IMAGES=1 - VOLUMES=0 # 禁止操作卷,避免挂载宿主机目录 - NETWORKS=1 - EXEC=0 # 禁止进入容器执行命令 - DELETE=1 networks: - jenkins-net jenkins: image: jenkins:docker build: ./.docker/ user: "${ID_USER}:${ID_GROUP}" env_file: - .env ports: - "8080:8080" volumes: - $PWD/jenkins_home:/var/jenkins_home networks: - jenkins-net environment: - DOCKER_HOST=tcp://docker-proxy:2375
3. 配置Docker RBAC细粒度权限
通过Docker的RBAC规则(需配合Swarm或第三方工具),限制Jenkins用户可执行的Docker操作,拒绝任何挂载宿主机敏感目录的请求。
- 核心思路:
- 使用第三方工具如
docker-authz实现自定义授权规则,拦截包含-v /etc这类危险挂载参数的容器创建请求。 - 针对Jenkins用户配置仅允许创建不挂载宿主机敏感目录的容器。
- 使用第三方工具如
4. 改用Docker-in-Docker(DinD)模式
让Jenkins在独立的Docker守护进程中运行容器,完全隔离宿主机的Docker环境。
- 注意:DinD需要启用特权模式,但可通过配置让Jenkins的容器在独立环境内操作,不会直接影响宿主机。不过特权模式本身存在一定风险,需根据场景权衡使用。
内容的提问来源于stack exchange,提问作者Salvatore Esposito
相关产品推荐
相关产品推荐

