Mục lục

Không có mục lục
Tham gia kênh Telegram của CloudFly để nhận thêm ưu đãi và không bỏ lỡ bất kỳ khuyến mãi nào từ CloudFly

Cách chuyển tiếp cổng qua Linux Gateway bằng Iptables

Ngày đăng: 6 tháng 11 năm 2023

Giới thiệu

NAT, hay địa chỉ mạng, là một thuật ngữ chung để chỉ các mangling packets nhằm chuyển hướng chúng đến một địa chỉ thay thế. Thông thường, điều này được sử dụng để cho phép lưu lượng truy cập vượt qua ranh giới mạng. Một máy chủ triển khai NAT thường có quyền truy cập vào hai mạng trở lên và được định cấu hình để định tuyến lưu lượng giữa chúng.

Port forwarding (Chuyển tiếp cổng) là quá trình chuyển tiếp các yêu cầu cho một cổng cụ thể tới máy chủ, mạng hoặc cổng khác. Vì quá trình này sửa đổi đích đến của packet đang truyền nên nó được coi là một loại hoạt động NAT.

Trong hướng dẫn này, chúng tôi sẽ trình bày cách sử dụng iptables để chuyển tiếp cổng tới máy chủ phía sau tường lửa bằng cách sử dụng kỹ thuật NAT. Điều này hữu ích nếu bạn đã định cấu hình một mạng riêng nhưng vẫn muốn cho phép một số lưu lượng truy cập nhất định bên trong thông qua một gateway machine được chỉ định.

Điều kiện tiên quyết

Để làm theo hướng dẫn này, bạn sẽ cần:

  • Thiết lập hai máy chủ Ubuntu 20.04 trong cùng một trung tâm dữ liệu có bật mạng riêng. Trên mỗi máy này, bạn sẽ cần thiết lập tài khoản non-root user với đặc quyền sudo. Bạn có thể tìm hiểu cách thực hiện việc này với bài viết của chúng tôi về hướng dẫn thiết lập máy chủ ban đầu Ubuntu 20.04. Có thể bỏ qua Bước 4 của hướng dẫn này vì chúng tôi sẽ thiết lập và định cấu hình tường lửa trong hướng dẫn này.
  • Trên một trong các máy chủ của bạn, hãy thiết lập mẫu tường lửa (firewall template) với iptables để nó có thể hoạt động như máy chủ tường lửa (firewall server) của bạn. Bạn có thể thực hiện việc này bằng cách làm theo hướng dẫn của chúng tôi về Cách triển khai Tường lửa cơ bản với Iptables trên Ubuntu 20.04. Sau khi hoàn tất, máy chủ tường lửa của bạn sẽ có sẵn những thứ sau để sử dụng:
    • Đã cài đặt iptables-persistent
    • Đã lưu bộ quy tắc mặc định vào /etc/iptables/rules.v4
    • Hiểu cách thêm hoặc điều chỉnh quy tắc bằng cách chỉnh sửa tệp quy tắc hoặc bằng cách sử dụng lệnh iptables

Máy chủ mà bạn thiết lập mẫu tường lửa trong đó sẽ đóng vai trò là tường lửa và bộ định tuyến cho mạng riêng của bạn. Với mục đích trình diễn, máy chủ thứ hai sẽ được cấu hình với một máy chủ web chỉ có thể truy cập được bằng giao diện riêng tư (Private Interface) của nó. Bạn sẽ định cấu hình firewall machine để chuyển tiếp các yêu cầu nhận được trên giao diện công cộng (Public Interface) của nó tới máy chủ web mà nó sẽ tiếp cận trên giao diện riêng tư.

Chi tiết máy chủ

Trước khi bắt đầu, bạn cần biết giao diện và địa chỉ nào đang được cả hai máy chủ của bạn sử dụng.

Tìm chi tiết mạng của bạn

Để biết thông tin chi tiết về hệ thống của riêng bạn, hãy bắt đầu bằng cách tìm các giao diện mạng của bạn. Bạn có thể tìm thấy các giao diện trên máy của mình và các địa chỉ được liên kết với chúng bằng cách chạy như sau:

  1. ip -4 addr show scope global
Sample Output
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 203.0.113.1/18 brd 45.55.191.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 10.0.0.1/16 brd 10.132.255.255 scope global eth1 valid_lft forever preferred_lft forever

