Skip to content

VPC Flow Logs — Observability Mạng và Network Forensics

Flow Logs Không Capture Tất Cả Packets

Một hiểu lầm phổ biến về VPC Flow Logs: không phải mọi packet đều được log. GCP dùng hai tầng sampling:

Primary sampling (dynamic, không configurable): GCP tự động áp dụng sampling rate biến đổi dựa trên load của physical host đang chạy VM. Traffic càng cao, sampling rate càng cao (để đảm bảo coverage); host đang yên tĩnh có rate thấp hơn. Bạn không thể control tầng này.

Secondary sampling (configurable): Sau primary sampling, GCP áp dụng một lần filter thứ hai với rate bạn chọn. Default là 50% (giữ lại 50% samples từ primary). Bạn có thể set từ 0 (tắt hoàn toàn) đến 1.0 (giữ tất cả từ primary).

Hệ quả: Ngay cả khi secondary sampling = 1.0, bạn vẫn không thấy 100% traffic — vì primary sampling đã loại bỏ một phần. Flow Logs là representative sample, không phải complete traffic dump.

Điểm Thu Thập: Trước Hay Sau Firewall?

Điểm này ảnh hưởng trực tiếp đến cách dùng Flow Logs cho debugging:

Ingress packets: Được sample SAU khi firewall rules đã evaluate. Điều này có nghĩa là packets bị DENY bởi ingress firewall không xuất hiện trong Flow Logs.

Egress packets: Được sample TRƯỚC khi egress firewall rules evaluate. Packets bị DENY bởi egress firewall xuất hiện trong Flow Logs (với disposition DENY).

Packet đến VM (Ingress flow):
  [External Source] → [Andromeda ingress firewall check] → [VM]
                              ↓ DENY here                    ↑ not reached
                         Không có log                   SAU đây mới có log

Packet ra từ VM (Egress flow):
  [VM] → [Sample TẠI ĐÂY] → [Andromeda egress firewall check] → [Destination]
          ↑ Log được tạo          ↓ nếu DENY                        ↑ không tới
                             Log có disposition=DENY

Hệ quả cho debugging: Nếu bạn không thấy inbound connection trong Flow Logs, có hai khả năng:

  1. Traffic chưa bao giờ đến VPC (blocked upstream)
  2. Ingress firewall đã drop traffic (nên check firewall logs thay vì flow logs)

Structure Của Một Flow Log Entry

Mỗi flow log entry đại diện cho một aggregated flow trong một aggregation interval (5 giây đến 15 phút, default 5 giây):

json
{
  "connection": {
    "src_ip": "203.0.113.5",
    "dest_ip": "10.0.0.5",
    "src_port": 54321,
    "dest_port": 443,
    "protocol": 6
  },
  "reporter": "DEST",
  "start_time": "2025-01-15T10:00:00Z",
  "end_time": "2025-01-15T10:00:05Z",
  "bytes_sent": 15234,
  "packets_sent": 23,
  "rtt_msec": 5,
  "src_location": {
    "country": "US",
    "region": "California"
  },
  "dest_instance": {
    "project_id": "my-project",
    "vm_name": "web-server-1",
    "region": "us-west1",
    "zone": "us-west1-a"
  }
}

Reporter field: Quan trọng nhất:

  • SRC: Flow được report bởi VM nguồn (egress flow)
  • DEST: Flow được report bởi VM đích (ingress flow đến VM trong GCP)

Nếu destination là external (internet), chỉ có SRC reporter. Nếu cả source và destination đều là VMs trong GCP, có thể có cả hai reporters — tránh count double khi analyze.

Metadata Fields (Optional)

Có thể enable thêm metadata:

  • Source/destination VM names, VPC, subnet
  • Source/destination geographic location
  • VPC project information
  • Latency measurements (RTT)

Enable metadata tăng storage cost nhưng cần thiết cho serious forensics.

Aggregation Interval: Trade-off Visibility vs Cost

Flow Logs aggregate packets trong một interval thành một entry:

Aggregation = 5 seconds (default):
  [1000 packets từ 203.0.113.5:54321 → 10.0.0.5:443 trong 5 giây]
  → Một log entry với bytes_sent=sum, packets_sent=1000

Aggregation = 5 minutes:
  [Cùng flow, aggregate thành 1 entry per 5 phút]
  → Ít entries hơn, tiết kiệm cost nhưng kém visibility

Default 5 giây phù hợp cho incident response và forensics. 5-15 phút phù hợp cho capacity planning và cost analysis.

Enable Flow Logs

