Ingress Gateway
This task shows you how to enforce IP-based access control on an Istio ingress gateway using an authorization policy.
Before you begin
Before you begin this task, do the following:
Read the Istio authorization concepts.
Install Istio using the Istio installation guide.
Deploy a workload,
httpbinin a namespace, for examplefoo, and expose it through the Istio ingress gateway with this command:$ kubectl create ns foo $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n foo $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin-gateway.yaml@) -n fooTurn on RBAC debugging in Envoy for the ingress gateway:
$ kubectl get pods -n istio-system -o name -l istio=ingressgateway | sed 's|pod/||' | while read -r pod; do istioctl proxy-config log "$pod" -n istio-system --level rbac:debug; doneFollow the instructions in Determining the ingress IP and ports to define the
INGRESS_HOSTandINGRESS_PORTenvironment variables.Verify that the
httpbinworkload and ingress gateway are working as expected using this command:$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200
Getting traffic into Kubernetes and Istio
All methods of getting traffic into Kubernetes involve opening a port on all worker nodes. The main features that accomplish this are the NodePort service and the LoadBalancer service. Even the Kubernetes Ingress resource must be backed by an Ingress controller that will create either a NodePort or a LoadBalancer service.
A
NodePortjust opens up a port in the range 30000-32767 on each worker node and uses a label selector to identify which Pods to send the traffic to. You have to manually create some kind of load balancer in front of your worker nodes or use Round-Robin DNS.A
LoadBalanceris just like aNodePort, except it also creates an environment specific external load balancer to handle distributing traffic to the worker nodes. For example, in AWS EKS, theLoadBalancerservice will create a Classic ELB with your worker nodes as targets. If your Kubernetes environment does not have aLoadBalancerimplementation, then it will just behave like aNodePort. An Istio ingress gateway creates aLoadBalancerservice.
What if the Pod that is handling traffic from the NodePort or LoadBalancer isn’t running on the worker node that received the traffic? Kubernetes has its own internal proxy called kube-proxy that receives the packets and forwards them to the correct node.
Source IP address of the original client
If a packet goes through an external proxy load balancer and/or kube-proxy, then the original source IP address of the client is lost. Below are some strategies for preserving the original client IP for logging or security purposes.
For reference, here are the types of load balancers created by Istio with a LoadBalancer service on popular managed Kubernetes environments:
| Cloud Provider | Load Balancer Name | Load Balancer Type |
|---|---|---|
| AWS EKS | Classic Elastic Load Balancer | TCP Proxy |
| GCP GKE | TCP/UDP Network Load Balancer | Network |
| Azure AKS | Azure Load Balancer | Network |
| DO DOKS | Load Balancer | Network |
IP-based allow list and deny list
When to use ipBlocks vs. remoteIpBlocks: If you are using the X-Forwarded-For HTTP header or the Proxy Protocol to determine the original client IP address, then you should use remoteIpBlocks in your AuthorizationPolicy. If you are using externalTrafficPolicy: Local, then you should use ipBlocks in your AuthorizationPolicy.
| Load Balancer Type | Source of Client IP | ipBlocks vs. remoteIpBlocks |
|---|---|---|
| TCP Proxy | Proxy Protocol | remoteIpBlocks |
| Network | packet source address | ipBlocks |
| HTTP/HTTPS | X-Forwarded-For | remoteIpBlocks |
- The following command creates the authorization policy,
ingress-policy, for the Istio ingress gateway. The following policy sets theactionfield toALLOWto allow the IP addresses specified in theipBlocksto access the ingress gateway. IP addresses not in the list will be denied. TheipBlockssupports both single IP address and CIDR notation.
Verify that a request to the ingress gateway is denied:
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 403Update the
ingress-policyto include your client IP address:
Verify that a request to the ingress gateway is allowed:
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200Update the
ingress-policyauthorization policy to set theactionkey toDENYso that the IP addresses specified in theipBlocksare not allowed to access the ingress gateway:
Verify that a request to the ingress gateway is denied:
$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 403You could use an online proxy service to access the ingress gateway using a different client IP to verify the request is allowed.
If you are not getting the responses you expect, view the ingress gateway logs which should show RBAC debugging information:
$ kubectl get pods -n istio-system -o name -l istio=ingressgateway | sed 's|pod/||' | while read -r pod; do kubectl logs "$pod" -n istio-system; done
Clean up
Remove the namespace
foo:$ kubectl delete namespace fooRemove the authorization policy:
$ kubectl delete authorizationpolicy ingress-policy -n istio-system