Đầu ra được đánh dấu hiển thị hai giao diện (eth0eth1) và địa chỉ được gán cho mỗi giao diện (lần lượt là 203.0.113.110.0.0.1). Để tìm ra giao diện nào trong số này là giao diện công cộng của bạn, hãy chạy lệnh này:

  1. ip route show | grep default
Output
default via 111.111.111.111 dev eth0

Thông tin giao diện từ đầu ra này (eth0 trong ví dụ này) sẽ là giao diện được kết nối với cổng mặc định của bạn. Đây gần như chắc chắn là giao diện công cộng của bạn.

Tìm các giá trị này trên mỗi máy của bạn và sử dụng chúng để làm theo phần còn lại của hướng dẫn này.

Dữ liệu mẫu được sử dụng trong hướng dẫn này

Để làm cho mọi thứ rõ ràng hơn, chúng tôi sẽ sử dụng các phép gán địa chỉ và giao diện trống sau đây trong suốt hướng dẫn này. Vui lòng thay thế các giá trị của riêng bạn bằng những giá trị được liệt kê sau đây:

Chi tiết mạng máy chủ web:

  • Địa chỉ IP công cộng (Public IP Address): 203.0.113.1
  • Địa chỉ IP riêng (Private IP Address): 10.0.0.1
  • Giao diện công cộng (Public Interface): eth0
  • Giao diện riêng (Private Interface): eth1

Chi tiết mạng tường lửa:

  • Địa chỉ IP công cộng: 203.0.113.2
  • Địa chỉ IP riêng: 10.0.0.2
  • Giao diện công cộng: eth0
  • Giao diện riêng: eth1

Thiết lập máy chủ web

Bắt đầu kết nối với máy chủ web của bạn bằng cách đăng nhập bằng sudo user của bạn.

Cài đặt Nginx

Bước đầu tiên là cài đặt Nginx trên máy chủ lưu trữ web của bạn và khóa nó để nó chỉ nghe (listen) giao diện riêng tư của nó. Điều này sẽ đảm bảo rằng máy chủ web của bạn sẽ chỉ khả dụng nếu bạn thiết lập chuyển tiếp cổng chính xác.

Bắt đầu bằng cách cập nhật package cache cục bộ:

  1. sudo apt update

Tiếp theo sử dụng apt để tải và cài đặt phần mềm:

  1. sudo apt install nginx

Hạn chế Nginx vào mạng riêng

Sau khi Nginx được cài đặt, hãy mở tệp cấu hình khối máy chủ mặc định để đảm bảo rằng nó chỉ nghe giao diện riêng tư. Mở tệp bằng trình soạn thảo văn bản ưa thích của bạn. Ở đây chúng tôi sẽ sử dụng nano:

  1. sudo nano /etc/nginx/sites-enabled/default

Bên trong, tìm chỉ thị listen. Nó phải được liệt kê hai lần liên tiếp ở đầu cấu hình:

/etc/nginx/sites-enabled/default
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    . . .
}

Ở lệnh listen đầu tiên, hãy thêm địa chỉ IP riêng của máy chủ web của bạn và dấu hai chấm trước số 80 để yêu cầu Nginx chỉ nghe trên giao diện riêng tư. Chúng tôi chỉ trình bày tính năng chuyển tiếp IPv4 trong hướng dẫn này, vì vậy bạn có thể xóa lệnh listen thứ hai được định cấu hình cho IPv6.

Tiếp theo, sửa đổi các chỉ thị listen như sau:

/etc/nginx/sites-enabled/default
server {
    listen 10.0.0.1:80 default_server;

    . . .
}

Lưu và đóng tập tin khi bạn hoàn tất. Nếu bạn đã sử dụng nano, bạn có thể thực hiện việc này bằng cách nhấn CTRL + X, sau đó là YENTER.

Bây giờ hãy kiểm tra tệp để tìm lỗi cú pháp:

  1. sudo nginx -t
Output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

Nếu không có lỗi ở đầu ra, hãy khởi động lại Nginx để kích hoạt cấu hình mới:

  1. sudo systemctl restart nginx

Xác minh hạn chế mạng

Tại thời điểm này, việc xác minh mức độ truy cập bạn có vào máy chủ web của mình là rất hữu ích.

