TLDR;

  • UFW không chặn được các gói tin từ bên trong mạng nội bộ khi mapping port với Docker container (thường dùng trong tham số của docker run -p {internal-ip}:{expose-port}:{container-port}).
  • Phương án 1: Sử dụng firewall từ Cloud Provider.
  • Phương án 2: Sử dụng iptables để chặn các gói tin từ bên trong mạng nội bộ.
# Block all traffics 
sudo iptables -I DOCKER-USER -i {network_interface} -j DROP

# Keep connection states ESTABLISHED, RELATED
sudo iptables -I DOCKER-USER -i eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Each allowing rule will be added
sudo iptables -I DOCKER-USER -i {network_interface} -m conntrack -p tcp --ctstate NEW --ctorigsrc {source_ip} --ctorigdstport {destination_port} -j ACCEPT

Kịch bản

Hạ tầng

Hạ tầng

Máy chủ Network Interface IP Address Mô tả
A eth0 x.x.x.1 Cổng mạng ngoại bộ
A eth1 10.0.0.1 Cổng mạng nội bộ
B eth0 x.x.x.2 Cổng mạng ngoại bộ
B eth1 10.0.0.2 Cổng mạng nội bộ
C eth1 10.0.0.3 Cổng mạng nội bộ

Dịch vụ

Các dịch vụ đang chạy trong docker container, các cổng (port) được mapping như bảng sau.

Máy chủ Dịch vụ Bind IP Port
A Web Server 0.0.0.0 80
B MySQL 1 10.0.0.2 3306
B MySQL 2 10.0.0.2 3307

Mục tiêu

  • Chặn toàn bộ các gói tin từ Internet vào máy chủ B.
  • Chặn toàn bộ các gói tin từ bên trong mạng nội bộ vào máy chủ B.
  • Mở cho duy nhất máy chủ C được phép truy cập vào máy chủ B qua cổng 3307
  • Mở cho duy nhất máy chủ A được phép truy cập vào máy chủ B qua cổng 3306

Thực thi

Lưu ý: Kịch bản này chứa lỗi, không sử dụng trong môi trường thực tế.

  • Bind dịch vụ MySQL 1 và MySQL 2 trên máy chủ B với cổng 3306 và 3307 trên cổng mạng nội bộ.
# Môi trường: Máy chủ B
docker run --name mysql-1 -d -p 10.0.0.2:3306:3306 mysql:5.7 
docker run --name mysql-2 -d -p 10.0.0.2:3307:3306 mysql:5.7
  • Dùng ufw làm firewall trên máy chủ B.
# Môi trường: Máy chủ B

# Chặn toàn kết nối vào
ufw default deny incoming

# Mở cổng 3306 cho máy chủ A
ufw allow from 10.0.0.1/32 to any port 3306

# Mở cổng 3307 cho máy chủ C
ufw allow from 10.0.0.3/32 to any port 3307

Vấn đề

  • UFW không chặn được các gói tin 1 khi mapping port với Docker container (thường dùng trong tham số của docker run -p {internal-ip}:{expose-port}:{container-port}).
  • Một số bài viết 2 tìm cách chèn thêm các rules vào chain DOCKER-USER của iptables nhưng chỉ hiệu quả để chặn các gói tin đến từ bên ngoài, không chặn được các gói tin từ bên trong mạng nội bộ như kịch bản đề ra.

Phương án

1. Sử dụng firewall từ Cloud Provider

  • Đối với các dịch vụ cloud chuyên nghiệp như AWS, GCP, Azure, các máy chủ sẽ được quản lý bởi firewall của cloud provider. Với sự hỗ trợ của hệ thống mạng ảo VPC, họ tích hợp firewall tầng mạng thay vì sử dụng các firewall tầng phần mềm 3 4 5. Vì vậy, việc chặn sẽ hiệu quả và không ảnh hưởng vì các phần mềm xung đột với nhau.

2. Sử dụng iptables trên từng máy chủ

  • Dùng chain DOCKER-USER để quản lý các rule của Docker thay vì các chain mặc định. Mục đích của việc này là để tách biệt các rule định nghĩa cho Docker với các rule khác 1.
  • Các rules viết phải sử dụng extension conntrack6 vì sau khi gói tin vào DOCKER-USER đã qua bộ lọc DNAT 1, địa chỉ và cổng đã có thể bị thay đổi.
  • Lệnh thêm rules vào chain DOCKER-USER trên máy chủ B:

Lưu ý: iptables có thể làm mất kết nối điều khiển nếu bạn cấu hình sai. Hãy chắc chắn có phương án truy cập thay thế trong trường hợp mất kết nối.

# Môi trường: Máy chủ B
# Chặn toàn bộ gói tin từ Internet 
sudo iptables -I DOCKER-USER -i eth0 -j DROP
sudo iptables -I DOCKER-USER -i eth0 -j LOG --log-prefix "Dropped packet: " --log-level 4

# Chặn toàn bộ gói tin nội bộ
sudo iptables -I DOCKER-USER -i eth1 -j DROP
sudo iptables -I DOCKER-USER -i eth1 -j LOG --log-prefix "Dropped packet: " --log-level 4

# Giữ các kết nối ở trạng thái ESTABLISHED, RELATED
# Rule này sẽ giúp bạn giải quyết tình trạng kết nối ra ngoài đã thiết lập nhưng lại bị chặn.
sudo iptables -I DOCKER-USER -i eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Mở cho duy nhất máy chủ A truy cập cổng 3306 qua mạng nội bộ
sudo iptables -I DOCKER-USER -i eth1 -m conntrack -p tcp --ctstate NEW --ctorigsrc 10.0.0.1 --ctorigdstport 3306 -j ACCEPT

# Mở cho duy nhất máy chủ C truy cập cổng 3307 qua mạng nội bộ
sudo iptables -I DOCKER-USER -i eth1 -m conntrack -p tcp --ctstate NEW --ctorigsrc 10.0.0.3 --ctorigdstport 3307 -j ACCEPT