Skip to content

Firewall Debugging: Rule Priority and Evaluation

Tại sao Firewall Debugging Quan Trọng

Firewall rules là rào cản đầu tiên (first barrier) mà các packet gặp phải ngay sau interface nguồn (chiều egress) hoặc trước interface đích (chiều ingress). Cấu hình sai ở đây sẽ chặn traffic hợp lệ hoặc cho phép traffic không mong muốn đi qua.

VPC firewall rules sử dụng đánh giá dựa trên độ ưu tiên (priority-based evaluation) từ 0-65535 (số nhỏ hơn = độ ưu tiên cao hơn), không phải theo thứ tự tuần tự (sequence-based) như các firewall truyền thống. Nếu không hiểu rõ mô hình này, việc debug firewall rules sẽ rất phức tạp và dễ gây nhầm lẫn.

Cơ chế bên trong: Priority-Based Evaluation

Cấu trúc Rule

Mỗi VPC firewall rule gồm các thành phần:

Rule {
  name: "allow-http"
  direction: INGRESS  // hoặc EGRESS
  priority: 1000      // 0-65535, số nhỏ hơn = độ ưu tiên cao hơn
  action: ALLOW       // hoặc DENY
  match {
    sourceRanges: ["10.0.0.0/8"]      // nếu là INGRESS
    destinationRanges: ["10.0.0.0/8"]  // nếu là EGRESS
    sourceTags: ["web-client"]         // tag của source instance
    targetTags: ["web-server"]         // tag của destination instance
    protocol: "tcp"
    ports: [80, 443]
  }
}

Thuật toán Đánh giá (Evaluation Algorithm)

Khi packet truyền đến (ingress) hoặc gửi đi (egress), firewall sẽ áp dụng:

Bước 1: Tìm tất cả các rules khớp (match) về direction, protocol, ports, ranges, và tags.

Bước 2: Sắp xếp các rules khớp theo thứ tự ưu tiên (priority tăng dần, từ 0 trở lên).

Bước 3: Áp dụng rule khớp đầu tiên tìm được (chỉ áp dụng duy nhất rule đó, bỏ qua các rule còn lại).

Bước 4: Nếu không có rule nào khớp, áp dụng hành động default deny mặc định.

Ví dụ:

Packet: Ingress TCP tới port 443 từ 10.0.1.2 đến 10.1.1.2 (target tag: "web-server")

Rules hiện có:
  Rule A: priority=100, action=DENY, sourceRanges=[10.0.0.0/8]
  Rule B: priority=500, action=ALLOW, sourceRanges=[10.0.1.0/24]
  Rule C: priority=1000, action=ALLOW, sourceRanges=[0.0.0.0/0]
  Rule D: priority=2000, action=DENY, ports=[443]

Bước 1: Tìm các rule khớp
  - Rule A: Khớp (sourceRange khớp, target tag khớp)
  - Rule B: Khớp (sourceRange khớp, target tag khớp)
  - Rule C: Khớp (sourceRange khớp, target tag khớp)
  - Rule D: Không khớp (độ ưu tiên thấp hơn, khớp port nhưng không khớp các điều kiện khác)

Bước 2: Sắp xếp theo priority (ưu tiên từ cao xuống thấp)
  1. Rule A (priority 100) ← ĐỘ ƯU TIÊN CAO NHẤT (SỐ NHỎ NHẤT)
  2. Rule B (priority 500)
  3. Rule C (priority 1000)
  4. Rule D (priority 2000)

Bước 3: Áp dụng rule khớp đầu tiên
  → Rule A khai báo DENY
  → Traffic bị chặn
  
Kết quả: DENIED (bởi Rule A)

Key insight: Không quan trọng việc Rule B chi tiết hơn (exact source range là 10.0.1.0/24) so với Rule A (10.0.0.0/8). Vì Rule A có priority cao hơn (số 100 nhỏ hơn 500), nên Rule A sẽ chiến thắng.

