TL;DR: kube-restrict-ip allows you to restrict access to specified TCP ports of the Kubernetes nodes to defined set of IP addresses. Configuration for kube-restrict-ip is provided via a ConfigMap and it can be reconfigured in a live cluster by creating or editing this ConfigMap.

Tell me more!

Okay, let's imagine we have a Kubernetes cluster and deployed NGINX Ingress Controller. Its deployment descriptor specified use of hostNetwork: true for a great reason: this way NGINX running in a pod can directly see the network interfaces of the host machine where the pod was started. But the side effect of such setup is any service running in a pod will be directly accessible by the outside world, for example Prometheus metrics service running on port 10254.

Surely, we could manually add iptables rules for any node we need to restrict access to these ports, but it isn't in any way match Kubernetes ideology of the dynamic environment where nodes and pods can be created and destroyed at any moment. So, it will be great if these iptables rules will be also created automatically. And here we come to the kube-restrict-ip.

kube-restrict-ip is a little utility written in Go that creates an iptables chain containing matching rules for user-specified IP addresses (hosts and CIDR ranges), and a rule in INPUT chain that routes requests bound to restricted ports to rules chain. All unmatched IPs will be rejected.

The simplest way to apply these restrictions to all nodes in a Kubernetes cluster is launch the kube-restrict-ip utility as a DaemonSet. kube-restrict-ip repo includes an example kube-restrict-ip.yaml file that can be used to launch the kube-restrict-ip as a DaemonSet:

kubectl create -f kube-restrict-ip.yaml

After start kube-restrict-ip container will wait for a config file mounted to /etc/kube-restrict-ip/config.yaml mount point. This file can be provided via a ConfigMap, so it can be reconfigured in a live cluster by creating or editing this ConfigMap.

kube-restrict-ip repo includes an example config file that could be used to create the ConfigMap in your cluster:

kubectl create configmap kube-restrict-ip --from-file=config.yaml --namespace=kube-system

Please note that the ConfigMap in the same namespace as the DaemonSet Pods, and named the kube-restrict-ip to match the DaemonSet spec. This is necessary for the ConfigMap to appear in the Pods' filesystems.

Let's look into example config.yaml:

restrictedPorts:
  - 9100
  - 10254

allowedNetworks:
  - 127.0.0.1
  - 10.244.0.0/16
  - 172.17.0.1/16

checkInterval: 60s
  • restrictedPorts: A list restricted TCP ports (required).
  • allowedNetworks: A list allowed hosts and networks in CIDR notation (required). Please don't forget to add all internal networks here (docker, flannel, etc).
  • checkInterval: The interval to check config for updates (optional, default 60s). The syntax is any format accepted by Go's time.ParseDuration function. Please note that ConfigMap updates are propagated in the Kubernetes cluster with some delay which by my observations is about a minute, so setting checkInterval to values less of several tens seconds makes little sense.

There is another option not included in the example above:

  • ipChain: iptables chain name (optional, default "KUBE-RESTRICT-IP"). You could use it for specifying alternate rules chain name in case of multiple kube-restrict-ip running in a cluster.

After applying this config file to kube-restrict-ip, the next iptables rules will be created at the Kubernetes node:

# iptables --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
KUBE-RESTRICT-IP  tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 9100,10254 /* kube-restrict-ip */

...

Chain KUBE-RESTRICT-IP (1 references)
target     prot opt source               destination         
RETURN     all  --  localhost            anywhere            
RETURN     all  --  10.244.0.0/16        anywhere            
RETURN     all  --  172.17.0.0/16        anywhere            
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Conclusion

kube-restrict-ip is an utility focused in providing a simple way to restrict access to the services in a Kubernetes cluster. You could use it to limit access to ports exposed by pods with hostNetwork: true, like Prometheus metrics services, and modify these restrictions on the fly using a Kubernetes ConfigMap mechanism.