非 root 运行容器
为什么需要非 root 运行
容器默认以 root 用户运行,这是常见的安全风险。容器内的 root 在宿主机上虽然受到 Namespace 隔离,但仍拥有部分系统权限,提权漏洞可能导致容器逃逸。
安全原则:容器中的进程应该使用最小必要权限,非 root 运行是最基本的安全实践。
Dockerfile 中设置非 root 用户
创建专用用户
FROM node:18-alpine
# 创建用户和组
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 设置工作目录
WORKDIR /app
# 复制文件
COPY . .
# 确保应用文件属主
RUN chown -R appuser:appgroup /app
# 切换到非 root 用户
USER appuser
# 启动应用
CMD ["node", "app.js"]
常见语言的基础配置
# Python
FROM python:3.11-slim
RUN addgroup --system app && adduser --system --group app
USER app
# Node.js
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# Go(编译后不需要运行时)
FROM alpine:3.18
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /app/myapp /myapp
USER appuser
CMD ["/myapp"]
# Java
FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
docker run 中指定用户
# 使用 UID 和 GID
docker run --user 1000:1000 nginx
# 使用用户名(需要在镜像中存在)
docker run --user appuser nginx
# 不指定组
docker run --user 1000 nginx
# 只指定 UID
docker run -u 1000 nginx
Compose 中的非 root 配置
services:
app:
image: myapp
user: "1000:1000"
# 或者使用镜像中创建的用户
# user: appuser
nginx:
image: nginx:alpine
user: nginx
端口映射与非 root 用户
非 root 用户不能绑定 <1024 的端口:
# ❌ 非 root 用户不能绑定 80 端口
services:
nginx:
user: nginx
ports:
- "80:80" # 失败
# ✅ 使用高位端口,然后端口映射
services:
nginx:
user: nginx
ports:
- "80:8080" # 宿主机 80 → 容器 8080
# ✅ 或给容器 CAP_NET_BIND_SERVICE
services:
nginx:
user: nginx
cap_add:
- NET_BIND_SERVICE
ports:
- "80:80"
数据卷的权限问题
非 root 用户挂载数据卷时可能遇到权限问题:
services:
app:
user: "1000:1000"
volumes:
- ./data:/app/data
# 宿主机目录权限必须匹配
mkdir data
chown 1000:1000 data
# 或创建时设置权限
mkdir -p data && chmod 777 data # 不推荐
最佳实践:使用命名卷(不需要设置权限):
services:
app:
user: "1000:1000"
volumes:
- appdata:/app/data
volumes:
appdata: # Docker 自动管理权限
不同基础镜像的用户创建命令
# Alpine(adduser)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Debian/Ubuntu(adduser)
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
# CentOS/RHEL
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
# Distroless
# 在 multi-stage 中创建用户
验证非 root 运行
# 检查容器中的用户
docker exec myapp whoami
# appuser
# 检查进程用户
docker exec myapp id
# uid=1000(appuser) gid=1000(appgroup)
# 检查 UID
docker inspect myapp --format '{{.Config.User}}'
# appuser
# 检查是否能写敏感位置
docker exec myapp touch /etc/test
# touch: /etc/test: Permission denied
特殊情况处理
需要访问 Docker Socket
# 添加用户到 docker 组
docker run -v /var/run/docker.sock:/var/run/docker.sock \
--group-add docker \
myapp
需要 root 的初始化操作
使用 multi-stage 或 init 脚本:
FROM alpine:3.18
# 安装依赖在 root 阶段完成
RUN apk add --no-cache nginx
# 启动时创建所需目录
RUN mkdir -p /var/cache/nginx /var/run/nginx && \
chown -R nginx:nginx /var/cache/nginx /var/run/nginx
USER nginx
安全检查清单
- [ ] Dockerfile 中是否有
USER指令? - [ ] 是否避免了
--privileged? - [ ] 数据卷权限是否正确?
- [ ] 端口映射是否适配非 root 用户?
- [ ] 非 root 用户能否正常写日志?
- [ ] 非 root 用户能否访问所需资源?
非 root 运行是容器安全的第一道防线,应该在所有 Dockerfile 中使用。这是实现最小权限原则最直接、最有效的方式。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容