|
| 1 | +# IP Filtering |
| 2 | + |
| 3 | +The Hooks service provides comprehensive application-level IP filtering functionality that allows you to control access to your webhooks based on client IP addresses. This feature supports both allowlist and blocklist configurations with CIDR notation support. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +IP filtering operates as a "pre-flight" check in the request processing pipeline, validating incoming requests before they reach your webhook handlers. The filtering can be configured both globally (for all endpoints) and at the individual endpoint level. |
| 8 | + |
| 9 | +## ⚠️ Security Considerations |
| 10 | + |
| 11 | +**Important**: This IP filtering operates at the application layer and relies on HTTP headers (like `X-Forwarded-For`) to determine client IP addresses. This approach has important security implications: |
| 12 | + |
| 13 | +1. **Header Trust**: The service trusts proxy headers, which can be spoofed by malicious clients |
| 14 | +2. **Network-Level Protection**: For production security, consider implementing IP filtering at the network or load balancer level |
| 15 | +3. **Proper Proxy Configuration**: Ensure your reverse proxy/load balancer is properly configured to set accurate IP headers |
| 16 | +4. **Defense in Depth**: Use this feature as part of a broader security strategy, not as the sole protection mechanism |
| 17 | + |
| 18 | +## Configuration |
| 19 | + |
| 20 | +### Global Configuration |
| 21 | + |
| 22 | +Configure IP filtering globally to apply rules to all endpoints: |
| 23 | + |
| 24 | +```yaml |
| 25 | +# hooks.yml or your main configuration file |
| 26 | +ip_filtering: |
| 27 | + ip_header: X-Forwarded-For # Optional, defaults to X-Forwarded-For |
| 28 | + allowlist: |
| 29 | + - "10.0.0.0/8" # Allow entire private network |
| 30 | + - "172.16.0.0/12" # Allow another private range |
| 31 | + - "192.168.1.100" # Allow specific IP |
| 32 | + blocklist: |
| 33 | + - "192.168.1.200" # Block specific IP even if in allowlist |
| 34 | + - "203.0.113.0/24" # Block entire subnet |
| 35 | +``` |
| 36 | +
|
| 37 | +### Endpoint-Level Configuration |
| 38 | +
|
| 39 | +Configure IP filtering for specific endpoints: |
| 40 | +
|
| 41 | +> If a global configuration is set, endpoint-level settings will override it. |
| 42 | +
|
| 43 | +```yaml |
| 44 | +# config/endpoints/secure-endpoint.yml |
| 45 | +path: /secure-webhook |
| 46 | +handler: my_secure_handler |
| 47 | + |
| 48 | +ip_filtering: |
| 49 | + ip_header: X-Real-IP # Optional, defaults to X-Forwarded-For |
| 50 | + allowlist: |
| 51 | + - "127.0.0.1" # Allow localhost |
| 52 | + - "192.168.1.0/24" # Allow local network |
| 53 | + blocklist: |
| 54 | + - "192.168.1.100" # Block specific IP in the allowed range |
| 55 | +``` |
| 56 | +
|
| 57 | +## Configuration Options |
| 58 | +
|
| 59 | +### `ip_header` (optional) |
| 60 | + |
| 61 | +- **Default**: `X-Forwarded-For` |
| 62 | +- **Description**: HTTP header to check for the client IP address |
| 63 | +- **Common alternatives**: `X-Real-IP`, `CF-Connecting-IP`, `X-Client-IP` |
| 64 | + |
| 65 | +### `allowlist` (optional) |
| 66 | + |
| 67 | +- **Type**: Array of strings |
| 68 | +- **Description**: List of allowed IP addresses or CIDR ranges |
| 69 | +- **Behavior**: If specified, only IPs in this list are allowed access |
| 70 | +- **Format**: Individual IPs (`192.168.1.1`) or CIDR notation (`192.168.1.0/24`) |
| 71 | + |
| 72 | +### `blocklist` (optional) |
| 73 | + |
| 74 | +- **Type**: Array of strings |
| 75 | +- **Description**: List of blocked IP addresses or CIDR ranges |
| 76 | +- **Behavior**: IPs in this list are denied access, even if they appear in the allowlist |
| 77 | +- **Format**: Individual IPs (`192.168.1.1`) or CIDR notation (`192.168.1.0/24`) |
| 78 | + |
| 79 | +## Filtering Logic |
| 80 | + |
| 81 | +The IP filtering follows this precedence order: |
| 82 | + |
| 83 | +1. **Extract Client IP**: Get the client IP from the configured header (case-insensitive lookup) |
| 84 | +2. **Check Blocklist**: If the IP matches any entry in the blocklist, deny immediately |
| 85 | +3. **Check Allowlist**: If an allowlist is configured, the IP must match an entry to be allowed |
| 86 | +4. **Default Allow**: If no allowlist is configured and IP is not blocked, allow the request |
| 87 | + |
| 88 | +### Precedence Rules |
| 89 | + |
| 90 | +- **Endpoint-level configuration** takes precedence over global configuration |
| 91 | +- **Blocklist rules** take precedence over allowlist rules |
| 92 | +- **First IP in comma-separated list** is used (e.g., in `X-Forwarded-For: 192.168.1.1, 10.0.0.1`, only `192.168.1.1` is checked) |
| 93 | + |
| 94 | +## CIDR Notation Support |
| 95 | + |
| 96 | +The service supports CIDR (Classless Inter-Domain Routing) notation for specifying IP ranges: |
| 97 | + |
| 98 | +```yaml |
| 99 | +ip_filtering: |
| 100 | + allowlist: |
| 101 | + - "192.168.1.0/24" # Allows 192.168.1.1 through 192.168.1.254 |
| 102 | + - "10.0.0.0/8" # Allows 10.0.0.1 through 10.255.255.254 |
| 103 | + - "172.16.0.0/12" # Allows 172.16.0.1 through 172.31.255.254 |
| 104 | + blocklist: |
| 105 | + - "192.168.1.100/32" # Blocks specific IP (equivalent to 192.168.1.100) |
| 106 | + - "203.0.113.0/24" # Blocks entire test network range |
| 107 | +``` |
| 108 | + |
| 109 | +## Examples |
| 110 | + |
| 111 | +### Example 1: Basic Allowlist |
| 112 | + |
| 113 | +```yaml |
| 114 | +# Allow only specific IPs |
| 115 | +path: /secure-webhook |
| 116 | +handler: secure_handler |
| 117 | +
|
| 118 | +ip_filtering: |
| 119 | + allowlist: |
| 120 | + - "127.0.0.1" |
| 121 | + - "192.168.1.50" |
| 122 | +``` |
| 123 | + |
| 124 | +### Example 2: CIDR Range with Exceptions |
| 125 | + |
| 126 | +```yaml |
| 127 | +# Allow local network but block specific troublemaker |
| 128 | +path: /internal-webhook |
| 129 | +handler: internal_handler |
| 130 | +
|
| 131 | +ip_filtering: |
| 132 | + allowlist: |
| 133 | + - "192.168.1.0/24" |
| 134 | + blocklist: |
| 135 | + - "192.168.1.100" # Block this specific IP |
| 136 | +``` |
| 137 | + |
| 138 | +### Example 3: Custom IP Header |
| 139 | + |
| 140 | +```yaml |
| 141 | +# Use Cloudflare's connecting IP header |
| 142 | +path: /cloudflare-webhook |
| 143 | +handler: cf_handler |
| 144 | +
|
| 145 | +ip_filtering: |
| 146 | + ip_header: CF-Connecting-IP |
| 147 | + allowlist: |
| 148 | + - "203.0.113.0/24" |
| 149 | +``` |
| 150 | + |
| 151 | +### Example 4: Multiple CIDR Ranges |
| 152 | + |
| 153 | +```yaml |
| 154 | +# Allow multiple office networks |
| 155 | +path: /office-webhook |
| 156 | +handler: office_handler |
| 157 | +
|
| 158 | +ip_filtering: |
| 159 | + allowlist: |
| 160 | + - "192.168.1.0/24" # Main office |
| 161 | + - "192.168.2.0/24" # Branch office |
| 162 | + - "10.0.100.0/24" # VPN range |
| 163 | + blocklist: |
| 164 | + - "192.168.1.200" # Compromised machine |
| 165 | +``` |
| 166 | + |
| 167 | +## Error Responses |
| 168 | + |
| 169 | +When IP filtering fails, the service returns an HTTP 403 Forbidden response: |
| 170 | + |
| 171 | +```json |
| 172 | +{ |
| 173 | + "error": "ip_filtering_failed", |
| 174 | + "message": "IP address not allowed", |
| 175 | + "request_id": "<uuid>" |
| 176 | +} |
| 177 | +``` |
| 178 | + |
| 179 | +## Testing Your Configuration |
| 180 | + |
| 181 | +You can test your IP filtering configuration using curl: |
| 182 | + |
| 183 | +```bash |
| 184 | +# Test with allowed IP |
| 185 | +curl -H "X-Forwarded-For: 192.168.1.50" \ |
| 186 | + -H "Content-Type: application/json" \ |
| 187 | + -d '{"test": "data"}' \ |
| 188 | + http://localhost:8080/webhooks/secure-endpoint |
| 189 | +
|
| 190 | +# Test with blocked IP |
| 191 | +curl -H "X-Forwarded-For: 192.168.1.100" \ |
| 192 | + -H "Content-Type: application/json" \ |
| 193 | + -d '{"test": "data"}' \ |
| 194 | + http://localhost:8080/webhooks/secure-endpoint |
| 195 | +``` |
0 commit comments