Podman vs Docker: Những Vấn Đề Bảo Mật Mà Podman Thực Sự Giải Quyết
Vấn đề bảo mật của Docker là vấn đề kiến trúc
Khi bạn cài Docker, bạn có dockerd — một tiến trình daemon chạy với quyền root. Mỗi lệnh docker bạn gõ đều giao tiếp với daemon đó qua Unix socket tại /var/run/docker.sock.
Tài liệu cảnh báo không nên expose socket đó một cách tùy tiện. Vấn đề là: sự tồn tại của socket chính là lỗ hổng.
Bất kỳ thứ gì có quyền truy cập socket đó đều có thể chạy:
docker run -v /:/host --rm -it alpine chroot /hostLệnh này mount toàn bộ filesystem của host vào container và mở shell root trên host. Thoát hoàn toàn. Không cần CVE — đây là hành vi được thiết kế.
Docker socket về bản chất là một root shell với vài bước thêm. Bất cứ thứ gì có thể ghi vào socket đó đều làm chủ được máy của bạn.
Những gì thực sự xảy ra trong thực tế
1. Socket bị expose trong CI/CD
Pattern phổ biến nhất cho Docker-in-Docker trong CI là mount socket vào build container:
volumes: - /var/run/docker.sock:/var/run/docker.sockBất kỳ bước nào trong pipeline đó — một dependency bị xâm phạm, một image layer độc hại, một build script — đều có quyền truy cập root không hạn chế vào host. Socket chính là bán kính thiệt hại.
2. Group docker tương đương với root
Thêm user vào group docker là cách chuẩn để cho phép user không phải root chạy container. Điều mà tài liệu không nhấn mạnh: thành viên của group docker có quyền root thực sự trên host thông qua socket. Đó là root với một bước gián tiếp.
3. Container đặc quyền rò rỉ vào kernel của host
Container chạy bởi Docker daemon chia sẻ kernel của host. Container với --privileged hoặc các capability cụ thể (CAP_SYS_ADMIN, CAP_NET_ADMIN) có thể tương tác trực tiếp với các kernel subsystem — mount filesystem, sửa đổi network interface, load kernel module. Daemon đang chạy với quyền root, nên mọi thứ nó spawn đều kế thừa ngữ cảnh tin cậy đó theo mặc định.
4. Daemon là single point of failure
Tất cả container đều là con của dockerd. Nếu daemon crash, restart, hoặc bị kill, tất cả container đang chạy đều bị ảnh hưởng. Trong các sự cố bảo mật — nếu kẻ tấn công kill daemon để xóa dấu vết — bạn mất khả năng theo dõi những gì đang chạy.
Cách Podman giải quyết vấn đề này
Container rootless
Podman chạy container với quyền của user đang gọi, không phải root. Khi bạn chạy:
podman run nginxContainer đó chạy dưới UID của bạn. Process tree thuộc sở hữu của user của bạn. Không có gì có quyền nâng cao liên quan.
Điều này hoạt động vì Podman sử dụng Linux user namespace. Bên trong container, các tiến trình có vẻ chạy với quyền root (UID 0). Bên ngoài, chúng được ánh xạ đến UID không đặc quyền của bạn. Kernel thực thi ranh giới này — root trong container không thể ảnh hưởng đến bất cứ điều gì bên ngoài user namespace.
Kết quả: một tiến trình container bị xâm phạm chỉ có thể làm những gì tài khoản user của bạn có thể làm trên host. Không có socket nào để thoát qua. Không có daemon nào để chiếm quyền.
Kiến trúc không có daemon
Podman không có daemon. Không có podmand. Mỗi lần gọi podman là một tiến trình trực tiếp — con của shell của bạn, chạy với quyền của bạn.
ps aux | grep podman# Bạn chỉ thấy các tiến trình bạn đã khởi động, thuộc sở hữu của user của bạnContainer là tiến trình con của lệnh podman đã khởi chạy chúng. Vòng đời của chúng gắn với Unix process semantics thông thường, không phải với một background service đặc quyền.
Điều này loại bỏ:
- Socket daemon như một vector tấn công
- Single point of failure
- Quyền root tiềm ẩn đang chờ giữa các lệnh
Không có vấn đề tương đương với group docker
Vì không có daemon đặc quyền, không có socket đặc quyền để cấp quyền truy cập. Cho một user khả năng chạy Podman có nghĩa là cho họ quyền truy cập binary podman — đã bị giới hạn trong UID và user namespace của chính họ. Bạn không cấp quyền root ngầm định.
So sánh chi tiết
| Vấn đề | Docker | Podman |
|---|---|---|
| Daemon chạy với quyền root | Có — luôn luôn | Không có daemon |
| Tiến trình container thuộc sở hữu của | root (dockerd) | user đang gọi |
| Bề mặt tấn công socket | /var/run/docker.sock | Không có |
Group docker/podman = root | Có | Không |
| Cô lập user namespace | Tùy chọn, không phải mặc định | Mặc định |
| Kernel capabilities cần thiết | Nhiều (qua daemon) | Tối thiểu (qua newuidmap) |
| Thoát container qua socket | Dễ dàng thực hiện | Không áp dụng |
Rootless không phải là giải pháp toàn diện
Kiến trúc của Podman loại bỏ vấn đề daemon-as-root. Nó không loại bỏ tất cả các vấn đề bảo mật container:
- Lỗ hổng kernel vẫn quan trọng. Container chia sẻ kernel của host. Một kernel exploit bỏ qua ranh giới user namespace hoàn toàn.
- Tin tưởng image vẫn là trách nhiệm của bạn. Container rootless vẫn chạy bất cứ thứ gì trong image. Pull image không đáng tin cậy là nguy hiểm bất kể runtime nào.
- Capability trong user namespace. Một container có
CAP_SYS_ADMINtrong namespace của nó vẫn có thể gây hại trong namespace đó. Hãy kiểm tra các capability grant của bạn. - Shared storage và bind mount. Container rootless với bind mount đến một đường dẫn host nhạy cảm vẫn có thể đọc hoặc ghi đường dẫn đó nếu permission cho phép.
Mô hình mối đe dọa mà Podman giải quyết cụ thể là: một container bị xâm phạm hoặc một bước CI leo thang lên root của host thông qua một runtime đặc quyền. Đây là vector tấn công thực và phổ biến. Loại bỏ nó có giá trị thực sự.
Ma sát khi chuyển đổi
Podman cung cấp CLI tương thích với Docker. Hầu hết lệnh docker hoạt động với podman mà không cần thay đổi:
# Hai lệnh này tương đươngdocker run -d -p 8080:80 nginxpodman run -d -p 8080:80 nginxNhững nơi chính gặp ma sát:
Bind port dưới 1024 — tiến trình rootless không thể bind privileged port mà không thay đổi sysctl:
sudo sysctl net.ipv4.ip_unprivileged_port_start=80Hoặc sử dụng port trên 1024 và đặt reverse proxy trước.
Quyền volume — vì UID container ánh xạ đến UID user của bạn qua user namespace, quyền sở hữu volume có thể hoạt động khác với Docker. Tùy chọn SELinux label :Z và flag --userns=keep-id xử lý hầu hết các trường hợp.
Systemd socket activation — Podman tích hợp với systemd natively qua podman generate systemd hoặc Quadlet. Điều này thay thế hành vi restart của Docker daemon bằng systemd unit file thích hợp.
Tóm tắt một dòng
Vấn đề bảo mật của Docker không phải là misconfiguration bạn có thể sửa — đó là hậu quả của việc chạy một privileged daemon mà mọi container kế thừa sự tin cậy từ đó. Podman loại bỏ daemon, chạy container dưới UID của chính bạn qua user namespace, và loại bỏ socket như một bề mặt tấn công. Cải thiện bảo mật mang tính cấu trúc, không phải bề ngoài.