Ingress HTTP Example
The example ingress configuration routes traffic to backend services from the
bookinfo
demo microservices app from the Istio project.
Deploy the Demo App
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.11/samples/bookinfo/platform/kube/bookinfo.yaml
This is just deploying the demo app, it’s not adding any Istio components. You can confirm that with Cilium Service Mesh there is no Envoy sidecar created alongside each of the demo app microservices.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-5498c86cf5-kjzkj 1/1 Running 0 2m39s
productpage-v1-65b75f6885-ff59g 1/1 Running 0 2m39s
ratings-v1-b477cf6cf-kv7bh 1/1 Running 0 2m39s
reviews-v1-79d546878f-r5bjz 1/1 Running 0 2m39s
reviews-v2-548c57f459-pld2f 1/1 Running 0 2m39s
reviews-v3-6dd79655b9-nhrnh 1/1 Running 0 2m39s
Note
With the sidecar implementation the output would show 2/2 READY. One for the microservice and one for the Envoy sidecar.
Deploy the First Ingress
You’ll find the example Ingress definition in basic-ingress.yaml
.
# Basic ingress for istio bookinfo demo application, which can be found in below
# https://raw.githubusercontent.com/istio/istio/release-1.11/samples/bookinfo/platform/kube/bookinfo.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: basic-ingress
namespace: default
spec:
ingressClassName: cilium
rules:
- http:
paths:
- backend:
service:
name: details
port:
number: 9080
path: /details
pathType: Prefix
- backend:
service:
name: productpage
port:
number: 9080
path: /
pathType: Prefix
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/basic-ingress.yaml
This example routes requests for the path /details
to the details
service,
and /
to the productpage
service.
Getting the list of services, you’ll see a LoadBalancer service is automatically created for this ingress. Your cloud provider will automatically provision an external IP address, but it may take around 30 seconds.
# For dedicated load balancer mode
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-ingress-basic-ingress LoadBalancer 10.98.169.125 10.98.169.125 80:32478/TCP 2m11s
details ClusterIP 10.102.131.226 <none> 9080/TCP 2m15s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10m
productpage ClusterIP 10.97.231.139 <none> 9080/TCP 2m15s
ratings ClusterIP 10.108.152.42 <none> 9080/TCP 2m15s
reviews ClusterIP 10.111.145.160 <none> 9080/TCP 2m15s
# For shared load balancer mode
$ kubectl get services -n kube-system cilium-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-ingress LoadBalancer 10.98.169.125 10.98.169.125 80:32690/TCP,443:31566/TCP 18m
The external IP address should also be populated into the Ingress:
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
basic-ingress cilium * 10.98.169.125 80 97s
Note
Some providers e.g. EKS use a fully-qualified domain name rather than an IP address.
Make HTTP Requests
Check (with curl
or in your browser) that you can make HTTP requests to that
external address. The /
path takes you to the home page for the bookinfo
application.
From outside the cluster you can also make requests directly to the details
service using the path /details
. But you can’t directly access other URL paths
that weren’t defined in basic-ingress.yaml
.
For example, you can get JSON data from a request to <address>/details/1
and
get back some data, but you will get a 404 error if you make a request to <address>/ratings
.
$ HTTP_INGRESS=$(kubectl get ingress basic-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ curl --fail -s http://"$HTTP_INGRESS"/details/1 | jq
{
"id": 1,
"author": "William Shakespeare",
"year": 1595,
"type": "paperback",
"pages": 200,
"publisher": "PublisherA",
"language": "English",
"ISBN-10": "1234567890",
"ISBN-13": "123-1234567890"
}
Apply Cilium Network Policy
The previous example doesn’t include any network policy, so all the external traffic is allowed by default. Let’s apply network policy to lock down the external traffic.
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
name: "external-lockdown"
spec:
description: "Block all the traffic originating from outside of the cluster"
endpointSelector: {}
ingress:
- fromEntities:
- cluster
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/policy/external-lockdown.yaml
With this policy applied, any request originating from outside the cluster will be rejected with a 403 Forbidden status code:
$ curl --fail -v http://"$HTTP_INGRESS"/details/1
* Trying 172.18.255.194:80...
* Connected to 172.18.255.194 (172.18.255.194) port 80
> GET /details/1 HTTP/1.1
> Host: 172.18.255.194
> User-Agent: curl/8.6.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< content-length: 15
< content-type: text/plain
< date: Thu, 29 Feb 2024 12:59:54 GMT
< server: envoy
* The requested URL returned error: 403
* Closing connection
curl: (22) The requested URL returned error: 403
# Capture hubble flows in another terminal
$ kubectl --namespace=kube-system exec -i -t cilium-xjl4x -- hubble observe -f --identity ingress
Defaulted container "cilium-agent" out of: cilium-agent, config (init), mount-cgroup (init), apply-sysctl-overwrites (init), mount-bpf-fs (init), wait-for-node-init (init), clean-cilium-state (init), install-cni-binaries (init)
Feb 29 13:00:29.389: 172.18.0.1:53866 (ingress) -> kube-system/cilium-ingress:80 (world) http-request DROPPED (HTTP/1.1 GET http://172.18.255.194/details/1)
Feb 29 13:00:29.389: 172.18.0.1:53866 (ingress) <- kube-system/cilium-ingress:80 (world) http-response FORWARDED (HTTP/1.1 403 0ms (GET http://172.18.255.194/details/1))
Let’s check if the in-cluster traffic to Ingress endpoint is still allowed:
# The test-application.yaml contains a client pod with curl available $ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/envoy/test-application.yaml $ kubectl exec -it deployment/client -- curl -s http://$HTTP_INGRESS/details/1 {"id":1,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}%
Another common use case is to allow only a specific set of IP addresses to access the Ingress. This can be achieved via the below policy
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
name: "allow-cidr"
spec:
description: "Allow all the traffic originating from a specific CIDR"
endpointSelector: {}
ingress:
- fromCIDRSet:
# Please update the CIDR to match your environment
- cidr: 172.18.0.1/32
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/policy/allow-ingress-cidr.yaml
$ curl -s --fail http://"$HTTP_INGRESS"/details/1
{"id":1,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}