An example that demonstrates the use of Istio's egress gateway for stable outbound IP connectivity and whitelisting
First, create the GKE cluster:
gcloud beta container clusters create [CLUSTER_NAME] \
--machine-type=n1-standard-2 \
--cluster-version=latest \
--enable-stackdriver-kubernetes --enable-ip-alias \
--scopes cloud-platform
Grab the cluster credentials - you’ll need them for kubectl
commands to work:
gcloud container clusters get-credentials [CLUSTER_NAME]
Make yourself a cluster-admin
so you can install Istio:
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
Grab the latest release of Istio:
curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.2.2 sh -
cd istio-1.2.2
Create the istio-system
namespace:
kubectl create namespace istio-system
Now use helm
to install the Istio CustomResourceDefinitions:
helm template install/kubernetes/helm/istio-init \
--name istio-init \
--namespace istio-system | kubectl apply -f -
Confirm that 23 CRDs we’re in fact installed:
kubectl get crds | grep 'istio.io' | wc -l
Now use helm
to install the Istio control plane components, using the default
installation profile. Note that we’re also installing and configuring the istio-egressgateway
:
helm template install/kubernetes/helm/istio \
--name istio \
--namespace istio-system \
--set gateways.istio-egressgateway.enabled=true \
--set gateways.istio-egressgateway.type=LoadBalancer \
--set kiali.enabled=true \
--set grafana.enabled=true | kubectl apply -f -
Finally, turn on Istio’s auto-injection for the default
namespace so that all Pods deployed to default
get the istio-proxy
automatically injected.
kubectl label ns default istio-injection=enabled
We’ll use the sleep
Istio sample to test connectivity:
kubectl apply -f samples/sleep/sleep.yaml
Now create the target system, in this case a Compute Engine VM running Container-Optimized OS, which is optimized for running Docker containers:
gcloud compute instances create httpbin \
--zone=us-central1-f \
--machine-type=n1-standard-1 \
--subnet=default \
--network-tier=PREMIUM \
--maintenance-policy=MIGRATE \
--scopes=cloud-platform \
--image=cos-stable-75-12105-97-0 \
--image-project=cos-cloud \
--boot-disk-size=10GB \
--boot-disk-type=pd-standard \
--boot-disk-device-name=httpbin \
--tags=vm-egress-gateway-test
Connect to the instance and deploy httpbin
:
gcloud compute ssh httpbin
docker run -p 80:80 -d kennethreitz/httpbin
Deploy the following Istio manifests, which
httpbin
servicehttpbin
to the istio-egressgateway
istio-egressgateway
to the httpbin
VM
kubectl apply -n istio-system -f egress-serviceentry.yaml
kubectl apply -f egress-destinationrule.yaml
kubectl apply -f egress-gateway.yaml
kubectl apply -f egress-virtualservice.yaml
Now send some test traffic to the httpbin
service:
APP_POD=$(kubectl get pods -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it $APP_POD -c sleep -- curl -H "Host: httpbin.gcp.external" 1.2.3.4/ip
First determine which Node has the istio-egressgateway
Pod and note it’s IP:
kubectl get pods -l istio=egressgateway -n istio-system -o jsonpath={.items..status.hostIP}
kubectl get nodes -o wide
Then create a firewall rule to only allow traffic from that Node’s IP:
gcloud compute firewall-rules create httpbin-allow-80-egressgateway \
--description="Allow traffic on tcp:80 only from istio-egressgateway" \
--direction=INGRESS \
--priority=1000 \
--network=default \
--action=ALLOW \
--rules=tcp:80 \
--source-ranges=[SOURCE_NODE_IP_ADDRESS] \
--target-tags=vm-egress-gateway-test
Finally confirm that you can still reach the httpbin
service:
APP_POD=$(kubectl get pods -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it $APP_POD -c sleep -- curl -H "Host: httpbin.gcp.external" 1.2.3.4/ip
This sample uses httpbin.gcp.external
as the hostname of the downstream service. If you examine egress-serviceentry.yaml
you’ll see that the IP of the GCE VM is included there. Due to that configuration, the IP used with curl
is ignored and only the Host
header is examined by Istio.