1. Cài đặt Docker Engine và Docker Compose trên Linux
Bước đầu tiên là chuẩn bị môi trường Linux host với Docker Engine phiên bản mới nhất để hỗ trợ các tính năng bảo mật như User Namespace và Seccomp.
Chúng ta sẽ sử dụng repository chính thức của Docker để đảm bảo tính tương thích và cập nhật bảo mật kịp thời, tránh dùng gói cũ trong repo mặc định của distro.
Thực hiện các lệnh sau để cập nhật hệ thống và cài đặt Docker Engine:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
Kết quả mong đợi: Docker Engine được cài đặt thành công, dịch vụ docker chạy tự động và người dùng hiện tại có quyền truy cập docker mà không cần sudo.
Để cài đặt Docker Compose (plugin), hãy chạy lệnh kiểm tra phiên bản để xác nhận:
docker compose version
Kết quả mong đợi: Xuất hiện thông tin phiên bản Docker Compose Plugin (ví dụ: v2.20.0) và Docker Engine.
2. Viết file docker-compose.yml với các biến môi trường bảo mật
Sau khi có Docker, chúng ta sẽ tạo file cấu hình docker-compose.yml để định nghĩa container Database.
File này sẽ tập trung vào việc tách biệt biến môi trường nhạy cảm (password) ra khỏi file cấu hình chính, sử dụng file .env riêng biệt để giảm thiểu rủi ro rò rỉ mật khẩu trong VCS.
Tạo thư mục dự án và file cấu hình tại đường dẫn /var/lib/db-project/docker-compose.yml với nội dung:
cat > /var/lib/db-project/docker-compose.yml
Kết quả mong đợi: File docker-compose.yml được tạo với cấu hình an toàn, bao gồm việc drop tất cả capabilities, chỉ giữ lại những gì cần thiết, và sử dụng secret file cho mật khẩu.
3. Cấu hình quyền truy cập volume (bind mount) để cô lập dữ liệu
Để đảm bảo tính bảo mật cho dữ liệu, chúng ta cần cấu hình đúng quyền sở hữu (ownership) và quyền truy cập (permissions) cho các thư mục volume.
Docker container chạy với user "70:70" (postgres) nên thư mục dữ liệu trên host phải thuộc quyền sở hữu của user này để tránh lỗi "Permission denied" và ngăn chặn root host đọc trực tiếp file dữ liệu nhạy cảm nếu không cần thiết.
Tạo cấu trúc thư mục, file secret và file config, sau đó gán quyền sở hữu chính xác:
mkdir -p /var/lib/db-project/{secrets,config,data}
echo "SuperSecurePassword123!" > /var/lib/db-project/secrets/db_password.txt
chmod 600 /var/lib/db-project/secrets/db_password.txt
chown 70:70 /var/lib/db-project/secrets/db_password.txt
cat > /var/lib/db-project/config/postgresql.conf
Kết quả mong đợi: Thư mục data và secrets thuộc quyền sở hữu của user 70 (postgres), file mật khẩu chỉ có quyền đọc cho chủ sở hữu (600), đảm bảo container có thể đọc nhưng các user khác trên host không thể.
Để xác minh quyền sở hữu, chạy lệnh ls -la:
ls -la /var/lib/db-project/secrets/
Kết quả mong đợi: Thấy file db_password.txt với owner là postgres (uid 70) và permissions là -rw-------.
4. Chạy thử Database và xác minh kết nối từ bên ngoài
Giờ chúng ta sẽ khởi động container Database sử dụng file docker-compose.yml đã cấu hình.
Do container chạy với user không root và drop capabilities, nó sẽ yêu cầu quyền truy cập chính xác vào các volume đã cấu hình ở bước trên. Nếu quyền sai, container sẽ crash ngay lập tức.
Chuyển vào thư mục dự án và chạy lệnh start:
cd /var/lib/db-project
docker compose up -d
Kết quả mong đợi: Docker tạo volume, tải image và khởi động container. Container trạng thái là "running".
Kiểm tra trạng thái container để đảm bảo không bị lỗi exit:
docker compose ps
Kết quả mong đợi: Bảng trạng thái hiển thị container secure-postgres đang ở trạng thái "Up" và health check "healthy".
Xác minh kết nối từ bên ngoài (host) bằng công cụ psql hoặc lệnh docker exec để kiểm tra xem database có khởi động đúng với biến môi trường không:
docker exec -it secure-postgres psql -U db_admin -d production_db -c "SELECT version();"
Kết quả mong đợi: Kết quả trả về phiên bản PostgreSQL (ví dụ: PostgreSQL 15.x) chứng tỏ kết nối thành công, user và database đã được tạo đúng như cấu hình.
Để kiểm tra xem secret password có được nạp đúng không, ta có thể reset lại hoặc kiểm tra log:
docker logs secure-postgres | grep "password"
Kết quả mong đợi: Log không hiển thị password rõ văn bản (plaintext) mà chỉ thông báo "password provided" hoặc tương tự, xác nhận việc đọc từ file secret đã thành công.
Điều hướng series:
Mục lục: Series: Xây dựng Database an toàn với Linux Seccomp và Systemd Service Hardening
« Phần 1: Chuẩn bị môi trường và kiến trúc cơ bản cho Database an toàn
Phần 3: Nguyên lý hoạt động và phân tích System Call của Database »