Từ máy chủ tường lửa của bạn, hãy thử truy cập máy chủ web của bạn từ giao diện riêng tư bằng lệnh sau:

  1. curl --connect-timeout 5 10.0.0.1

Nếu thành công, kết quả đầu ra của bạn sẽ dẫn đến thông báo sau:

Output
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .

Nếu bạn cố gắng sử dụng giao diện công cộng, bạn sẽ nhận được thông báo cho biết nó không thể kết nối:

  1. curl --connect-timeout 5 203.0.113.1
Output
curl: (7) Failed to connect to 203.0.113.1 port 80: Connection refused

Những kết quả này được mong đợi.

Cấu hình tường lửa để chuyển tiếp cổng 80

Bây giờ bạn sẽ tiến hành triển khai chuyển tiếp cổng trên firewall machine của mình.

Kích hoạt chuyển tiếp trong Kernel

Điều đầu tiên bạn cần làm là kích hoạt chuyển tiếp lưu lượng ở cấp kernel. Theo mặc định, hầu hết các hệ thống đều tắt tính năng chuyển tiếp.

Để bật chuyển tiếp cổng chỉ cho session này, hãy chạy như sau:

  1. echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Output
1

Để bật chuyển tiếp cổng vĩnh viễn, bạn sẽ phải chỉnh sửa tệp /etc/sysctl.conf. Bạn có thể làm điều này bằng cách mở tệp với đặc quyền sudo:

  1. sudo nano /etc/sysctl.conf

Trong tệp, tìm và bỏ ghi chú dòng có nội dung như sau:

/etc/sysctl.conf
net.ipv4.ip_forward=1

Lưu và đóng tập tin khi bạn hoàn tất.

Sau đó áp dụng các cài đặt trong tập tin này. Đầu tiên chạy lệnh sau:

  1. sudo sysctl -p
Output
net.ipv4.ip_forward = 1

Sau đó chạy lệnh tương tự, nhưng thay thế cờ -p bằng --system:

  1. sudo sysctl --system
Output
. . . * Applying /usr/lib/sysctl.d/50-pid-max.conf ... kernel.pid_max = 4194304 * Applying /etc/sysctl.d/99-cloudimg-ipv6.conf ... net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.default.use_tempaddr = 0 * Applying /etc/sysctl.d/99-sysctl.conf ... net.ipv4.ip_forward = 1 * Applying /usr/lib/sysctl.d/protect-links.conf ... fs.protected_fifos = 1 fs.protected_hardlinks = 1 fs.protected_regular = 2 fs.protected_symlinks = 1 * Applying /etc/sysctl.conf ... net.ipv4.ip_forward = 1

Thêm quy tắc chuyển tiếp vào tường lửa cơ bản

Tiếp theo, bạn sẽ định cấu hình tường lửa để lưu lượng truy cập vào giao diện công cộng (eth0) trên cổng 80 sẽ được chuyển tiếp đến giao diện riêng tư (eth1) của bạn.

Tường lửa mà bạn đã định cấu hình trong hướng dẫn Cách triển khai mẫu tường lửa cơ bản với Iptables trên Ubuntu 20.04 có chuỗi FORWARD được đặt thành DROP lưu lượng truy cập theo mặc định. Bạn cần thêm các quy tắc cho phép bạn chuyển tiếp kết nối đến máy chủ web của mình. Vì lý do bảo mật, bạn nên khóa mục này thật chặt để chỉ cho phép những kết nối bạn muốn chuyển tiếp.

Trong chuỗi FORWARD, bạn sẽ chấp nhận các kết nối mới dành cho cổng 80 đến từ giao diện công cộng và chuyển sang giao diện riêng tư của bạn. Các kết nối mới được xác định bởi tiện ích mở rộng conntrack và sẽ được biểu thị cụ thể bằng gói TCP SYN như sau:

  1. sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT

Điều này sẽ cho phép packet đầu tiên, nhằm thiết lập kết nối, đi qua tường lửa. Bạn cũng cần phải cho phép mọi lưu lượng truy cập tiếp theo theo cả hai hướng bắt nguồn từ kết nối đó. Để cho phép lưu lượng ESTABLISHEDRELATED giữa giao diện công cộng và riêng tư của bạn, hãy chạy các lệnh sau. Đầu tiên cho giao diện công cộng của bạn:

  1. sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Sau đó, đối với giao diện riêng tư của bạn:

  1. sudo iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Kiểm tra kỹ xem chính sách của bạn trên chuỗi FORWARD có được đặt thành DROP không:

  1. sudo iptables -P FORWARD DROP