bash
# Enable cho subnet
gcloud compute networks subnets update prod-us-west1 \
  --region=us-west1 \
  --enable-flow-logs \
  --logging-aggregation-interval=INTERVAL_5_SEC \
  --logging-flow-sampling=0.5 \
  --logging-metadata=INCLUDE_ALL_METADATA

# Disable (khi không cần nữa - cost savings)
gcloud compute networks subnets update prod-us-west1 \
  --region=us-west1 \
  --no-enable-flow-logs

Flow Logs được viết vào Cloud Logging automatically. Từ Cloud Logging có thể route đến BigQuery (analytics), Cloud Storage (long-term retention), hoặc Pub/Sub (real-time processing).

Cost Analysis: Khi Nào Flow Logs Quá Tốn Kém?

Flow Logs billing: $0.50/GB ingested vào Cloud Logging (tại thời điểm viết, kiểm tra pricing page để verify).

Với traffic volume cao:

Web server xử lý 10,000 requests/second:
  Mỗi flow entry: ~500 bytes
  Primary sampling: ~50% (estimate)
  Secondary sampling: 50%

Ước tính entries/second: 10,000 × 0.5 × 0.5 = 2,500 entries/sec
Ước tính data: 2,500 × 500 bytes = 1.25 MB/sec = 108 GB/ngày
Cost: 108 × $0.50 = $54/ngày per subnet

→ $1,620/tháng chỉ cho flow logs của một subnet!

Với production high-traffic environments, phải cân nhắc:

  1. Giảm secondary sampling: 0.1 (10%) thay vì 0.5 giảm cost 5×
  2. Tăng aggregation interval: 60 giây thay vì 5 giây
  3. Disable metadata: Chỉ enable khi cần
  4. Enable chỉ cho critical subnets: Không cần cho tất cả subnets
  5. Export sang BigQuery với lifecycle policy: Giữ Cloud Logging logs ngắn hạn, long-term analysis ở BigQuery storage tier rẻ hơn

Dùng Flow Logs Cho Debugging

Use Case 1: Tìm Nguồn Gốc Của Traffic Tăng Bất Thường

sql
-- Query BigQuery: Top source IPs trong 1 giờ qua
SELECT
  jsonPayload.connection.src_ip,
  SUM(CAST(jsonPayload.bytes_sent AS INT64)) as total_bytes,
  COUNT(*) as flow_count
FROM `project.dataset.compute_googleapis_com_vpc_flows_*`
WHERE
  _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
  AND jsonPayload.reporter = 'DEST'
  AND jsonPayload.dest_instance.vm_name = 'web-server-1'
GROUP BY 1
ORDER BY total_bytes DESC
LIMIT 20

Use Case 2: Kiểm Tra Connectivity (Outbound)

sql
-- Check xem VM có kết nối đến destination IP không
SELECT
  jsonPayload.connection.src_ip,
  jsonPayload.connection.dest_ip,
  jsonPayload.connection.dest_port,
  jsonPayload.start_time,
  jsonPayload.bytes_sent
FROM `project.dataset.compute_googleapis_com_vpc_flows_*`
WHERE
  jsonPayload.reporter = 'SRC'
  AND jsonPayload.src_instance.vm_name = 'app-server-1'
  AND jsonPayload.connection.dest_ip = '10.50.0.5'
ORDER BY start_time DESC
LIMIT 100

Use Case 3: Lateral Movement Detection (Security)

sql
-- Tìm VMs kết nối đến nhiều internal IPs (potential port scan)
SELECT
  jsonPayload.connection.src_ip,
  jsonPayload.src_instance.vm_name,
  COUNT(DISTINCT jsonPayload.connection.dest_ip) as unique_dests,
  COUNT(DISTINCT jsonPayload.connection.dest_port) as unique_ports
FROM `project.dataset.compute_googleapis_com_vpc_flows_*`
WHERE
  jsonPayload.reporter = 'SRC'
  AND TIMESTAMP(jsonPayload.start_time) > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
  AND NET.IP_IN_NET(jsonPayload.connection.dest_ip, '10.0.0.0/8')
GROUP BY 1, 2
HAVING unique_dests > 50
ORDER BY unique_dests DESC

Limitation Quan Trọng

Flow Logs không log traffic bị firewall drop (cho ingress). Nếu bạn cần biết packets bị drop, phải enable Firewall Rules Logging (riêng biệt với Flow Logs):

bash
gcloud compute firewall-rules update deny-ssh \
  --enable-logging

Firewall Rules Logging log mỗi connection được allow hoặc deny bởi rule đó. Dùng kết hợp Flow Logs (connectivity patterns) và Firewall Logs (allow/deny decisions) cho complete visibility.

References