Giao diện
Docker Security Audit
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Quét lỗ hổng bảo mật Docker image bằng Trivy
- Sửa Dockerfile tuân thủ security best practices
- Triển khai rootless container để giảm attack surface
- Quản lý secrets an toàn và giới hạn tài nguyên
Mô tả bài tập
Bạn audit bảo mật cho ứng dụng Node.js đã dockerize. Image hiện tại chạy root, không giới hạn resource, hardcode secrets. Nhiệm vụ: fix từng vấn đề.
Yêu cầu
Bài 1: Scan Image với Trivy
bash
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image --severity HIGH,CRITICAL node:20Yêu cầu: Scan node:20 và node:20-alpine. So sánh số lượng CVE giữa hai image.
Bài 2: Fix Dockerfile Security Issues
Dockerfile dưới đây có 4 vấn đề bảo mật. Tìm và sửa tất cả.
dockerfile
FROM node:20
ENV DATABASE_URL=postgres://admin:password@db:5432/app
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["node", "server.js"]Yêu cầu: Viết lại: dùng alpine, non-root user, không hardcode secrets, chỉ copy cần thiết.
Bài 3: Rootless Container & Resource Limits
dockerfile
FROM node:20-alpine
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci --only=production
COPY --chown=appuser:appgroup . .
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]Yêu cầu: Build image, chạy container với --memory=256m --cpus=0.5 --read-only, xác nhận process chạy user appuser.
Gợi ý
Gợi ý Bài 1
Alpine images thường có ít CVE hơn vì chỉ chứa packages tối thiểu. Dùng --format table để dễ đọc.
Gợi ý Bài 2
4 vấn đề: (1) Full image thay vì alpine, (2) Hardcode secrets trong ENV, (3) Chạy root, (4) COPY toàn bộ source.
Lời giải tham khảo
Xem lời giải
dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:20-alpine
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --chown=appuser:appgroup src/ ./src/
COPY --chown=appuser:appgroup server.js .
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]yaml
services:
api:
build: .
secrets:
- db_password
deploy:
resources:
limits:
cpus: "0.5"
memory: 256M
security_opt:
- no-new-privileges:true
read_only: true
secrets:
db_password:
file: ./secrets/db_password.txt