Tại thời điểm này, bạn đã cho phép một số lưu lượng truy cập nhất định giữa giao diện công cộng và riêng tư đi qua tường lửa của mình. Tuy nhiên, bạn chưa định cấu hình các quy tắc thực sự sẽ cho iptables biết cách dịch và điều hướng lưu lượng truy cập.

Thêm quy tắc NAT vào gói trực tiếp một cách chính xác

Tiếp theo, bạn sẽ thêm các quy tắc sẽ cho iptables biết cách định tuyến lưu lượng truy cập của bạn. Bạn cần thực hiện hai thao tác riêng biệt để iptables thay đổi chính xác các packet để máy khách có thể giao tiếp với máy chủ web.

Hoạt động đầu tiên, được gọi là DNAT, sẽ diễn ra trong chuỗi PREROUTING của bảng nat. DNAT là một hoạt động thay đổi địa chỉ đích của packet để cho phép nó định tuyến chính xác khi nó đi qua giữa các mạng. Các máy khách trên mạng công cộng sẽ kết nối với máy chủ tường lửa của bạn và sẽ không biết về cấu trúc liên kết mạng riêng của bạn. Do đó, bạn cần thay đổi địa chỉ đích của từng packet để khi gửi đi trên mạng riêng của bạn, nó sẽ biết cách truy cập chính xác vào máy chủ web của bạn.

Vì bạn chỉ định cấu hình chuyển tiếp cổng và không thực hiện NAT trên mọi gói truy cập tường lửa của mình, nên bạn sẽ cần match cổng 80 theo quy tắc của mình. Bạn sẽ match các packet nhắm đến cổng 80 với địa chỉ IP riêng của máy chủ web của bạn (10.0.0.1 trong ví dụ sau):

  1. sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1

Quá trình này xử lý một nửa toàn cảnh. Packet sẽ được định tuyến chính xác đến máy chủ web của bạn. Tuy nhiên, lúc này packet vẫn sẽ có địa chỉ gốc của máy khách làm địa chỉ nguồn. Máy chủ sẽ cố gắng gửi trả lời trực tiếp đến địa chỉ đó, điều này sẽ khiến việc thiết lập kết nối TCP hợp pháp không thể thực hiện được.

Để định cấu hình định tuyến phù hợp, bạn cũng cần sửa đổi địa chỉ nguồn của packet khi nó rời tường lửa trên đường đến máy chủ web. Bạn cần sửa đổi địa chỉ nguồn thành địa chỉ IP riêng của máy chủ tường lửa (10.0.0.2 trong ví dụ sau). Câu trả lời sau đó sẽ được gửi trở lại tường lửa, sau đó tường lửa có thể chuyển tiếp nó trở lại máy khách như mong đợi.

Để bật chức năng này, hãy thêm quy tắc vào chuỗi POSTROUTING của bảng nat, quy tắc này được đánh giá ngay trước khi các packet được gửi đi trên mạng. Bạn sẽ match các packet dành cho máy chủ web của mình theo địa chỉ IP và cổng:

  1. sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 10.0.0.1 -j SNAT --to-source 10.0.0.2

Khi quy tắc này được áp dụng, máy chủ web của bạn sẽ có thể truy cập được bằng cách trỏ trình duyệt web của bạn vào địa chỉ công khai của máy tường lửa:

  1. curl 203.0.113.2
Output
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . .

Thiết lập chuyển tiếp cổng của bạn hiện đã hoàn tất.

Điều chỉnh bộ quy tắc vĩnh viễn

Bây giờ bạn đã thiết lập chuyển tiếp cổng, bạn có thể lưu cổng này vào bộ quy tắc vĩnh viễn của mình.

Nếu bạn không quan tâm đến việc mất các nhận xét trong bộ quy tắc hiện tại của mình, hãy sử dụng lệnh netfilter-persistent để sử dụng dịch vụ iptables và lưu quy tắc của bạn:

  1. sudo service netfilter-persistent save
Output
* Saving netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save [ OK ]