Quy tắc Tiebreaker: Deny Wins

Nếu hai rules có cùng priority (trong trường hợp hiếm hoi), hành động DENY sẽ chiến thắng:

Rule X: priority=1000, action=ALLOW
Rule Y: priority=1000, action=DENY

→ DENY được áp dụng (để đảm bảo an toàn)

Trên thực tế, GCP không cho phép tạo các rule trùng priority trong cùng một VPC network, do đó trường hợp này hiếm khi xảy ra.

Các lỗi Firewall thường gặp khi Debug

Trường hợp 1: Luật Deny quá rộng (Overly Broad Deny Rule)

Kịch bản:

Rule 1: priority=100, action=DENY, sourceRanges=[0.0.0.0/0]
Rule 2: priority=500, action=ALLOW, sourceRanges=[10.0.0.0/8]

Vấn đề: Rule 2 không bao giờ được kích hoạt, vì Rule 1 (deny all) có priority cao hơn (100 < 500).

Triệu chứng: Mọi traffic đều bị chặn, kể cả traffic từ các dải IP nội bộ.

Debug:

bash
gcloud compute firewall-rules list --filter="priority<1000" --format=table
# Kiểm tra xem có rule DENY rộng nào có priority cao hay không

Cách sửa: Xóa Rule 1 (dựa vào cơ chế default deny mặc định), hoặc giảm độ ưu tiên của nó (tăng số priority):

bash
gcloud compute firewall-rules update rule-1 --priority=9999

Trường hợp 2: Thiếu luật Allow (Missing Allow Rule)

Kịch bản:

Không có rule allow rõ ràng cho kiểu traffic X
Mặc định: Deny all

Vấn đề: Traffic X bị chặn.

Triệu chứng: Connectivity Tests báo cấu hình OK, nhưng flow logs hiển thị action=DENY với rule_name="default-deny" (hoặc không tìm thấy rule khớp).

Debug:

bash
# Kiểm tra các rule tồn tại cho kiểu traffic này
gcloud compute firewall-rules list \
  --filter="direction=INGRESS AND allow-list:tcp:443"

Cách sửa: Tạo rule allow với priority cao hơn các rule deny hiện tại (số priority nhỏ hơn):

bash
gcloud compute firewall-rules create allow-https \
  --direction=INGRESS \
  --allow=tcp:443 \
  --source-ranges=0.0.0.0/0 \
  --target-tags=web-server \
  --priority=100

Trường hợp 3: Nhầm lẫn giữa Source Tags và Destination Tags

Kịch bản:

Rule: sourceRanges=[10.0.0.0/8], targetTags=["web-server"]

Vấn đề: Rule này khớp với traffic đi TỚI các instance có tag "web-server" từ dải IP 10.0.x.x.

Nếu bạn muốn khớp với traffic đi từ các instance có tag "client", bạn phải sử dụng sourceTags thay vì sourceRanges.

Cách sửa:

bash
gcloud compute firewall-rules create allow-from-clients \
  --direction=INGRESS \
  --allow=tcp:443 \
  --source-tags=client          # ← Cấu hình Source tags
  --target-tags=web-server
  --priority=100

Trường hợp 4: Rule cụ thể hơn không ghi đè được Priority

Kịch bản:

Rule A: priority=100, action=DENY, protocol=all
Rule B: priority=500, action=ALLOW, protocol=tcp, ports=[443]

Vấn đề: Rule B (cụ thể hơn) bị bỏ qua, vì Rule A có priority cao hơn (100 < 500).

Hiểu lầm phổ biến: "Quy tắc allow của tôi cụ thể hơn, nên nó phải được ưu tiên trước."

Thực tế: Priority luôn luôn chiến thắng, bất kể rule có cụ thể ra sao.

Cách sửa: Cấu hình Rule B có priority cao hơn (số nhỏ hơn):

