Skip to content

Remediation: API Latency Spike, BGP Route Leak, Fix Is Network ACL

Immediate Fix (Security — Domain C)

The fix is to replace the BGP prefix-list filter with a proper inbound ACL that achieves the security intent without breaking routing.

Step 1: Remove the BGP prefix-list filter

router# configure terminal
router(config)# no ip prefix-list DENY-PARTNER-ROUTES seq 10 deny 198.51.100.0/24
router(config)# end
router# clear ip bgp 203.0.114.1 soft in

Step 2: Verify the preferred route is restored

router# show ip bgp 198.51.100.0/24
BGP routing table entry for 198.51.100.0/24
  Paths: (2 available, best #2)
    Path 1: AS_PATH 64501 64999 64700
      Next hop: 203.0.113.1 (ISP-A via transit)
      MED: 200, LOCAL_PREF: 100
    Path 2: AS_PATH 64502 64700
      Next hop: 203.0.114.1 (ISP-B direct peering)
      MED: 50, LOCAL_PREF: 150
      Origin: IGP, valid, best   **<-- Now active**

Step 3: Implement the correct security control — inbound ACL

router# configure terminal
router(config)# ip access-list extended BLOCK-PARTNER-INBOUND-SCANS
router(config-acl)# remark Block inbound scanning from partner range per SEC-4471
router(config-acl)# deny tcp 198.51.100.0 0.0.0.255 any range 1 1023 log
router(config-acl)# deny udp 198.51.100.0 0.0.0.255 any range 1 1023 log
router(config-acl)# permit ip any any
router(config-acl)# exit
router(config)# interface GigabitEthernet0/1
router(config-if)# ip access-group BLOCK-PARTNER-INBOUND-SCANS in
router(config-if)# end
router# write memory

This blocks inbound scanning from the partner's range (the actual security intent) without affecting outbound BGP route selection.

Verification

Domain A (Observability) — Latency back to normal

# Prometheus query after fix:
# histogram_quantile(0.99, rate(http_request_duration_seconds_bucket{service="checkout-api",handler="/v1/checkout"}[5m]))
# Result: 0.172 seconds — back to baseline

# Error rate:
# rate(http_requests_total{service="checkout-api",status=~"5.."}[5m]) / rate(http_requests_total{service="checkout-api"}[5m])
# Result: 0.001 — back to baseline 0.1%

Domain B (Networking) — Route path correct

$ kubectl exec -it checkout-api-6b5d8c9f-x2k4j -n prod -- traceroute -n 198.51.100.42
traceroute to 198.51.100.42, 30 hops max
 1  10.0.0.1      0.5 ms
 2  10.0.1.1      0.8 ms
 3  172.16.0.1    1.2 ms
 4  203.0.114.1   2.1 ms    # ISP-B (direct peering)
 5  198.51.100.1  14.2 ms   # Partner's edge
 6  198.51.100.42 16.8 ms   # Partner's server

6 hops, 17ms — back to the direct peering path.

Domain C (Security) — Inbound scanning blocked

router# show access-lists BLOCK-PARTNER-INBOUND-SCANS
Extended IP access list BLOCK-PARTNER-INBOUND-SCANS
    10 deny tcp 198.51.100.0 0.0.0.255 any range 1 1023 log (23 matches)
    20 deny udp 198.51.100.0 0.0.0.255 any range 1 1023 log (7 matches)
    30 permit ip any any (1284721 matches)

The ACL is active and blocking inbound scans while permitting all other traffic.

Prevention

  • Monitoring: Add a BGP route change alert that fires when the active path to critical partner prefixes changes. Monitor AS path length as a proxy for route quality.
- alert: BGPPathChanged
  expr: bgp_path_as_count{prefix="198.51.100.0/24"} > 3
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "BGP path to partner network has changed  AS path length increased"
  • Runbook: Security tickets that involve IP range blocking must specify the control type (inbound ACL, outbound ACL, or BGP filter) and must be reviewed by the network team for routing impact before implementation.

  • Architecture: Separate the security ACL from BGP route policy. Use a firewall or a separate ACL on the interface for traffic filtering. BGP prefix-lists should only be used for route policy, never for security filtering.