Nếu bạn muốn giữ lại nhận xét trong tệp của mình, hãy mở nó lên và chỉnh sửa thủ công:

  1. sudo nano /etc/iptables/rules.v4

Bạn sẽ cần điều chỉnh cấu hình trong bảng filter cho các quy tắc chuỗi FORWARD đã được thêm vào. Bạn cũng sẽ cần điều chỉnh phần cấu hình bảng nat để có thể thêm các quy tắc PREROUTINGPOSTROUTING của mình. Nội dung sẽ giống như sau:

/etc/iptables/rules.v4
*filter
# Allow all outgoing, but drop incoming and forwarding packets by default
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Custom per-protocol chains
:UDP - [0:0]
:TCP - [0:0]
:ICMP - [0:0]

# Acceptable UDP traffic

# Acceptable TCP traffic
-A TCP -p tcp --dport 22 -j ACCEPT

# Acceptable ICMP traffic

# Boilerplate acceptance policy
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT

# Drop invalid packets
-A INPUT -m conntrack --ctstate INVALID -j DROP

# Pass traffic to protocol-specific chains
## Only allow new connections (established and related should already be handled)
## For TCP, additionally only allow new SYN packets since that is the only valid
## method for establishing a new TCP connection
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP

# Reject anything that's fallen through to this point
## Try to be protocol-specific w/ rejection message
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable

# Rules to forward port 80 to our web server

# Web server network details:

# * Public IP Address: 203.0.113.1
# * Private IP Address: 10.0.0.1
# * Public Interface: eth0
# * Private Interface: eth1
# 
# Firewall network details:
# 
# * Public IP Address: 203.0.113.2
# * Private IP Address: 10.0.0.2
# * Public Interface: eth0
# * Private Interface: eth1
-A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# End of Forward filtering rules

# Commit the changes

COMMIT

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Rules to translate requests for port 80 of the public interface
# so that we can forward correctly to the web server using the
# private interface.

# Web server network details:

# * Public IP Address: 203.0.113.1
# * Private IP Address: 10.0.0.1
# * Public Interface: eth0
# * Private Interface: eth1
# 
# Firewall network details:
# 
# * Public IP Address: 203.0.113.2
# * Private IP Address: 10.0.0.2
# * Public Interface: eth0
# * Private Interface: eth1
-A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
-A POSTROUTING -d 10.0.0.1 -o eth1 -p tcp --dport 80 -j SNAT --to-source 10.0.0.2
# End of NAT translations for web server traffic
COMMIT

*security
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT

*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

Lưu và đóng tệp sau khi bạn đã thêm nội dung và điều chỉnh các giá trị để phản ánh môi trường mạng của riêng bạn.

Tiếp theo, kiểm tra cú pháp của tệp quy tắc của bạn:

  1. sudo sh -c "iptables-restore -t < /etc/iptables/rules.v4"

Nếu không phát hiện thấy lỗi, hãy tải bộ quy tắc:

  1. sudo service netfilter-persistent reload
Output
* Loading netfilter rules... run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start [ OK ]

Bây giờ hãy kiểm tra xem máy chủ web của bạn vẫn có thể truy cập được thông qua địa chỉ IP công cộng của tường lửa hay không:

  1. curl 203.0.113.2

Điều này sẽ hoạt động giống như trước đây.

Kết luận

Bây giờ, bạn đã quen với việc chuyển tiếp cổng trên máy chủ Linux có iptables. Quá trình này bao gồm việc cho phép chuyển tiếp ở cấp kernel, thiết lập quyền truy cập để cho phép chuyển tiếp lưu lượng của cổng cụ thể giữa hai giao diện trên hệ thống tường lửa, và định cấu hình quy tắc NAT để các packet có thể được định tuyến chính xác. Điều này có vẻ giống như một quá trình khó sử dụng, nhưng nó cũng thể hiện tính linh hoạt của packet filtering framework netfilter và tường lửa iptables. Điều này có thể được sử dụng để ngụy trang cấu trúc liên kết mạng riêng của bạn trong khi cho phép lưu lượng dịch vụ truyền tự do qua gateway firewall machine của bạn.

Tham gia kênh Telegram của CloudFly để nhận thêm ưu đãi và không bỏ lỡ bất kỳ khuyến mãi nào từ CloudFly
Chia sẻ

0 câu trả lời