Cấu hình file Unit Systemd để truyền Profile Seccomp
Chúng ta cần tạo một file unit systemd mới hoặc chỉnh sửa file hiện có để Docker daemon hoặc container cụ thể thừa kế chính sách Seccomp.
Mục đích là sử dụng chỉ thị SecuritySeccompBpf trong file unit để trỏ đến file profile JSON đã tạo ở Phần 4.
Hệ thống systemd sẽ đọc file này và áp dụng bộ lọc BPF (Berkeley Packet Filter) cho tiến trình Docker trước khi nó khởi động, đảm bảo container chỉ có thể gọi các system call được phép.
Đường dẫn file: /etc/systemd/system/database-container.service
Nội dung hoàn chỉnh của file:
[Unit]
Description=Secure Database Container with Seccomp and Capabilities
After=network.target
Wants=docker.service
[Service]
Type=simple
ExecStart=/usr/bin/docker run --rm --name secure-db \
--cap-drop=ALL \
--cap-add=CAP_NET_BIND_SERVICE \
--cap-add=CAP_CHOWN \
--cap-add=CAP_FOWNER \
--cap-add=CAP_SETGID \
--cap-add=CAP_SETUID \
--cap-add=CAP_DAC_OVERRIDE \
--cap-add=CAP_FOWNER \
-v /var/lib/db-data:/data \
-p 5432:5432 \
--security-opt seccomp=/etc/seccomp/db-profile.json \
postgres:15-alpine
ExecStop=/usr/bin/docker stop secure-db
Restart=on-failure
RestartSec=5
# Systemd Hardening Directives
SecuritySeccompBpf=/etc/seccomp/db-profile.json
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
SystemCallErrorNumber=EPERM
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN CAP_FOWNER CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
[Install]
WantedBy=multi-user.target
Kết quả mong đợi: File unit được lưu thành công, không báo lỗi cú pháp. Systemd đã nhận diện các chỉ thị bảo mật mới.
Giải thích các Directives bảo mật trong Systemd
Để hiểu rõ cách hoạt động, chúng ta cần phân tích các chỉ thị (Directives) quan trọng đã được thêm vào file unit trên.
Chỉ thị SecuritySeccompBpf: Trỏ đến file profile JSON. Systemd sẽ nạp file này vào kernel để lọc system calls cho tiến trình con (Docker container).
Chỉ thị CapabilityBoundingSet: Giới hạn các capabilities tối đa mà tiến trình có thể sử dụng. Dù container yêu cầu nhiều quyền hơn, kernel sẽ từ chối nếu không nằm trong tập hợp này.
Chỉ thị NoNewPrivileges: Ngăn chặn tiến trình và các tiến trình con (fork) của nó từ việc tăng quyền (ví dụ: qua setuid/setgid) sau khi khởi động.
Chỉ thị SystemCallFilter: Lọc các system calls tại mức systemd. Tham số @system-service là danh sách mặc định an toàn, ~@privileged loại bỏ các lệnh đặc quyền, ~@resources hạn chế thay đổi giới hạn tài nguyên.
Chỉ thị SystemCallErrorNumber: Khi một system call bị chặn bởi filter, kernel sẽ trả về mã lỗi EPERM (Operation not permitted) thay vì ENOSYS, giúp ứng dụng xử lý lỗi dễ hơn.
Triển khai và Chạy Container qua Systemd
Bây giờ chúng ta sẽ thực thi file unit đã cấu hình để chạy container với các ràng buộc bảo mật kép (Systemd + Docker).
Trước tiên, cần reload cấu hình của systemd để nhận diện file unit mới, sau đó khởi động service.
sudo systemctl daemon-reload
sudo systemctl start database-container.service
Kết quả mong đợi: Command chạy xong không báo lỗi. Systemd đã khởi động tiến trình Docker với các tham số bảo mật.
Kiểm tra trạng thái của service để đảm bảo nó đang chạy và không bị restart liên tục do lỗi bảo mật.
sudo systemctl status database-container.service
Kết quả mong đợi: Trạng thái hiện là active (running). Log không hiển thị các lỗi về "Permission denied" liên quan đến capabilities hoặc seccomp.
Nếu container bị dừng ngay lập tức, kiểm tra log chi tiết bằng lệnh dưới đây để xem nguyên nhân.
sudo journalctl -u database-container.service -f
Kết quả mong đợi: Có thể thấy log khởi động của PostgreSQL (ví dụ: "database system is ready to accept connections") nếu cấu hình đúng.
Xác minh các chính sách bảo mật đã áp dụng
Sau khi container đang chạy, chúng ta cần xác minh rằng các chính sách Seccomp và Capabilities đã thực sự được kernel áp dụng.
Bước 1: Kiểm tra trạng thái Seccomp của container.
Dùng lệnh docker inspect để xem cấu hình runtime của container, đặc biệt là phần HostConfig.
docker inspect secure-db | jq '.[0].HostConfig.Seccomp'
Kết quả mong đợi: Giá trị trả về là đường dẫn file profile của chúng ta (/etc/seccomp/db-profile.json) hoặc default nếu Docker override, nhưng quan trọng hơn là kiểm tra file /proc//status bên trong container.
Bước 2: Xác minh Seccomp mode từ bên trong container.
Chạy lệnh shell bên trong container để đọc file /proc/self/status và lọc dòng Seccomp.
docker exec secure-db cat /proc/self/status | grep Seccomp
Kết quả mong đợi: Giá trị phải là Seccomp: 2. Số 2 đại diện cho SECCOMP_MODE_FILTER, nghĩa là profile tùy chỉnh đã được áp dụng. Nếu là 0 thì chưa áp dụng.
Bước 3: Xác minh Capabilities thực tế.
Kiểm tra các capabilities đang được cấp cho tiến trình PostgreSQL bên trong container.
docker exec secure-db cat /proc/1/status | grep Cap
Kết quả mong đợi:
CapInh: 0000000000000000
CapPrm: 0000000000000800
CapEff: 0000000000000800
CapBnd: 0000000000000800
Giải thích kết quả: Hex 0000000000000800 tương ứng với CAP_NET_BIND_SERVICE (và các quyền nhỏ khác nếu có trong profile). Các bit khác phải là 0. Điều này chứng tỏ --cap-drop=ALL và CapabilityBoundingSet đã hoạt động.
Bước 4: Kiểm tra giới hạn System Calls từ bên ngoài (nếu cần).
Dùng systemd-analyze để xem các property của unit đang chạy.
systemctl show database-container.service | grep -E "SecuritySeccompBpf|CapabilityBoundingSet|NoNewPrivileges"
Kết quả mong đợi:
SecuritySeccompBpf=/etc/seccomp/db-profile.json
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN CAP_FOWNER CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE
NoNewPrivileges=yes
Điều này xác nhận systemd đang giữ các ràng buộc này cho tiến trình Docker.
Bước 5: Thử nghiệm tấn công giả lập (Optional nhưng khuyến khích).
Thử chạy một lệnh bị chặn (ví dụ: mount hoặc ptrace) bên trong container để đảm bảo nó bị từ chối.
docker exec secure-db mount -t proc none /mnt
echo "Exit code: $?"
Kết quả mong đợi: Lệnh thất bại với thông báo "Operation not permitted" hoặc lỗi tương tự, và exit code khác 0. Điều này chứng tỏ Seccomp đã chặn system call mount.
Đ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 6: Xây dựng Systemd Service để quản lý Database container
Phần 8: Kiểm thử bảo mật, xử lý sự cố và mẹo nâng cao »