背景与适用场景
Docker 已经成为现代服务部署的事实标准,但容器安全问题也随之而来。镜像漏洞、错误配置、密钥泄露、容器逃逸等问题在实际生产环境中时有发生。本文从运维角度出发,讲解 Docker 安全加固的实战方法,覆盖镜像安全、镜像构建最佳实践、容器运行时配置、密钥管理、网络隔离和监控审计。让你能对 Docker 环境做一次全面的安全加固。
适合阅读本文的场景:
新机器上部署 Docker,不清楚安全基线该怎么配
已有 Docker 环境,发现有安全风险需要整改
排查容器被入侵、挖矿、植入后门的原因
需要给容器做密钥管理和网络隔离
审计容器的系统调用和行为
建立 Docker 安全基线和运维规范
阅读本文需要具备基本的 Linux 操作能力和 Docker 使用经验。
Docker 安全风险概览
常见 Docker 安全问题
1. 镜像漏洞:基础镜像有 CVE 漏洞 2. 密钥泄露:密钥硬编码在镜像或配置文件中 3. 容器逃逸:容器内权限过大,可渗透到宿主机 4. 错误配置:特权容器、共享宿主机的 namespaces 5. 恶意镜像:使用了被篡改的官方镜像 6. 供应链攻击:依赖库有漏洞或被篡改 7. 资源耗尽:容器无限占用宿主机资源 8. 镜像篡改:拉取的镜像被中间人攻击替换
安全加固总体思路
纵深防御:多层安全机制叠加 1. 镜像层:使用最小化基础镜像,定期扫描漏洞 2. 构建层:安全构建流程,防止密钥泄露 3. 运行时层:限制容器权限,最小化 capabilities 4. 网络层:网络隔离,限制容器间访问 5. 监控层:审计日志,异常行为告警 6. 主机层:安全基线配置,资源限制
镜像安全
使用最小化基础镜像
生产环境不要用 ubuntu、debian 这类完整发行版作为基础镜像,应该用专门裁剪过的镜像。
# 不推荐:完整系统镜像 FROM ubuntu:22.04 FROM debian:bookworm FROM python:3.11 # 推荐:Alpine 或 distroless FROM alpine:3.19 FROM python:3.11-alpine FROM gcr.io/distroless/static-debian12 # 最佳:distroless(Google 出品,仅包含运行时) FROM gcr.io/distroless/static-debian12 # 多阶段构建示例:构建时用完整镜像,运行用最小镜像 FROM golang:1.22-alpine AS builder WORKDIR /app COPY . . RUN go build -o myapp FROM alpine:3.19 COPY --from=builder /app/myapp /myapp ENTRYPOINT ["/myapp"]
定期扫描镜像漏洞
# 1. 使用 Trivy 扫描(推荐,开源免费) # 安装 wget https://github.com/aquasecurity/trivy/releases/download/v0.53.0/trivy_0.53.0_Linux-64bit.tar.gz tar -xzf trivy_0.53.0_Linux-64bit.tar.gz mv trivy /usr/local/bin/ # 扫描镜像 trivy image alpine:3.19 trivy image nginx:1.25 trivy image myregistry/myapp:latest # 扫描文件系统目录 trivy fs /path/to/project # 只显示高危漏洞 trivy image --severity HIGH,CRITICAL nginx:1.25 # 输出 JSON 格式供集成使用 trivy image -f json --output result.json myregistry/myapp:latest # 2. 使用 Docker Scout(Docker 官方) docker scout cves myregistry/myapp:latest docker scout recommendations myregistry/myapp:latest # 3. 使用 Grype(Anchore 出品) docker run --rm -v /var/run/docker.sock:/var/run/docker.sock anchore/grype:latest myregistry/myapp:latest # 4. 在 CI/CD 中集成漏洞扫描 # .gitlab-ci.yml 示例 scan: stage: security script: - trivy image --exit-code 1 --severity HIGH,CRITICAL$IMAGE_TAG rules: -if:$CI_COMMIT_BRANCH=="main"
镜像签名和内容信任
防止拉取到被篡改的镜像。
# 1. 开启 Docker Content Trust exportDOCKER_CONTENT_TRUST=1 exportDOCKER_CONTENT_TRUST_SERVER_PASSWORD=xxx exportDOCKER_CONTENT_TRUST_SERVER_PIN=xxx # 拉取镜像时自动验证签名 docker pull myregistry/myapp:latest # 2. 使用 Cosign 签名镜像(更现代的方式) # 安装 cosign wget https://github.com/sigstore/cosign/releases/download/v2.2.0/cosign-linux-amd64 mv cosign-linux-amd64 /usr/local/bin/cosign chmod +x /usr/local/bin/cosign # 签名镜像 cosign sign --key cosign.key myregistry/myapp:latest # 验证镜像 cosign verify --key cosign.pub myregistry/myapp:latest # 3. 在 Docker Compose 中强制签名验证 # docker-compose.yml version:"3.8" services: app: image: myregistry/myapp:latest priviledged:false
Dockerfile 安全构建
正确处理密钥
# 错误示例:密钥硬编码 FROMalpine:3.19 ENVAPI_KEY=sk-xxxxxxx # 不要这样做 COPYsecret.key /app/secret.key # 不要这样做 # 正确示例:运行时注入密钥 FROMalpine:3.19 # 使用空文件占位,构建时不要包含真实密钥 COPYdummy-key.pub /app/key.pub # 正确做法:通过环境变量或挂载 # docker run -e API_KEY=sk-xxxxxxx myapp # docker run -v /path/to/key:/app/key:ro myapp # 多阶段构建:构建阶段用密钥,运行阶段不要密钥 FROMgolang:1.22-alpine AS builder ARGAPI_KEY ENVAPI_KEY=$API_KEY RUNgo build -ldflags="-X main.apiKey=$API_KEY"-o myapp FROMalpine:3.19 COPY--from=builder /app/myapp /myapp # 运行时不需要 API_KEY ENTRYPOINT["/myapp"] # 构建时传入密钥 # docker build --build-arg API_KEY=sk-xxxxxxx .
最小化权限
# 使用非 root 用户运行 FROMalpine:3.19 # 创建应用用户 RUNaddgroup -g 1000 appgroup && adduser -u 1000 -G appgroup -s /bin/sh -D appuser # 切换到非 root 用户 USERappuser # 如果必须用 root(不推荐),确保只读文件系统 # docker run --read-only myapp # 清理缓存和临时文件(alpine 用 apk) RUNapk add --no-cache --virtual .build-deps some-package && rm -rf /var/cache/apk/* # pip 清理缓存 RUNpip install --no-cache-dir -r requirements.txt
其他 Dockerfile 安全建议
# 使用 COPY 而非 ADD(COPY 更透明) COPY--chown=appuser:appgroup app /app # 显式指定端口(不暴露不需要的端口) EXPOSE8080 # 设置工作目录 WORKDIR/app # 健康检查 HEALTHCHECK--interval=30s --timeout=3s --start-period=5s --retries=3 CMD curl -f http://localhost:8080/health ||exit1 # 不要用 latest 标签 # 错误:FROM nginx:latest # 正确:FROM nginx:1.25.4-alpine # 验证下载文件的完整性 RUNwget -O file.tar.gz https://example.com/file.tar.gz &&echo"sha256:abc123..."| sha256sum -c -
Docker 守护进程配置
安全配置文件
# /etc/docker/daemon.json
{
"icc":false,
"userns-remap":"default",
"live-restore":true,
"no-new-privileges":true,
"default-ulimits": {
"nofile": {
"Name":"nofile",
"Hard": 64000,
"Soft": 64000
}
},
"default-cgroupns-mode":"host",
"storage-driver":"overlay2",
"log-driver":"json-file",
"log-opts": {
"max-size":"100m",
"max-file":"3"
},
"registry-mirrors": [],
"insecure-registries": [],
"userland-proxy":false,
"fixed-cidr":"172.17.0.0/16"
}
关键配置项说明
# icc=false:禁止容器间通信 # userns-remap:启用用户命名空间重映射(防止容器逃逸) # no-new-privileges:禁止容器获取新权限 # live-restore:Docker 重启时容器保持运行 # default-ulimits:设置默认资源限制 # userland-proxy=false:使用 iptables 代替用户空间代理(更安全) # storage-driver:使用 overlay2 存储驱动 # 重启 Docker 使配置生效 systemctl restart docker # 验证配置 docker info | grep -E"Storage Driver|USerns|Logging"
容器运行时安全配置
最小化容器权限
# 1. 不要用特权容器 # 错误:docker run --privileged myapp # 正确:不加 --privileged 参数 # 2. 使用只读文件系统 docker run --read-only myapp # 3. 限制 capabilities(Linux 能力) # 查看所有可用 capabilities capsh --print # 运行容器时去掉不需要的 capabilities docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp # 4. 禁止容器获取新权限 docker run --security-opt=no-new-privileges:truemyapp # 5. 禁用 SUID 和 SGID docker run --security-opt=no-new-privileges:true --security-opt="seccomp=profile.json" myapp # 6. 使用 AppArmor/SELinux 限制 docker run --security-opt apparmor=my-profile myapp docker run --security-opt label=type:container_t myapp
seccomp 配置文件
# 下载默认 seccomp 配置文件
curl -o /etc/docker/seccomp.json https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json
# 自定义 seccomp 配置(只允许需要的系统调用)
cat > /etc/docker/seccomp-app.json << 'EOF'
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_ARM"
],
"syscalls": [
{
"names": [
"accept",
"accept4",
"access",
"alarm",
"arch_prctl",
"bind",
"brk",
"capget",
"capset",
"chdir",
"chmod",
"chown",
"chown32",
"clock_getres",
"clock_gettime",
"clock_nanosleep",
"close",
"connect",
"copy_file_range",
"creat",
"dup",
"dup2",
"dup3",
"epoll_create",
"epoll_create1",
"epoll_ctl",
"epoll_pwait",
"epoll_wait",
"eventfd",
"eventfd2",
"execve",
"execveat",
"exit",
"exit_group",
"faccessat",
"fadvise64",
"fadvise64_64",
"fallocate",
"fanotify_init",
"fanotify_mark",
"fchdir",
"fchmod",
"fchmodat",
"fchown",
"fchown32",
"fchownat",
"fcntl",
"fcntl64",
"fdatasync",
"fgetxattr",
"flistxattr",
"flock",
"fork",
"fremovexattr",
"fsetxattr",
"fstat",
"fstat64",
"fstatat64",
"fstatfs",
"fstatfs64",
"fsync",
"ftruncate",
"ftruncate64",
"futex",
"futimesat",
"getcwd",
"getdents",
"getdents64",
"getegid",
"getegid32",
"geteuid",
"geteuid32",
"getgid",
"getgid32",
"getgroups",
"getgroups32",
"getitimer",
"getpeername",
"getpgid",
"getpgrp",
"getpid",
"getppid",
"getpriority",
"getrandom",
"getresgid",
"getresgid32",
"getresuid",
"getresuid32",
"getrlimit",
"get_robust_list",
"getrusage",
"getsid",
"getsockname",
"getsockopt",
"gettid",
"gettimeofday",
"getuid",
"getuid32",
"getxattr",
"io_cancel",
"io_destroy",
"io_getevents",
"io_setup",
"io_submit",
"ioctl",
"ipc",
"kill",
"lchown",
"lchown32",
"lgetxattr",
"link",
"linkat",
"listen",
"listxattr",
"llistxattr",
"_llseek",
"lremovexattr",
"lseek",
"lsetxattr",
"lstat",
"lstat64",
"lstatfs",
"lstatfs64",
"madvise",
"mbind",
"memfd_create",
"mincore",
"mkdir",
"mkdirat",
"mknod",
"mknodat",
"mlock",
"mlock2",
"mlockall",
"mmap",
"mmap2",
"mprotect",
"mremap",
"msgget",
"msgrcv",
"msgsnd",
"msync",
"munlock",
"munlockall",
"munmap",
"name_to_handle_at",
"nanosleep",
"newfstatat",
"nfsservctl",
"nice",
"open",
"openat",
"openat2",
"pause",
"perf_event_open",
"pipe",
"pipe2",
"poll",
"ppoll",
"prctl",
"pread64",
"preadv",
"prlimit64",
"process_vm_readv",
"process_vm_writev",
"pselect6",
"ptrace",
"pwrite64",
"pwritev",
"read",
"readahead",
"readlink",
"readlinkat",
"readv",
"recv",
"recvfrom",
"recvmsg",
"remap_file_pages",
"removexattr",
"rename",
"renameat",
"renameat2",
"restart_syscall",
"rmdir",
"rt_sigaction",
"rt_sigpending",
"rt_sigprocmask",
"rt_sigqueueinfo",
"rt_sigreturn",
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_tgsigqueueinfo",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
"sched_getpriority_max",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_setaffinity",
"sched_setattr",
"sched_setparam",
"sched_setscheduler",
"sched_yield",
"seccomp",
"select",
"semget",
"semop",
"semtimedop",
"send",
"sendfile",
"sendmsg",
"sendto",
"setdomainname",
"setfsgid",
"setfsgid32",
"setfsuid",
"setfsuid32",
"setgid",
"setgid32",
"setgroups",
"setgroups32",
"setitimer",
"setns",
"setpgid",
"setpriority",
"setregid",
"setregid32",
"setresgid",
"setresgid32",
"setresuid",
"setresuid32",
"setreuid",
"setreuid32",
"setrlimit",
"set_robust_list",
"setsid",
"setsockopt",
"setthreadarea",
"set_tid_address",
"setuid",
"setuid32",
"setxattr",
"shmat",
"shmctl",
"shmdt",
"shmget",
"shutdown",
"sigaltstack",
"signalfd",
"signalfd4",
"socket",
"socketpair",
"splice",
"stat",
"stat64",
"statfs",
"statfs64",
"statx",
"symlink",
"symlinkat",
"sync",
"sync_file_range",
"syncfs",
"sysinfo",
"syslog",
"tee",
"tgkill",
"time",
"timer_create",
"timer_delete",
"timer_getoverrun",
"timer_gettime",
"timer_settime",
"timerfd_create",
"times",
"tkill",
"truncate",
"truncate64",
"ugetrlimit",
"umask",
"uname",
"unlink",
"unlinkat",
"unshare",
"uselib",
"userfaultfd",
"ustat",
"utime",
"utimensat",
"utimes",
"vfork",
"vhangup",
"vmsplice",
"wait4",
"waitid",
"waitpid",
"write",
"writev"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
EOF
# 使用自定义 seccomp 配置
docker run --security-opt seccomp=/etc/docker/seccomp-app.json myapp
资源限制
# 内存限制 docker run -m 512m --memory-swap 1g myapp # CPU 限制 docker run --cpus 1.5 myapp docker run --cpus=0.5 --cpuset-cpus="0,1"myapp # 限制 PIDs(防止 Fork 炸弹) docker run --pids-limit 100 myapp # I/O 限制 docker run --device-read-bps /dev/sda:10mb myapp docker run --device-write-bps /dev/sda:10mb myapp docker run --device-read-iops /dev/sda:1000 myapp docker run --device-write-iops /dev/sda:1000 myapp # 网络带宽限制(需要开启流量控制) docker run --network none myapp # 完全禁用网络 # Docker Compose 中的资源限制 # docker-compose.yml version:"3.8" services: app: image: myapp deploy: resources: limits: cpus:'1.5' memory: 512M reservations: cpus:'0.5' memory: 256M
密钥管理
不要在容器中存储密钥
# 错误做法:密钥在镜像或容器中 # Dockerfile: ENV API_KEY=sk-xxx # docker run -e API_KEY=sk-xxx # 环境变量会被其他容器看到 # 正确做法 1:使用密钥管理服务 # HashiCorp Vault、AWS Secrets Manager、Azure Key Vault # 正确做法 2:使用 Docker secrets(Swarm 模式) docker secret create api_key api_key.txt docker service create --secret api_key myapp # 正确做法 3:挂载只读密钥文件 docker run -v /path/to/secrets:/run/secrets:ro myapp # 密钥文件权限设置为 400 # 正确做法 4:K8s Secret kubectl create secret generic api-key --from-literal=api-key=sk-xxx kubectl apply -f pod.yaml # pod 中引用 secret
Vault 集成示例
# 1. 启动 Vault(生产环境应该用高可用部署) docker run -d --name=vault -p 8200:8200 -e VAULT_ADDR=http://localhost:8200 -e VAULT_TOKEN=xxx vault server -dev # 2. 存储密钥 vault kv put secret/myapp/api-key value=sk-xxx vault kv get secret/myapp/api-key # 3. 应用从 Vault 获取密钥(使用 sidecar 或 init container) # init-container 方式获取密钥 # pod.yaml apiVersion: v1 kind: Pod metadata: name: myapp spec: initContainers: - name: get-secrets image: vault:1.13 env: - name: VAULT_ADDR value:"http://vault:8200" - name: VAULT_TOKEN valueFrom: secretKeyRef: name: vault-token key: token command: - sh - -c - | vault kv get -format=json secret/myapp/api-key | jq -r'.data.data.api_key'> /secrets/api_key volumeMounts: - name: secrets mountPath: /secrets containers: - name: app image: myapp volumeMounts: - name: secrets mountPath: /secrets readOnly:true volumes: - name: secrets emptyDir: medium: Memory
网络隔离
容器网络模式选择
# 1. bridge(默认):容器在桥接网络,可以和其他容器通信 docker run --network bridge myapp # 2. host:容器直接用宿主机网络栈(危险,不推荐) docker run --network host myapp # 3. none:禁用网络 docker run --network none myapp # 4. 自定义网络:实现容器间隔离 docker network create --driver bridge mynetwork docker run --network mynetwork myapp # 5. 网络隔离示例 docker network create frontend docker network create backend # Web 服务在 frontend 网络 docker run --network frontend --name web myweb # 数据库只在 backend 网络 docker run --network backend --name db mydb # Web 容器无法直接访问 db,只能通过 backend 网络的某个服务访问
网络访问控制
# 1. iptables 限制容器网络访问 # 禁止容器访问特定 IP iptables -I DOCKER -p tcp -d 10.0.0.1 -j DROP # 禁止容器访问外网(只允许内网) iptables -I DOCKER -p tcp ! -s 172.17.0.0/16 -j DROP # 2. Docker Compose 网络配置 # docker-compose.yml version:"3.8" services: app: image: myapp networks: - frontend db: image: mysql:8.0 networks: - backend # 只有 app 能访问 db external_links: - app networks: frontend: driver: bridge backend: driver: bridge internal:true# 完全隔离,不能访问外网
服务间认证(mTLS)
# 使用 linkerd 或 istio 实现服务间 mTLS 加密 # 示例:linkerd 配置 apiVersion: v1 kind: Namespace metadata: name: production annotations: linkerd.io/inject: enabled
容器监控与审计
审计容器行为
# 1. 启用 Docker 日志审计
# /etc/docker/daemon.json 中配置日志驱动
{
"log-driver":"json-file",
"log-opts": {
"max-size":"100m",
"max-file":"5"
}
}
# 2. 查看容器日志
docker logs mycontainer
docker logs --tail 100 mycontainer
docker logs --since 2026-05-29T10:00 mycontainer
docker logs --since 10m mycontainer
# 3. 集中式日志收集(ELK/Loki)
# Filebeat 收集 Docker 日志
filebeat.inputs:
-type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_docker_metadata:
host:"unix:///var/run/docker.sock"
# 4. Falco 容器行为审计
# 安装 Falco
curl -s https://download.falco.org/packages/rpm/stable/falco-0.37.0-x86_64.rpm | rpm -ivh -
# Falco 规则示例(检测异常行为)
# /etc/falco/falco_rules.yaml
- rule: Terminal shellincontainer
desc: A shell was spawnedina container other than'shell','sh','bash','ash'
condition: >
spawned_process and
container and
proc.namein(shell_binaries) and
not proc.pnamein(shell_binaries)
output: >
Shell spawnedincontainer
(user=%user.name container_id=%container.id
container_name=%container.name
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)
priority: NOTICE
- rule: Unauthorized container image
desc: Detected use of unauthorized image
condition: >
container and
container.image.repository !="myregistry/trusted-image"
output: >
Unauthorized container image
(container_id=%container.id image=%container.image.repository)
priority: WARNING
实时监控
# 1. docker stats 查看资源使用
docker stats
docker stats --no-stream mycontainer
docker stats --format"table {{.Name}} {{.CPUPerc}} {{.MemUsage}}"
# 2. cAdvisor 监控
docker run
--volume=/:/rootfs:ro
--volume=/var/run:/var/run:ro
--volume=/sys:/sys:ro
--volume=/var/lib/docker/:/var/lib/docker:ro
--volume=/dev/disk/:/dev/disk:ro
--publish=8080:8080
gcr.io/cadvisor/cadvisor:latest
# 3. Prometheus 监控 Docker
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name:'docker'
static_configs:
- targets: ['cadvisor:8080']
定期安全检查
# 1. Docker Bench Security(官方安全基线检查) docker run -it --net host --pid host --userns host --cap-add audit_control -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST -v /var/lib:/var/lib -v /var/run/docker.sock:/var/run/docker.sock aquasec/docker-bench:latest # 2. 扫描运行中的容器 trivy image --security-checks vuln,config myapp:latest # 3. 检查容器配置 docker inspect mycontainer | jq'.[].HostConfig' # 4. 检查 Dockerfile hadolint Dockerfile # 5. 检查网络安全 # 查看容器网络连接 dockerexec-it mycontainer ss -tlnp dockerexec-it mycontainer netstat -tlnp # 查看容器的 iptables 规则 iptables -L DOCKER -n -v
Docker 安全基线配置
主机安全基线
# 1. 禁止 Docker 访问宿主机敏感目录
# /etc/docker/daemon.json
{
"storage-driver":"overlay2",
"live-restore":true
}
# 2. 内核安全参数调优
# /etc/sysctl.d/99-docker.conf
# 禁止容器获取新的 capabilities
kernel.cap_last_cap = 37
# 禁止容器访问 /proc/sys
vm.protected_regular = 1
vm.unprivileged_userfaultfd = 1
# 3. AppArmor/Docker 配置
# /etc/apparmor.d/docker
生产环境 Docker 安全检查清单
# 镜像检查 [ ] 使用最小化基础镜像(alpine/distroless) [ ] 镜像无最新标签 [ ] 镜像已扫描无高危漏洞 [ ] 镜像已签名验证 # 构建检查 [ ] Dockerfile 不包含密钥 [ ] 使用非 root 用户运行 [ ] 只读文件系统 [ ] 清理缓存和临时文件 # 运行时检查 [ ] 资源限制配置(CPU/内存) [ ] 网络隔离配置 [ ] 禁用特权容器 [ ] capabilities 最小化 [ ] seccomp 配置 # 运维检查 [ ] 日志集中收集 [ ] 监控告警配置 [ ] 安全扫描集成 [ ] 定期更新镜像
常见安全问题修复
问题 1:容器内 root 权限过大
# 问题:容器以 root 运行,拥有过多 Linux capabilities # 修复方案 # 1. 创建非 root 用户 RUN addgroup -g 1000 appgroup && adduser -u 1000 -G appgroup -s /bin/sh -D appuser USER appuser # 2. 限制 capabilities docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp # 3. 使用只读文件系统 docker run --read-only --cap-drop ALL myapp
问题 2:敏感信息泄露
# 问题:密钥在环境变量或镜像中 # 修复方案 # 1. 使用密钥管理服务 # 2. 使用 Docker secrets(Swarm) # 3. 使用 K8s Secret # 4. 挂载只读密钥文件 docker run -v /secrets:/secrets:ro myapp chmod 400 /secrets/api_key
问题 3:容器逃逸风险
# 问题:--privileged 或共享宿主机 namespaces
# 修复方案
# 1. 不要使用 --privileged
# 2. 不要共享宿主机网络
# 3. 启用用户命名空间重映射
# /etc/docker/daemon.json
{
"userns-remap":"default"
}
# 4. 禁止获取新权限
docker run --security-opt=no-new-privileges:truemyapp
问题 4:镜像漏洞
# 问题:基础镜像有 CVE 漏洞 # 修复方案 # 1. 使用最小化镜像 FROM alpine:3.19 # 而不是 ubuntu/debian # 2. 定期更新基础镜像 docker pull alpine:3.19 docker build --pull . # 3. 使用 Distroless FROM gcr.io/distroless/static-debian12 # 4. 在 CI/CD 中集成漏洞扫描 trivy image --exit-code 1 --severity HIGH,CRITICAL myapp
总结
Docker 安全加固需要从多个层面入手:
镜像层:
使用最小化基础镜像(Alpine、distroless)
定期扫描漏洞(Trivy、Grype、Docker Scout)
镜像签名验证(Content Trust、Cosign)
构建层:
不在 Dockerfile 中硬编码密钥
使用非 root 用户运行
多阶段构建分离构建环境和运行环境
清理缓存和临时文件
运行时层:
资源限制(CPU、内存、PIDs)
网络隔离(自定义网络、禁止容器间通信)
capabilities 最小化(--cap-drop ALL)
seccomp/AppArmor 限制
只读文件系统
密钥管理:
不在容器中存储密钥
使用 Vault 或云服务商密钥管理
K8s Secret/Docker secrets
监控审计:
集中式日志收集
Falco 容器行为审计
Docker Bench Security 基线检查
Prometheus 监控
安全不是一次性工作,需要持续关注。建立安全基线、集成安全扫描到 CI/CD、定期巡检,才能保证 Docker 环境长期安全运行。
-
容器
+关注
关注
0文章
544浏览量
23076 -
镜像
+关注
关注
0文章
183浏览量
11729 -
Docker
+关注
关注
0文章
541浏览量
14527
原文标题:生产环境 Docker 安全加固:从镜像扫描到运行时防护
文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
如何判断是否在docker镜像中?
Docker监控实战分析
生产环境中Docker安全加固的实战方法
评论