bash
gcloud compute firewall-rules update rule-b --priority=50  # Số nhỏ hơn = ưu tiên cao hơn

Sử dụng VPC Flow Logs để debug Firewall

VPC Flow Logs hiển thị chính xác rule nào đang được áp dụng:

json
{
  "action": "DENY",
  "rule_priority": 1000,
  "rule_name": "deny-internal-ssh"
}

Quy trình xử lý:

  1. Bị chặn ở chiều Ingress (Ingress denied):

    • Kiểm tra Flow Logs của subnet đích (có thể không thấy entry vì bị chặn ở chiều ingress).
    • Kiểm tra Flow Logs của subnet nguồn, tìm entry có action=DENY.
    • Lấy thông tin rule_namerule_priority từ flow log.
    • Tìm kiếm rule tương ứng: gcloud compute firewall-rules describe [rule_name].
    • Xác minh xem traffic có khớp với sourceRanges, sourceTags, hay ports hay không.
    • Nếu rule không chính xác, tiến hành cập nhật hoặc xóa bỏ.
  2. Bị chặn ở chiều Egress (Egress denied):

    • Kiểm tra Flow Logs của subnet nguồn, tìm entry có action=DENY đi kèm egress rule.
    • Kiểm tra rule_priority, tìm rule tương ứng.
    • Xác minh rule destinationRanges và targetTags xem có khớp không.
    • Cập nhật rule nếu cần thiết.

Sử dụng Firewall Insights (Công cụ GCP)

GCP cung cấp công cụ Firewall Insights giúp phân tích các rule và đề xuất tối ưu hóa:

bash
gcloud compute firewall-policies rules list \
  --firewall-policy=default

Công cụ có thể phát hiện:

  • Các rule quá rộng (ví dụ: allow từ 0.0.0.0/0).
  • Các rule không được sử dụng (zero traffic).
  • Các rule bị xung đột (conflicting rules).

Sử dụng: Nên thường xuyên kiểm tra cấu hình rule bằng Firewall Insights.

Thiết lập Priority: Hướng dẫn Best Practices

Khi tạo nhiều rule, hãy phân chia các dải priority rõ ràng:

Deny all mặc định: 65534 (do hệ thống tạo)
Deny quan trọng (Critical): 1000-2000
Allow cho các service cụ thể: 100-500
Các trường hợp khác: 500-1000

Ví dụ:

bash
# Quan trọng: Chỉ cho phép SSH từ dải IP quản trị
gcloud compute firewall-rules create allow-admin-ssh \
  --direction=INGRESS \
  --allow=tcp:22 \
  --source-ranges=203.0.113.0/24 \  # Dải IP Admin
  --target-tags=admin-box \
  --priority=100

# Service: Cho phép HTTP từ mọi nơi
gcloud compute firewall-rules create allow-http-any \
  --direction=INGRESS \
  --allow=tcp:80 \
  --source-ranges=0.0.0.0/0 \
  --target-tags=web-server \
  --priority=500

# Service: Cho phép HTTPS từ mọi nơi
gcloud compute firewall-rules create allow-https-any \
  --direction=INGRESS \
  --allow=tcp:443 \
  --source-ranges=0.0.0.0/0 \
  --target-tags=web-server \
  --priority=500

# Luật chung: Chặn các dải IP xấu đã biết (cập nhật qua CI)
gcloud compute firewall-rules create deny-bad-ips \
  --direction=INGRESS \
  --allow=all \
  --source-ranges=198.51.100.0/24 \
  --priority=10000

Egress Firewall Rules

Chiều egress thường bị bỏ qua. VPC firewall cũng quản lý cả egress (outbound traffic từ VM).

Hành vi mặc định của Egress

Nếu không có rule egress rõ ràng, mặc định là cho phép toàn bộ outbound. Nhưng nếu bạn đã tạo một rule egress bất kỳ, quy tắc mặc định deny sẽ được áp dụng cho các traffic còn lại.

Kịch bản:

Subnet có rule egress cho phép traffic đến dải IP nội bộ:

Rule: priority=100, action=ALLOW, 
       direction=EGRESS, destinationRanges=[10.0.0.0/8]

Kết quả: Các VM trong subnet không thể kết nối ra ngoài internet (bị chặn bởi rule default deny)

Cách debug Egress Firewall

bash
# Liệt kê tất cả rule egress
gcloud compute firewall-rules list --filter="direction=EGRESS"

# Kiểm tra xem outbound có bị chặn không
# Nếu không có rule allow rõ ràng, hãy kiểm tra flow logs
# Tìm kiếm entry có action=DENY ở chiều egress với rule_name="default-deny-egress"

Một số trường hợp đặc biệt (Edge Cases)

Service Accounts và Firewall

Firewall rules không hoạt động dựa trên service account. Các rule chỉ dựa trên dải IP và tags.

Hệ quả: Nếu VM A (chạy service account X) và VM B (chạy service account Y) ở cùng subnet và có cùng tag, firewall rules sẽ áp dụng lên cả hai như nhau.

VPC Service Controls

Đừng nhầm lẫn VPC firewall rules với VPC Service Controls (Firewall Policies).

  • VPC Firewall Rules: Quản lý kết nối ở mức độ VM.
  • VPC Service Controls: Quản lý chính sách truy cập ở mức độ service (như GCS buckets, BigQuery datasets).

Cả hai hoạt động độc lập. Một gói tin có thể đi qua VPC firewall bình thường nhưng vẫn bị chặn bởi VPC Service Controls.

Custom Routes + Firewall

Firewall hoạt động độc lập với routing. Traffic có thể có route hợp lệ nhưng vẫn bị chặn bởi firewall, hoặc ngược lại có rule firewall cho phép nhưng không có route trả về (packet bị drop).

Best Practices

1. Sử dụng Service Accounts + IAM để kiểm soát truy cập ứng dụng

Các rule dựa trên IP/tag thường không đủ chi tiết. Để kiểm soát truy cập ở mức độ ứng dụng, hãy sử dụng service accounts kết hợp Cloud IAM:

bash
# Thay vì dùng firewall rule, hãy dùng IAM
gcloud projects add-iam-policy-binding my-project \
  --member=serviceAccount:app@my-project.iam.gserviceaccount.com \
  --role=roles/compute.instanceAdmin.v1

2. Định kỳ kiểm tra bằng Firewall Insights

Hãy định kỳ audit lại các rule bằng Firewall Insights:

bash
# Liệt kê các rule có lượng traffic lớn
gcloud compute firewall-policies rules list \
  --firewall-policy=default

3. Đặt tên Rule rõ nghĩa

Tên firewall rule nên mô tả rõ mục đích sử dụng của nó:

TỐT:  allow-internal-mysql
XẤU:  rule1

4. Kiểm tra trước khi thay đổi bằng Connectivity Tests

Trước khi áp dụng thay đổi firewall, hãy xác thực bằng Connectivity Tests:

bash
# Trước: Xác thực kết nối trước khi tắt rule cũ
gcloud compute network-management connectivity-tests create pre-change-test \
  --source-instance=... \
  --destination-instance=...

# Thực hiện thay đổi cấu hình

# Sau: Xác thực lại sau khi thay đổi
gcloud compute network-management connectivity-tests create post-change-test \
  --source-instance=... \
  --destination-instance=...

5. Sử dụng Firewall Policies cho các quy tắc ở mức Organization

Để áp dụng các rule chung cho nhiều VPC khác nhau:

bash
# Tạo firewall policy ở mức organization
gcloud compute firewall-policies create org-deny-low-priority \
  --description="Organization-level deny rules"

# Áp dụng chính sách cho các project mục tiêu
gcloud compute firewall-policies associations create \
  --firewall-policy=org-deny-low-priority \
  --target-resource=projects/my-project

References