非 root 运行容器

非 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
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容