design/ip-filtering-design.md
Status: Approved
Allow or deny traffic to services behind contour with an IP allowlist or an IP denylist.
There have been long standing requests to support some form of IP filtering. IP filtering is a useful tool for network segregation that is supported by other ingress controllers like ingress-nginx and ambassador, and is a common request among the community, often listed as a blocker for adopting contour.
X-Forwarded-For)The virtualhost and route sections of an HTTPProxy will each have two new fields added: ipAllowPolicy and ipDenyPolicy.
Example HTTPProxy:
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: basic
spec:
virtualhost:
fqdn: foo-basic.bar.com
ipAllowPolicy:
# traffic is allowed if it came from localhost (i.e. co-located reverse proxy)
- cidr: 127.0.0.1/32
source: Peer
routes:
- conditions:
- prefix: /
services:
- name: s1
port: 80
# route-level ip filters overrides the virtualhost-level filters
ipAllowPolicy:
# traffic is allowed if it came from localhost (i.e. co-located reverse proxy)
- cidr: 127.0.0.1/32
source: Peer
# and the request originated from an IP in this range
- cidr: 99.99.0.0/16
source: Remote
ipAllowPolicy/ipDenyPolicy has the following structure:
ipAllowPolicy:
- cidr: 127.0.0.1/32
source: Peer
- cidr: 99.99.0.0/16
source: Remote
ipDenyPolicy:
- cidr: 127.0.0.1/32
source: Peer
- cidr: 99.99.0.0/16
source: Remote
Note that:
Peer refers to the request IPRemote refers to the originating IP, i.e. X-Forwarded-For. numTrustedHops may also need to be set to filter on the desired IP.HTTPProxyProcessor and dag.Route will store the ip filtering rules in a new field.
These settings will be converted convert to a per-route or per-virtualhost envoy filter, i.e.:
routes:
- match:
prefix: /
route:
cluster: example-cluster
typed_per_filter_config:
envoy.filters.http.rbac:
'@type': type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute
rbac:
rules:
# action is ALLOW if ipAllowPolicy is used, otherwise DENY is used
action: ALLOW
policies:
ip-rules:
permissions:
- any: true
principals:
# direct_remote_ip is used if `source: Peer` is specified
- direct_remote_ip:
address_prefix: 127.0.0.1
prefix_len: 32
# remote_ip is used if `source: Remote` is specified
- remote_ip:
address_prefix: 99.99.0.0
prefix_len: 16
Please see the Envoy docs for more detailed explanations of the filter behavior.
The ip filtering could be a top-level field on the HTTPProxy.
This would allow building "trees" of ip filters via includes:
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: basic
spec:
virtualhost:
fqdn: foo-basic.bar.com
ipAllowPolicy:
# traffic is allowed if it came from localhost (i.e. co-located reverse proxy)
- peer: 127.0.0.1
# and the request originated from an IP in this range
- remote: 99.99.0.0/16
includes:
- name: service2
conditions:
- prefix: /service2
routes:
- conditions:
- prefix: /
services:
- name: s1
port: 80
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: service2
spec:
ipDenyPolicy:
# if the request made it through the first filter, it could still be denied here
- remote: 99.99.0.1
routes:
- conditions:
- prefix: /service2
services:
- name: s2
port: 80
But no other request filtering options work this way today, so this approach seems like a mismatch with current Contour.