本文目录导读:

在Shell脚本中配置容器进程降权,主要有以下几种安全实践:
使用非root用户运行
创建专用用户(在Dockerfile中)
FROM alpine:latest
# 创建非root用户
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
# 设置工作目录权限
RUN mkdir -p /app && \
chown -R appuser:appgroup /app
WORKDIR /app
# 切换到非root用户
USER appuser
COPY --chown=appuser:appgroup . .
CMD ["./start.sh"]
Shell脚本中动态创建用户
#!/bin/sh
# 动态创建非root用户
if ! id "appuser" &>/dev/null; then
addgroup -S appgroup 2>/dev/null || groupadd -r appgroup
adduser -S appuser -G appgroup 2>/dev/null || useradd -r -g appgroup appuser
fi
# 设置文件权限
chown -R appuser:appgroup /app
# 切换到非root用户执行
exec su -s /bin/sh -c "exec $@" appuser
利用capabilities降权
丢弃不需要的权限
#!/bin/sh
# 启动容器时使用 --cap-drop
# docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE ...
# 或在脚本中直接使用capsh
capsh --drop=cap_net_raw,cap_net_admin -- \
-c "exec /usr/local/bin/myapp"
实际应用示例
#!/bin/sh
# 保留最小必要权限
echo "Starting with limited capabilities..."
# 使用setpriv(需要安装util-linux)
setpriv --no-new-privs \
--inh-caps=-all \
--bounding-set=-all \
/usr/local/bin/myapp
使用docker run参数降权
#!/bin/bash
# Docker运行时的降权配置
docker run -d \
--user 1000:1000 \ # 指定UID/GID
--cap-drop=ALL \ # 丢弃所有capabilities
--cap-add=NET_BIND_SERVICE \ # 只添加需要的
--security-opt=no-new-privileges \ # 禁止提权
--security-opt seccomp=default.json \ # 使用seccomp
--read-only-rootfs \ # 只读根目录
-v /tmp:/tmp:rw \ # 挂载可写卷
myapp:latest
完整的降权脚本示例
#!/bin/sh
# ========== 容器进程降权脚本 ==========
set -e
APP_USER="appuser"
APP_GROUP="appgroup"
APP_DIR="/app"
# 1. 创建专用用户
create_user() {
if ! id "$APP_USER" &>/dev/null; then
echo "Creating user $APP_USER..."
# Alpine使用addgroup/adduser
if command -v addgroup &>/dev/null; then
addgroup -S "$APP_GROUP"
adduser -S "$APP_USER" -G "$APP_GROUP"
else
# Ubuntu/Debian使用groupadd/useradd
groupadd -r "$APP_GROUP" 2>/dev/null
useradd -r -g "$APP_GROUP" -d "$APP_DIR" -s /sbin/nologin "$APP_USER"
fi
fi
}
# 2. 设置目录权限
setup_permissions() {
echo "Setting directory permissions..."
chown -R "$APP_USER:$APP_GROUP" "$APP_DIR"
chmod 750 "$APP_DIR"
}
# 3. 移除不需要的capabilities
drop_capabilities() {
echo "Dropping capabilities..."
# 如果安装了libcap2-bin
if command -v capsh &>/dev/null; then
capsh --drop=cap_sys_admin,cap_net_admin,cap_dac_override \
--print 2>/dev/null
fi
}
# 4. 降权执行应用
run_as_user() {
echo "Running application as $APP_USER..."
# 方法1: 使用su
# exec su -s /bin/sh -c "exec $@" "$APP_USER"
# 方法2: 使用gosu (推荐)
if command -v gosu &>/dev/null; then
exec gosu "$APP_USER" "$@"
fi
# 方法3: 使用chpst (runit工具)
if command -v chpst &>/dev/null; then
exec chpst -u "$APP_USER:$APP_GROUP" "$@"
fi
# 方法4: 使用sudo (需要配置NOPASSWD)
if command -v sudo &>/dev/null; then
exec sudo -u "$APP_USER" "$@"
fi
# 最后备选
exec su -c "exec $*" "$APP_USER"
}
# 5. 验证安全配置
verify_security() {
echo "Verifying security configuration..."
# 检查是否以root运行
if [ "$(id -u)" -eq 0 ]; then
echo "WARNING: Running as root, but will drop privileges"
fi
# 检查no-new-privileges设置
if [ -f /proc/self/status ]; then
grep "NoNewPrivs" /proc/self/status
fi
}
# 主流程
main() {
echo "Starting container security setup..."
create_user
setup_permissions
drop_capabilities
verify_security
# 执行应用
run_as_user "$@"
}
# 如果直接执行脚本
if [ "$(basename "$0")" = "entrypoint.sh" ]; then
main "$@"
fi
Docker Compose示例
version: '3.8'
services:
app:
build: .
user: 1000:1000
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /tmp
volumes:
- app_data:/app/data
最佳实践建议
-
最小权限原则:
- 只赋予必要的权限
- 使用
--cap-drop=ALL然后单独添加
-
用户映射:
- 使用
--user或USER指令 - 避免使用UID 0
- 使用
-
文件系统安全:
--read-only-rootfs只读根文件系统- 挂载临时目录用于写入
-
内核安全特性:
- 启用seccomp过滤器
- 使用AppArmor或SELinux
-
网络隔离:
- 避免使用
--privileged - 限制网络capabilities
- 避免使用
这样配置后,容器进程将以非root用户运行,并且只拥有最小必要权限,大大提高了容器安全性。