Zero-Trust Partner Webhooks
Secure inbound webhooks from external SaaS partners (billing, messaging, observability) using layered network checks and dynamic blocks while preserving telemetry for debugging.
Scenario
- Only specific partner networks should reach internal webhook receivers.
- Partners occasionally rotate IPs; your team maintains both static CIDRs and dynamic DB lists.
- During incidents you need a fast kill-switch for malicious sources without editing Envoy config.
- Observability teams want ASN/Geo/UA context to trace delivery issues with partners.
Controllers Used
maxmind-asn— tag requests with partner ASNs for dashboards.maxmind-geoip— capture country/region to detect unexpected egress locations.ip-match(partner-cidrs) — primary allowlist supplied by partners (text files).ip-match-database(partner-live) — Postgres table for temporary IPs partners add via ticket.asn-match(partner-asns) — allowlist of expected ASNs per provider.ip-match-database(incident-block) — Redis kill-switch populated by SOC during an incident.
Policy
Allow only when source matches partner CIDRs or live DB allowlist, belongs to approved ASNs, and is not in the incident blocklist:
yaml
authorizationPolicy: "(partner-cidrs || partner-live) && partner-asns && !incident-block"1
Example Configuration
yaml
analysisControllers:
- name: asn
type: maxmind-asn
settings:
databasePath: config/GeoLite2-ASN.mmdb
- name: geoip
type: maxmind-geoip
settings:
databasePath: config/GeoLite2-City.mmdb
matchControllers:
- name: partner-cidrs
type: ip-match
settings:
cidrList: config/partners/webhook-cidrs.txt
- name: partner-live
type: ip-match-database
settings:
matchesOnFailure: true # Fail-open to avoid partner outages
cache:
ttl: 30m
database:
type: postgres
postgres:
query: "SELECT 1 FROM partner_webhook_ips WHERE ip = $1 AND active = true"
host: postgres.partners.svc.cluster.local
port: 5432
databaseName: partners
usernameEnv: DB_USER
passwordEnv: DB_PASSWORD
- name: partner-asns
type: asn-match
settings:
asnList: config/partners/partner-asns.txt
- name: incident-block
type: ip-match-database
settings:
cache:
ttl: 5m
database:
type: redis
redis:
keyPrefix: "block:webhook:"
host: redis.soc.svc.cluster.local
port: 63791
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Request Flow
- Analysis controllers emit headers so upstream webhook handlers can log ASN + location for each delivery.
- Static partner CIDRs cover official ranges;
partner-livecatches ad-hoc ranges partners add temporarily. partner-asnsensures traffic originates from the partner’s network, defending against spoofed IP headers.incident-blockgives SOC instant deny capability via Redis without reloading Envoy.
Value Delivered
- Reduces partner outage risk with fail-open DB allowlist while keeping a hard deny switch.
- Telemetry-rich headers accelerate debugging when partners claim delivery success.
- Works across multiple partners by simply adding more CIDR/ASN files per provider.
Reliability Tips
- Keep
partner-liveTTL shorter than partner change windows; revalidate entries automatically. - Alert on
incident-blockhits to ensure SOC playbooks close the loop.