Giới thiệu
Triển khai tường lửa là một bước quan trọng trong nhằm bảo mật máy chủ của bạn. Một phần lớn trong số đó là quyết định các quy tắc và chính sách riêng lẻ sẽ thực thi các giới hạn lưu lượng truy cập vào mạng của bạn. Tường lửa như iptables
cũng cho phép bạn nói về khuôn khổ cấu trúc mà các quy tắc của bạn được áp dụng.
Trong hướng dẫn này, bạn sẽ học cách xây dựng tường lửa có thể là cơ sở cho các bộ quy tắc phức tạp hơn. Tường lửa này sẽ tập trung chủ yếu vào việc cung cấp các giá trị mặc định hợp lý và thiết lập một khuôn khổ khuyến khích khả năng mở rộng.
Điều kiện
Để hoàn thành hướng dẫn này, bạn sẽ cần quyền truy cập vào máy chủ Ubuntu 20.04 sử dụng non-root user có đặc quyền sudo
.
Ngoài ra, chúng tôi khuyên bạn nên xem lại các chính sách tường lửa mà bạn muốn triển khai. Bạn có thể làm theo hướng dẫn này để hiểu rõ hơn về những điều cần xem xét.
Cài đặt tường lửa Persistent
Bắt đầu bằng cách cập nhật bộ nhớ đệm cục bộ:
Bây giờ tiến hành cài đặt iptables-persistent
. Điều này cho phép bạn lưu các bộ quy tắc của mình và tự động áp dụng chúng khi khởi động:
Trong quá trình cài đặt, bạn sẽ được hỏi có muốn lưu các quy tắc hiện tại của mình hay không, hãy chọn <YES>. Làm ơn hãy nhớ rằng bạn sẽ chạy lệnh netfilter-persistent
để thực thi dịch vụ tường lửa liên tục iptables
. Tiếp theo, bạn sẽ chỉnh sửa các tệp quy tắc đã tạo.
Lưu ý về IPv6 trong Hướng dẫn này
Trước khi bắt đầu, chúng ta sẽ thảo luận ngắn gọn về IPv4 và IPv6. Lệnh iptables
chỉ xử lý lưu lượng IPv4. Đối với lưu lượng IPv6, một công cụ đồng hành riêng biệt được gọi là ip6tables
được sử dụng. Các quy tắc được lưu trữ trong các bảng và chuỗi riêng biệt. Đối với lệnh netfilter-persistent
, các quy tắc IPv4 được ghi và đọc từ /etc/iptables/rules.v4
và các quy tắc IPv6 được lưu trữ trong /etc/iptables/rules.v6
.
Hướng dẫn này giả định rằng bạn không tích cực sử dụng IPv6 trên máy chủ của mình. Nếu các dịch vụ của bạn không tận dụng IPv6, thì việc chặn hoàn toàn quyền truy cập sẽ an toàn hơn, như sẽ được trình bày trong hướng dẫn này.
Với mục đích thiết lập và chạy nhanh nhất có thể, chúng tôi sẽ hướng dẫn bạn cách chỉnh sửa trực tiếp tệp quy tắc cũng như sao chép và dán chính sách tường lửa đã hoàn thành. Sau đó, chúng tôi sẽ giải thích chiến lược chung và cách thực hiện các quy tắc này bằng lệnh iptables thay vì sửa đổi tệp.
Thực hiện chính sách tường lửa cơ bản (Cách nhanh chóng)
Để triển khai khuôn khổ và chính sách tường lửa, bạn sẽ chỉnh sửa các tệp/etc/iptables/rules.v4
và /etc/iptables/rules.v6
. Mở tệp rules.v4
trong 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
:
Bên trong, tệp sẽ chứa các nội dung sau:
Xóa những nội dung này và thay thế chúng bằng những nội dung sau:
Lưu và đóng tập tin. Nếu đang 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 đó nhấn Y
và ENTER
.
Bạn có thể kiểm tra tệp để tìm lỗi cú pháp bằng cách chạy lệnh sau. Đảm bảo sửa lỗi cú pháp nếu bạn nhận được bất kỳ lỗi nào:
Tiếp theo, mở tệp /etc/iptables/rules.v6
để sửa đổi các quy tắc IPv6:
Tập tin này sẽ có các nội dung sau:
Bạn có thể chặn tất cả lưu lượng IPv6 bằng cách thay thế nội dung của tệp bằng cấu hình sau:
Lưu và đóng tập tin.
Để kiểm tra lỗi cú pháp cho tệp này, hãy sử dụng lệnh ip6tables-restore
với tùy chọn -t
:
Khi cả hai tệp quy tắc đều báo cáo không có lỗi cú pháp, bạn có thể áp dụng các quy tắc bạn đã đặt bằng cách chạy:
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 ]
Điều này sẽ ngay lập tức triển khai chính sách được nêu trong tệp của bạn. Bạn có thể xác minh điều này bằng cách liệt kê các quy tắc iptables
hiện đang được sử dụng. Lần đầu tiên kiểm tra IPv4:
Output-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-N ICMP
-N TCP
-N UDP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
-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
-A TCP -p tcp -m tcp --dport 22 -j ACCEPT
Sau đó, hãy kiểm tra các quy tắc IPv6 hiện tại:
Output-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
Các quy tắc tường lửa này sẽ được áp dụng lại mỗi lần khởi động. Hãy kiểm tra để đảm bảo rằng bạn vẫn có thể đăng nhập và tất cả các quyền truy cập khác đã bị chặn.
Giải thích về Chiến lược Tường lửa chung của chúng tôi
Trong tường lửa cơ bản được xây dựng với các quy tắc từ phần trước, chúng tôi đã tạo một khung mở rộng có thể được điều chỉnh để thêm hoặc xóa các quy tắc. Đối với lưu lượng IPv4, chúng tôi chủ yếu quan tâm đến chuỗi INPUT
trong bảng filter
. Chuỗi này sẽ xử lý tất cả các gói dành cho máy chủ của chúng tôi. Chúng tôi cũng đã cho phép tất cả lưu lượng gửi đi và từ chối tất cả chuyển tiếp gói, điều này sẽ chỉ phù hợp nếu máy chủ này hoạt động như một bộ định tuyến cho các máy chủ khác. Chúng tôi chấp nhận các gói trong tất cả các bảng khác vì chỉ muốn lọc các gói trong hướng dẫn này.
Nói chung, các quy tắc của chúng tôi thiết lập tường lửa sẽ từ chối lưu lượng đến theo mặc định. Sau đó, chúng tôi tạo ngoại lệ cho các dịch vụ và loại lưu lượng mà chúng tôi muốn loại trừ khỏi chính sách này.
Trong chuỗi INPUT
chính, chúng tôi đã thêm một số quy tắc chung cho lưu lượng truy cập mà chúng tôi tin rằng sẽ luôn được xử lý theo cùng một cách. Ví dụ: chúng tôi luôn muốn từ chối các gói được coi là "không hợp lệ" (invalid) và sẽ luôn muốn cho phép lưu lượng truy cập trên giao diện loopback cục bộ và dữ liệu được liên kết với kết nối đã thiết lập.
Sau đó, chúng tôi đối sánh lưu lượng truy cập dựa trên giao thức mà nó đang sử dụng và trộn nó vào một chuỗi giao thức cụ thể. Các chuỗi giao thức cụ thể này có nghĩa là giữ các quy tắc phù hợp và cho phép lưu lượng truy cập cho các dịch vụ cụ thể. Trong ví dụ này, dịch vụ duy nhất mà chúng tôi cho phép là SSH trong chuỗi TCP
của chúng tôi. Nếu chúng tôi cung cấp một dịch vụ khác, chẳng hạn như máy chủ HTTP (S), chúng tôi cũng có thể thêm các ngoại lệ ở đây. Các chuỗi này sẽ là trọng tâm của hầu hết các tùy chỉnh của bạn.
Bất kỳ lưu lượng nào không khớp với quy tắc chung hoặc quy tắc dịch vụ trong chuỗi giao thức cụ thể sẽ được xử lý bởi một số quy tắc cuối cùng trong chuỗi INPUT
. Chúng tôi đã đặt chính sách mặc định thành DROP
cho tường lửa của mình, chính sách này sẽ từ chối các gói nằm trong quy tắc của chúng tôi. Tuy nhiên, các quy tắc ở cuối chuỗi INPUT từ chối các gói và gửi thông báo đến máy khách, mô phỏng cách máy chủ sẽ phản hồi nếu không có dịch vụ nào chạy trên cổng đó.
Đối với lưu lượng IPv6, chúng tôi loại bỏ tất cả lưu lượng truy cập. Máy chủ của chúng tôi không sử dụng giao thức này, vì vậy an toàn nhất là không tham gia vào lưu lượng truy cập.
Triển khai tường lửa của bạn bằng lệnh iptables
Bây giờ bạn đã hiểu ý tưởng chung đằng sau chính sách mà chúng tôi đã xây dựng, chúng tôi sẽ thảo luận về cách bạn có thể tạo các quy tắc đó bằng cách sử dụng lệnh iptables
. Chúng tôi sẽ kết thúc với các quy tắc tương tự mà chúng tôi đã chỉ định ở trên, nhưng chúng tôi sẽ tạo các chính sách của mình bằng cách thêm các quy tắc lặp đi lặp lại. Bởi vì iptables
áp dụng từng quy tắc ngay lập tức, thứ tự quy tắc là rất quan trọng (ví dụ: chúng tôi để nguyên quy tắc từ chối gói cho đến cuối).
Đặt lại tường lửa của bạn
Bắt đầu bằng cách đặt lại các quy tắc tường lửa của bạn, để bạn có thể xem lại cách các chính sách có thể được xây dựng từ dòng lệnh. Xóa tất cả các quy tắc của bạn bằng cách chạy như sau:
Bây giờ, hãy xác minh rằng các quy tắc của bạn đã được đặt lại:
Bạn sẽ có kết quả hiển thị các quy tắc trong bảng filter
đã biến mất và chính sách mặc định được đặt thành ACCEPT
trên tất cả các chuỗi:
Output-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
Tạo chuỗi dành riêng cho giao thức
Tiếp theo, bạn sẽ tạo tất cả các chuỗi theo giao thức cụ thể của mình. Những điều này sẽ được sử dụng để giữ các quy tắc tạo ngoại lệ cho chính sách từ chối của bạn đối với các dịch vụ bạn muốn tiết lộ. Bạn sẽ tạo một cái cho lưu lượng UDP
:
Sau đó, một cái khác cho TCP
:
Và một cái nữa cho ICMP
:
Tiếp theo, thêm ngoại lệ cho lưu lượng SSH. SSH sử dụng TCP, vì vậy bạn sẽ thêm quy tắc để chấp nhận lưu lượng TCP
dành cho cổng 22
vào chuỗi TCP:
Nếu bạn muốn thêm các dịch vụ TCP bổ sung, bạn có thể thực hiện điều đó ngay bây giờ bằng cách lặp lại lệnh với số cổng được thay thế.
Tạo các Quy tắc Chấp nhận và Từ chối Mục đích Chung
Trong chuỗi INPUT
, nơi tất cả lưu lượng đến bắt đầu lọc, chúng ta cần thêm các quy tắc mục đích chung của mình. Đây là một số quy tắc thông thường thiết lập đường cơ sở cho tường lửa của chúng ta bằng cách chấp nhận lưu lượng truy cập có rủi ro thấp (lưu lượng truy cập cục bộ và lưu lượng liên kết với các kết nối mà chúng ta đã kiểm tra) và loại bỏ lưu lượng truy cập rõ ràng là không hữu ích (các gói không hợp lệ).
Trước tiên, hãy tạo một ngoại lệ để chấp nhận tất cả lưu lượng là một phần của kết nối đã thiết lập hoặc có liên quan đến kết nối đã thiết lập:
Quy tắc này sử dụng tiện ích mở rộng conntrack
, cung cấp tính năng theo dõi nội bộ, để iptables
có ngữ cảnh cần thiết đánh giá các gói như một phần của các kết nối lớn hơn, thay vì dưới dạng một luồng các gói rời rạc không liên quan. TCP là một giao thức dựa trên kết nối, vì vậy một kết nối đã thiết lập được xác định khá rõ ràng. Đối với UDP và các giao thức không kết nối khác, các kết nối đã thiết lập đề cập đến lưu lượng đã thấy phản hồi (nguồn của gói ban đầu sẽ là đích của gói phản hồi và ngược lại). Một kết nối có liên quan đề cập đến một kết nối mới đã được khởi tạo cùng với một kết nối hiện có. Ví dụ đơn giản ở đây là kết nối truyền dữ liệu FTP, kết nối này sẽ liên quan đến kết nối điều khiển FTP đã được thiết lập.
Bạn cũng sẽ muốn cho phép tất cả lưu lượng truy cập bắt nguồn trên giao diện lặp lại cục bộ. Đây là lưu lượng do máy chủ tạo ra và dành cho máy chủ. Nó được các dịch vụ trên máy chủ sử dụng để giao tiếp với nhau:
Cuối cùng, từ chối tất cả các gói không hợp lệ. Các gói có thể không hợp lệ vì một số lý do. Chúng có thể đề cập đến các kết nối không tồn tại, chúng có thể dành cho các giao diện, địa chỉ hoặc cổng không tồn tại hoặc chúng có thể không đúng định dạng. Trong mọi trường hợp, bạn sẽ loại bỏ tất cả các gói không hợp lệ vì không có cách thích hợp để xử lý chúng và vì chúng có thể đại diện cho hoạt động độc hại:
Tạo Quy tắc Chuyển sang Chuỗi dành riêng cho Giao thức
Cho đến giờ, chúng ta đã tạo một số quy tắc chung trong chuỗi INPUT
và một số quy tắc cho các dịch vụ cụ thể được chấp nhận trong chuỗi theo giao thức cụ thể của chúng ta. Tuy nhiên, hiện tại, lưu lượng truy cập vào chuỗi INPUT
và không có cách nào để tiếp cận chuỗi giao thức cụ thể.
Bây giờ bạn cần hướng lưu lượng truy cập trong chuỗi INPUT
vào các chuỗi giao thức cụ thể thích hợp. Bạn có thể đối sánh loại giao thức để gửi nó đến đúng chuỗi. Ngoài ra, hãy đảm bảo rằng gói đại diện cho một kết nối mới (bất kỳ kết nối nào được thiết lập hoặc có liên quan nên đã được xử lý trước đó). Bắt đầu với lưu lượng UDP
:
Tiếp theo, chạy lệnh sau cho lưu lượng TCP
. Xin lưu ý rằng với các gói TCP, bạn sẽ thêm yêu cầu bổ sung rằng gói đó là gói SYN, đây là loại hợp lệ duy nhất để bắt đầu kết nối TCP:
Sau đó, chạy như sau cho lưu lượng ICMP
:
Từ chối tất cả lưu lượng truy cập còn lại
Nếu một gói được chuyển đến một chuỗi giao thức cụ thể không khớp với bất kỳ quy tắc nào bên trong, thì quyền kiểm soát sẽ được chuyển trở lại chuỗi INPUT
. Bất kỳ thứ gì đạt đến điểm này sẽ không được phép bởi tường lửa của bạn.
Bạn sẽ từ chối lưu lượng truy cập bằng cách sử dụng mục tiêu REJECT
, mục tiêu này sẽ gửi thông báo phản hồi đến khách hàng. Điều này cho phép bạn chỉ định thông báo gửi đi để bạn có thể bắt chước phản hồi sẽ được đưa ra nếu khách hàng cố gắng gửi các gói đến một cổng đã đóng thông thường. Phản hồi phụ thuộc vào giao thức được sử dụng bởi máy khách.
Cố gắng truy cập một cổng UDP
đã đóng sẽ dẫn đến một thông báo ICMP
cho biết “cổng không thể truy cập được” (port unreachable). Bạn có thể bắt chước điều này bằng cách chạy như sau:
Cố gắng thiết lập kết nối TCP
trên một cổng đã đóng dẫn đến phản hồi TCP RST:
Đối với tất cả các gói khác, bạn có thể gửi thông báo ICMP
“giao thức không thể truy cập” (port unreachable) để cho biết rằng máy chủ không phản hồi với các gói thuộc loại đó:
Điều chỉnh chính sách mặc định
Ba quy tắc cuối cùng bạn đã thêm sẽ xử lý tất cả lưu lượng còn lại trong chuỗi INPUT
. Tuy nhiên, bạn nên đặt chính sách mặc định thành DROP
để đề phòng, như sau:
Bạn cũng nên đặt chính sách này trong chuỗi FORWARD
nếu máy chủ này không được thiết lập cấu hình làm bộ định tuyến cho các máy khác:
Cảnh báo: Với chính sách của bạn được đặt thành DROP
, nếu bạn xóa iptables
của mình bằng sudo iptables -F
, kết nối SSH hiện tại của bạn sẽ bị ngắt! Xóa bằng sudo netfilter-persistent flush
là cách tốt hơn để xóa các quy tắc vì nó cũng sẽ đặt lại chính sách mặc định.
Để phù hợp với chính sách loại bỏ tất cả lưu lượng truy cập IPv6 của bạn, bạn có thể sử dụng các lệnh ip6tables
sau, bắt đầu bằng INPUT
:
Sau đó chạy phần sau cho FORWARD
:
Kết thúc bằng cách thiết lập chính sách cho OUTPUT
:
Điều này sẽ sao chép các quy tắc của bạn khá chặt chẽ.
Lưu quy tắc iptables
Tại thời điểm này, bạn nên kiểm tra các quy tắc tường lửa của mình và đảm bảo rằng chúng chặn lưu lượng truy cập mà bạn muốn giữ lại trong khi không cản trở việc truy cập bình thường của bạn. Khi bạn hài lòng rằng các quy tắc của mình đang hoạt động chính xác, bạn có thể lưu chúng để chúng tự động được áp dụng cho hệ thống của bạn khi khởi động.
Lưu các quy tắc hiện tại của bạn (cả IPv4 và IPv6) bằng cách chạy như sau:
Thao tác này sẽ ghi đè các tệp /etc/iptables/rules.v4
và /etc/iptables/rules.v6
của bạn bằng các chính sách bạn đã tạo trên dòng lệnh.
Kết luận
Bằng cách làm theo hướng dẫn này, dán trực tiếp các quy tắc tường lửa của bạn vào tệp cấu hình hoặc bằng cách áp dụng và lưu chúng trên dòng lệnh theo cách thủ công, bạn đã tạo được cấu hình tường lửa khởi đầu tốt. Bạn sẽ phải thêm các quy tắc riêng lẻ để cho phép truy cập vào các dịch vụ bạn muốn cung cấp.
Khuôn khổ được thiết lập trong hướng dẫn này sẽ cho phép bạn thực hiện các điều chỉnh và có thể giúp làm rõ các chính sách hiện có của bạn. Xem một số hướng dẫn khác của chúng tôi về cách xây dựng chính sách tường lửa của bạn với một số dịch vụ phổ biến:
- Iptables Essentials: Các quy tắc và lệnh tường lửa phổ biến
- Cách thiết lập tường lửa Iptables để bảo vệ lưu lượng truy cập giữa các máy chủ của bạn
- Cách chuyển tiếp cổng thông qua cổng Linux với Iptables
- Cách kiểm tra cấu hình tường lửa của bạn với Nmap và Tcpdump