{"id":21354869,"url":"https://github.com/salrashid123/istio_helloworld","last_synced_at":"2025-07-17T02:38:47.560Z","repository":{"id":91310040,"uuid":"119312401","full_name":"salrashid123/istio_helloworld","owner":"salrashid123","description":"easy walkthrough of basic istio","archived":false,"fork":false,"pushed_at":"2024-11-25T13:10:35.000Z","size":4920,"stargazers_count":77,"open_issues_count":0,"forks_count":24,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-31T10:05:49.513Z","etag":null,"topics":["envoyproxy","google-cloud","google-cloud-platform","istio"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salrashid123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-29T00:44:40.000Z","updated_at":"2024-11-25T13:10:38.000Z","dependencies_parsed_at":"2024-12-24T19:00:37.376Z","dependency_job_id":null,"html_url":"https://github.com/salrashid123/istio_helloworld","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fistio_helloworld","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fistio_helloworld/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fistio_helloworld/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fistio_helloworld/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salrashid123","download_url":"https://codeload.github.com/salrashid123/istio_helloworld/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247640465,"owners_count":20971557,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["envoyproxy","google-cloud","google-cloud-platform","istio"],"created_at":"2024-11-22T04:14:47.333Z","updated_at":"2025-04-07T11:10:17.840Z","avatar_url":"https://github.com/salrashid123.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Istio \"Hello World\" my way\n\n## What is this repo?\n\nThis is a really simple application I wrote over holidays a year ago (12/17) that details my experiences and\nfeedback with istio.  To be clear, its a really basic NodeJS application that i used here but more importantly, it covers\nthe main sections of [Istio](https://istio.io/) that i was seeking to understand better (if even just as a helloworld).  \n\nI do know isito has the \"[bookinfo](https://github.com/istio/istio/tree/master/samples/bookinfo)\" application but the best way\ni understand something is to rewrite sections and only those sections from the ground up.\n\n## Istio version used\n\n* 11/14/24: Istio 1.24.0\n* 04/03/24: Istio 1.21.0\n* 09/05/22: Istio 1.15.0\n* 03/19/21: Istio 1.9.1\n* 12/21/20: Istio 1.8.0\n* 09/22/20: Istio 1.7.2\n* 04/28/20: Istio 1.5.2\n* 10/12/19: Istio 1.3.2\n* 03/10/19:  Istio 1.1.0\n* 01/09/19:  Istio 1.0.5\n* [Prior Istio Versions](https://github.com/salrashid123/istio_helloworld/tags)\n\n\n## What i tested\n\n- [Basic istio Installation on Google Kubernetes Engine](#lets-get-started)\n- [Grafana, Prometheus, Kiali, Jaeger](#setup-some-tunnels-to-each-of-the-services)\n- [Route Control](#route-control)\n- [Canary Deployments with VirtualService](#canary-deployments-with-virtualservice)\n- [Destination Rules](#destination-rules)\n- [Egress Rules](#egress-rules)\n- [Egress Gateway](#egress-gateway)\n- [WebAssembly](#webassembly)\n- [LUA HttpFilter](#lua-httpfilter)\n- [Authorization](#autorization)\n- [JWT Authentication an Authorization](#jwt-auth-autorization)\n- [Service to Service Authentication Policy](service-to-service-rbac-and-authentication-policy)\n- [Internal LoadBalancer (GCP)](#internal-loadbalancer)\n- [Mixer Out of Process Authorization Adapter](https://github.com/salrashid123/istio_custom_auth_adapter)\n- [Access GCE MetadataServer](#access-GCE-metadataServer)\n\nYou can also find info about istio+external authorization server here:\n\n- [Istio External Authorization Server](https://github.com/salrashid123/istio_external_authorization_server)\n\n\n## What is the app you used?\n\nNodeJS in a Dockerfile...something really minimal.  You can find the entire source under the 'nodeapp' folder in this repo.\n\nThe endpoints on this app are as such:\n\n- ```/```:  Does nothing;  ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L24))\n- ```/varz```:  Returns all the environment variables on the current Pod ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L33))\n- ```/version```: Returns just the \"process.env.VER\" variable that was set on the Deployment ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L37))\n- ```/backend```: Return the nodename, pod name.  Designed to only get called as if the applciation running is a `backend` ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L41))\n- ```/hostz```:  Does a DNS SRV lookup for the `backend` and makes an http call to its `/backend`, endpoint ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L45))\n- ```/requestz```:  Makes an HTTP fetch for several external URLs (used to show egress rules) ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L120))\n- ```/headerz```:  Displays inbound headers\n ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L115))\n- ```/remote```: Access `/backend` while deployed in a remote istio cluster  ([source](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L145))\n\nI build and uploaded this app to dockerhub at\n\n```\ndocker.io/salrashid123/istioinit:1\ndocker.io/salrashid123/istioinit:2\n```\n\n(basically, they're both the same application but each has an environment variable that signifies which 'version; they represent.  The version information for each image is returned by the `/version` endpoint)\n\nYou're also free to build and push these images directly:\n\n```bash\ndocker build  --build-arg VER=1 -t your_dockerhub_id/istioinit:1 .\ndocker build  --build-arg VER=2 -t your_dockerhub_id/istioinit:2 .\n\ndocker push your_dockerhub_id/istioinit:1\ndocker push your_dockerhub_id/istioinit:2\n```\n\nTo give you a sense of the differences between a regular GKE specification yaml vs. one modified for istio, you can compare:\n- [all-istio.yaml](all-istio.yaml)  vs [all-gke.yaml](all-gke.yaml)\n(review Ingress config, etc)\n\n## Lets get started\n\n### Create Minikube or GKE Cluster and Bootstrap Istio\n\nUse Minikube locally..its easier but you can't really test the internal loadbalancer excercise.\n\nnote, for GKE, the following cluster is setup with a  [aliasIPs](https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips) (`--enable-ip-alias` )\n\nWe will be installing istio with [istioctl](https://istio.io/docs/setup/install/istioctl/)\n\n```bash\nminikube start --driver=kvm2  --cpus=4 --kubernetes-version=v1.28 --host-only-cidr 192.168.39.1/24\n\nminikube addons enable metallb\n\n## get the IP, for me it was the following\n$ minikube ip\n192.168.39.1\n\n## setup a loadbalancer metallb, enter the ip range shown below\nminikube addons configure metallb\n# -- Enter Load Balancer Start IP: 192.168.39.104\n# -- Enter Load Balancer End IP: 192.168.39.110\n\n### in a new window\nminikube dashboard\n\n\n## for GKE\n# gcloud container  clusters create cluster-1 --machine-type \"n2-standard-4\" --zone us-central1-a  --num-nodes 4  --enable-l4-ilb-subsetting --enable-ip-alias -q\n# gcloud container clusters get-credentials cluster-1 --zone us-central1-a\n# kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)\n\nkubectl create ns istio-system\n\nexport ISTIO_VERSION=1.24.0\nexport ISTIO_VERSION_MINOR=1.24\n\nwget -P /tmp/ https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istio-$ISTIO_VERSION-linux-amd64.tar.gz\ntar xvf /tmp/istio-$ISTIO_VERSION-linux-amd64.tar.gz -C /tmp/\nrm /tmp/istio-$ISTIO_VERSION-linux-amd64.tar.gz\n\nexport PATH=/tmp/istio-$ISTIO_VERSION/bin:$PATH\n\nistioctl install --set profile=demo \\\n --set meshConfig.enableAutoMtls=true  \\\n --set values.gateways.istio-ingressgateway.runAsRoot=true \\\n --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY \\\n --set meshConfig.defaultConfig.gatewayTopology.forwardClientCertDetails=SANITIZE_SET\n\n ### GKE https://github.com/GoogleCloudPlatform/istio-samples/tree/master/internal-load-balancer \n ### add to istioctl command above -f overlay-istio-gateway.yaml\n\n$ istioctl profile dump --config-path components.ingressGateways demo\n$ istioctl profile dump --config-path values.gateways.istio-ingressgateway demo\n\nkubectl apply -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION_MINOR/samples/addons/prometheus.yaml\nsleep 20\nkubectl apply -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION_MINOR/samples/addons/kiali.yaml\nkubectl apply -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION_MINOR/samples/addons/grafana.yaml\nkubectl apply -f https://raw.githubusercontent.com/istio/istio/release-$ISTIO_VERSION_MINOR/samples/addons/jaeger.yaml\n\nkubectl label namespace default istio-injection=enabled\n```\n\nWait maybe 2 to 3 minutes and make sure all the Deployments are live:\n\n- For reference, here are the Istio [operator installation options](https://istio.io/docs/reference/config/istio.operator.v1alpha1/)\n\n### Make sure the Istio installation is ready\n\nVerify this step by making sure all the ```Deployments``` are Available.\n\n```bash\n$  kubectl get no,po,rc,svc,ing,deployment -n istio-system \nNAME            STATUS   ROLES           AGE     VERSION\nnode/minikube   Ready    control-plane   6m55s   v1.28.13\n\nNAME                                        READY   STATUS    RESTARTS   AGE\npod/grafana-6f7c87f789-8ptwb                1/1     Running   0          73s\npod/istio-egressgateway-5686766648-wrpj9    1/1     Running   0          5m44s\npod/istio-ingressgateway-7647b7fcfc-8hxhv   1/1     Running   0          5m43s\npod/istiod-5fbd9b746d-h7mjc                 1/1     Running   0          6m4s\npod/jaeger-6d58dbf847-492js                 1/1     Running   0          72s\npod/kiali-7d57f454c-p7wcf                   1/1     Running   0          74s\npod/prometheus-858b48bf9b-r82nk             2/2     Running   0          95s\n\nNAME                           TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                                                                      AGE\nservice/grafana                ClusterIP      10.107.88.114    \u003cnone\u003e           3000/TCP                                                                     73s\nservice/istio-egressgateway    ClusterIP      10.105.163.55    \u003cnone\u003e           80/TCP,443/TCP                                                               5m44s\nservice/istio-ingressgateway   LoadBalancer   10.101.132.30    192.168.39.104   15021:32216/TCP,80:32466/TCP,443:30304/TCP,31400:30523/TCP,15443:32664/TCP   5m44s\nservice/istiod                 ClusterIP      10.110.231.171   \u003cnone\u003e           15010/TCP,15012/TCP,443/TCP,15014/TCP                                        6m4s\nservice/jaeger-collector       ClusterIP      10.104.227.189   \u003cnone\u003e           14268/TCP,14250/TCP,9411/TCP,4317/TCP,4318/TCP                               72s\nservice/kiali                  ClusterIP      10.108.203.182   \u003cnone\u003e           20001/TCP,9090/TCP                                                           74s\nservice/prometheus             ClusterIP      10.100.159.4     \u003cnone\u003e           9090/TCP                                                                     95s\nservice/tracing                ClusterIP      10.108.168.98    \u003cnone\u003e           80/TCP,16685/TCP                                                             72s\nservice/zipkin                 ClusterIP      10.96.117.238    \u003cnone\u003e           9411/TCP                                                                     72s\n\nNAME                                   READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps/grafana                1/1     1            1           73s\ndeployment.apps/istio-egressgateway    1/1     1            1           5m44s\ndeployment.apps/istio-ingressgateway   1/1     1            1           5m44s\ndeployment.apps/istiod                 1/1     1            1           6m4s\ndeployment.apps/jaeger                 1/1     1            1           72s\ndeployment.apps/kiali                  1/1     1            1           74s\ndeployment.apps/prometheus             1/1     1            1           95s\n```\n\n\n### Make sure the Istio an IP for the ```LoadBalancer``` is assigned:\n\nRun\n\n```bash\n$ kubectl get svc istio-ingressgateway -n istio-system\n\nexport GATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $GATEWAY_IP\n```\n\n\n### Setup some tunnels to each of the services\n\nOpen up several new shell windows and type in one line into each:\n\n```bash\nkubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].metadata.name}') 3000:3000\n\nkubectl port-forward -n istio-system $(kubectl get pod -n istio-system -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 16686:16686\n\nkubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app.kubernetes.io/name=kiali -o jsonpath='{.items[0].metadata.name}') 20001:20001\n```\n\nOpen up a browser (4 tabs) and go to:\n- Kiali http://localhost:20001/kiali (username: admin, password: admin)\n- Grafana http://localhost:3000/dashboards\n- Jaeger http://localhost:16686\n\n\n### Deploy the sample application\n\nThe default `all-istio.yaml` runs:\n\n- Ingress with SSL\n- Deployments:\n- - myapp-v1:  1 replica\n- - myapp-v2:  1 replica\n- - be-v1:  1 replicas\n- - be-v2:  1 replicas\n\nbasically, a default frontend-backend scheme with one replicas for each `v1` and `v2` versions.\n\n\u003e Note: the default yaml pulls and run my dockerhub image- feel free to change this if you want.\n\n\n```bash\nkubectl apply -f all-istio.yaml\nkubectl apply -f istio-lb-certs.yaml\n```\n\nNow enable the ingress gateway for both external and internal loadbalancer traffic on _only_ port `:443`:\n\n```bash\nkubectl apply -f istio-ingress-gateway.yaml -f istio-ingress-ilbgateway.yaml \nkubectl apply -f istio-fev1-bev1.yaml\n```\n\nWait until the deployments complete:\n\n```bash\n\n$ kubectl get po,deployments,svc,ing\n\nNAME                            READY   STATUS    RESTARTS   AGE\npod/be-v1-965f5d5d4-2vb46       2/2     Running   0          85s\npod/be-v2-859c86c476-vfpmp      2/2     Running   0          85s\npod/myapp-v1-f65cf8f46-gvccx    2/2     Running   0          85s\npod/myapp-v2-56f6698cd4-fjh2f   2/2     Running   0          85s\n\nNAME                       READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps/be-v1      1/1     1            1           85s\ndeployment.apps/be-v2      1/1     1            1           85s\ndeployment.apps/myapp-v1   1/1     1            1           85s\ndeployment.apps/myapp-v2   1/1     1            1           85s\n\nNAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE\nservice/be           ClusterIP   10.101.138.254   \u003cnone\u003e        8080/TCP   85s\nservice/kubernetes   ClusterIP   10.96.0.1        \u003cnone\u003e        443/TCP    10m\nservice/myapp        ClusterIP   10.101.150.123   \u003cnone\u003e        8080/TCP   85s\n```\n\nNotice that each pod has two containers:  one is from isto, the other is the applicaiton itself (this is because we have automatic sidecar injection enabled on the `default` namespace).\n\nAlso note that in `all-istio.yaml` we did not define an `Ingress` object though we've defined a TLS secret with a very specific metadata name: `istio-ingressgateway-certs`.  That is a special name for a secret that is used by Istio to setup its own ingress gateway:\n\n\n#### Ingress Gateway Secret in 1.0.0+\n\nNote the `istio-ingress-gateway` secret specifies the Ingress cert to use (the specific metadata name is special and is **required**)\n\n```yaml\napiVersion: v1\ndata:\n  tls.crt: _redacted_\n  tls.key: _redacted_\nkind: Secret\nmetadata:\n  name: istio-ingressgateway-certs\n  namespace: istio-system\ntype: kubernetes.io/tls\n```\n\nRemember we've acquired the ```$GATEWAY_IP``` earlier:\n\n```bash\nexport GATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $GATEWAY_IP\n```\n\nyou may need to restart the ingress pod if the certs they used didn't pickup\n```bash\nINGRESS_POD_NAME=$(kubectl get po -n istio-system | grep ingressgateway\\- | awk '{print$1}'); echo ${INGRESS_POD_NAME};\nkubectl delete po/$INGRESS_POD_NAME -n istio-system\n```\n\n### Send Traffic\n\nThis section shows basic user-\u003efrontend traffic and see the topology and telemetry in the Kiali and Grafana consoles:\n\n#### Frontend only\n\nSo...lets send traffic with the ip to the `/versions`  on the frontend\n\n```bash\nfor i in {1..1000}; do curl  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version; sleep 1; done\n```\n\n\nYou should see a sequence of 1's indicating the version of the frontend you just hit\n\n```\n111111111111111111111111111111111\n```\n\n(source: [/version](https://github.com/salrashid123/istio_helloworld/blob/master/nodeapp/app.js#L37) endpoint)\n\nYou should also see on kiali just traffic from ingress -\u003e `fe:v1`\n\n![alt text](images/kiali_fev1.png)\n\nand in grafana:\n\n![alt text](images/grafana_fev1.png)\n\n\n#### Frontend and Backend\n\nNow the next step in th exercise:\n\nto send requests to `user--\u003efrontend--\u003e backend`;  we'll use the  `/hostz` endpoint to do that.  Remember, the `/hostz` endpoint takes a frontend request, sends it to the backend which inturn echos back the podName the backend runs as.  The entire response is then returned to the user.  This is just a way to show the which backend host processed the requests.\n\n(note i'm using  [jq](https://stedolan.github.io/jq/) utility to parse JSON)\n\n```bash\nfor i in {1..1000}; do curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz | jq '.[0].body'; sleep 1; done\n```\n\nyou should see output indicating traffic from the v1 backend verison: ```be-v1-*```.  Thats what we expect since our original rule sets defines only `fe:v1` and `be:v1` as valid targets.\n\n```bash\n$ for i in {1..1000}; do curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz | jq '.[0].body'; sleep 1; done\n\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n```\n\nNote both Kiali and Grafana shows both frontend and backend service telemetry and traffic to ```be:v1```\n\n![alt text](images/kiali_fev1_bev1.png)\n\n\n![alt text](images/grafana_fev1_bev1.png)\n\n## Route Control\n\nThis section details how to selectively send traffic to specific service versions and control traffic routing.\n\n### Selective Traffic\n\nIn this sequence,  we will setup a routecontrol to:\n\n1. Send all traffic to `myapp:v1`.  \n2. traffic from `myapp:v1` can only go to `be:v2`\n\nBasically, this is a convoluted way to send traffic from `fe:v1`-\u003e `be:v2` even if all services and versions are running.\n\nThe yaml on `istio-fev1-bev2.yaml` would direct inbound traffic for `myapp:v1` to go to `be:v2` based on the `sourceLabels:`.  The snippet for this config is:\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: VirtualService\nmetadata:\n  name: be-virtualservice\nspec:\n  gateways:\n  - mesh\n  hosts:\n  - be\n  http:\n  - match:\n    - sourceLabels:\n        app: myapp\n        version: v1\n    route:\n    - destination:\n        host: be\n        subset: v2\n      weight: 100\n---\napiVersion: networking.istio.io/v1\nkind: DestinationRule\nmetadata:\n  name: be-destination\nspec:\n  host: be\n  trafficPolicy:\n    tls:\n      mode: ISTIO_MUTUAL\n    loadBalancer:\n      simple: ROUND_ROBIN\n  subsets:\n  - name: v1\n    labels:\n      version: v1\n  - name: v2\n    labels:\n      version: v2\n```\n\nSo lets apply the config with kubectl:\n\n```bash\nkubectl replace -f istio-fev1-bev2.yaml\n```\n\nAfter sending traffic,  check which backend system was called by invoking `/hostz` endpoint on the frontend.\n\nWhat the `/hostz` endpoint does is takes a users request to `fe-*` and targets any `be-*` that is valid.  Since we only have `fe-v1` instances running and the fact we setup a rule such that only traffic from `fe:v1` can go to `be:v2`, all the traffic outbound for `be-*` must terminate at a `be-v2`:\n\n```bash\n$ for i in {1..1000}; do curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz | jq '.[0].body'; sleep 1; done\n\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n```\n\nand on the frontend version is always one.\n```bash\nfor i in {1..100}; do curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version; sleep 1; done\n11111111111111111111111111111\n```\n\nNote the traffic to ```be-v1``` is 0 while there is a non-zero traffic to ```be-v2``` from ```fe-v1```:\n\n![alt text](images/kiali_route_fev1_bev2.png)\n\nLook at the incoming requests by source graph:\n\n![alt text](images/grafana_fev1_bev2.png)\n\n\nIf we now overlay rules that direct traffic allow interleaved  ```fe(v1|v2) -\u003e be(v1|v2)``` we expect to see requests to both frontend v1 and backend\n\n```bash\nkubectl replace -f istio-fev1v2-bev1v2.yaml\n```\n\nthen frontend is both v1 and v2:\n```bash\nfor i in {1..1000}; do curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version;  sleep 1; done\n111211112122211121212211122211\n```\n\nand backend is responses comes from both be-v1 and be-v2\n\n```bash\n$ for i in {1..1000}; do curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz | jq '.[0].body'; sleep 1; done\n\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n```\n\n![alt text](images/kiali_route_fev1v2_bev1v2.png)\n\n![alt text](images/grafana_fev1v2_bev1v2.png)\n\n\n### Route Path\n\nNow lets setup a more selective route based on a specific path in the URI:\n\n- The rule we're defining is: \"_First_ route requests to myapp where `path=/version` to only go to the ```v1``` set\"...if there is no match, fall back to the default routes where you send `20%` traffic to `v1` and `80%` traffic to `v2`\n\n\n```yaml\n---\napiVersion: networking.istio.io/v1\nkind: VirtualService\nmetadata:\n  name: myapp-virtualservice\nspec:\n  hosts:\n  - \"*\"\n  gateways:\n  - my-gateway\n  http:\n  - match:\n    - uri:\n        exact: /version\n    route:\n    - destination:\n        host: myapp\n        subset: v1\n  - route:\n    - destination:\n        host: myapp\n        subset: v1\n      weight: 20\n    - destination:\n        host: myapp\n        subset: v2\n      weight: 80\n```\n\n\n```bash\nkubectl replace -f istio-route-version-fev1-bev1v2.yaml\n```\n\nSo check all requests to `/version` are `fe:v1`\n\n```bash\nfor i in {1..1000}; do curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version; sleep 1; done\n1111111111111111111\n```\n\nYou may have noted how the route to any other endpoint other than `/version` destination is weighted split and not delcared round robin (eg:)\n```yaml\n  - route:\n    - destination:\n        host: myapp\n        subset: v1\n      weight: 20\n    - destination:\n        host: myapp\n        subset: v2\n      weight: 80\n```\n\nAnyway, now lets edit rule to  and change the prefix match to `/xversion` so the match *doesn't apply*.   What we expect is a request to http://gateway_ip/version will go to v1 and v2 (since the path rule did not match and the split is the fallback rule.\n\n```bash\nkubectl replace -f istio-route-version-fev1-bev1v2.yaml\n\n```\nObserve the version of the frontend you're hitting:\n\n```bash\nfor i in {1..1000}; do curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version; sleep 1; done\n2121212222222222222221122212211222222222222222\n```\n\nWhat you're seeing is `myapp-v1` now getting about `20%` of the traffic while `myapp-v2` gets `80%` because the previous rule doens't match.\n\nUndo that change `/xversion` --\u003e `/version` and reapply to baseline:\n\n```bash\nkubectl replace -f istio-route-version-fev1-bev1v2.yaml\n```\n\n#### Canary Deployments with VirtualService\n\nYou can use this traffic distribuion mechanism to run canary deployments between released versions.  For example, a rule like the following will split the traffic between `v1|v2` at `80/20` which you can use to gradually roll traffic over to `v2` by applying new percentage weights.\n\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: VirtualService\nmetadata:\n  name: myapp-virtualservice\nspec:\n  hosts:\n  - \"*\"\n  gateways:\n  - my-gateway\n  - my-gateway-ilb\n  http:\n  - route:\n    - destination:\n        host: myapp\n        subset: v1\n      weight: 80\n    - destination:\n        host: myapp\n        subset: v2\n      weight: 20\n```\n### Destination Rules\n\nLets configure Destination rules such that all traffic from `myapp-v1` round-robins to both version of the backend.\n\nFirst lets  force all gateway requests to go to `v1` only:\n\non `istio-fev1-bev1v2.yaml`:\n\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: VirtualService\nmetadata:\n  name: myapp-virtualservice\nspec:\n  hosts:\n  - \"*\"\n  gateways:\n  - my-gateway\n  - my-gateway-ilb\n  http:\n  - route:\n    - destination:\n        host: myapp\n        subset: v1\n```\n\n\nAnd where the backend trffic is split between `be-v1` and `be-v2` with a `ROUND_ROBIN`\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: DestinationRule\nmetadata:\n  name: be-destination\nspec:\n  host: be\n  trafficPolicy:\n    tls:\n      mode: ISTIO_MUTUAL\n    loadBalancer:\n      simple: ROUND_ROBIN\n  subsets:\n  - name: v1\n    labels:\n      version: v1\n  - name: v2\n    labels:\n      version: v2\n```\n\nAfter you apply the rule,\n\n```bash\nkubectl replace -f istio-fev1-bev1v2.yaml\n```\n\nyou'll see frontend request all going to `fe-v1`\n\n```bash\nfor i in {1..1000}; do curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version; sleep 1; done\n11111111111111\n```\n\nwith backend requests coming from _pretty much_ round robin\n\n```bash\n$ for i in {1..1000}; do curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz | jq '.[0].body'; sleep 1; done\n\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n```\n\nNow change the `istio-fev1-bev1v2.yaml`  to `RANDOM` and see response is from v1 and v2 random:\n\n```bash\n$ for i in {1..1000}; do curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz | jq '.[0].body'; sleep 1; done\n\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v2-859c86c476-vfpmp]    node: [minikube]\"\n\"pod: [be-v1-965f5d5d4-2vb46]    node: [minikube]\"\n```\n\n### Internal LoadBalancer (GKE)\n\nThe configuration here  sets up an internal loadbalancer on GCP to access an exposed istio service.\n\nTHis only applies if you set up the `overlay-istio-gateway.yaml` operator during setup for GKE only\n\nThe config settings that enabled this during istio setup was done by an operator and annotation:\n\nSpecifically, we created a new `ingressGateway` and set its annotation to\n`cloud.google.com/load-balancer-type: \"internal\"`\n\n\n```yaml\napiVersion: install.istio.io/v1\nkind: IstioOperator\nspec:\n  components:\n    ingressGateways:\n      - name: istio-ingressgateway\n        enabled: true\n        k8s:\n          service:\n            ports:\n            - name: https\n              port: 443\n              protocol: TCP\n      - name: istio-ilbgateway\n        enabled: true\n        k8s:\n          serviceAnnotations:\n            cloud.google.com/load-balancer-type: \"internal\"\n            networking.gke.io/load-balancer-type: \"Internal\"\n          service:\n            type: LoadBalancer\n            ports:\n            - port: 443\n              name: https\n              protocol: TCP\n```\n\nWe did that duirng setup and later on, attached a Gateway to it which also exposed only `:443`\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: Gateway\nmetadata:\n  name: my-gateway-ilb\nspec:\n  selector:\n    istio: istio-ilbgateway\n  servers:\n  - port:\n      number: 443\n      name: https\n      protocol: HTTPS\n    hosts:\n    - \"*\"    \n    tls:\n      mode: SIMPLE\n      serverCertificate: /etc/istio/ilbgateway-certs/tls.crt\n      privateKey: /etc/istio/ilbgateway-certs/tls.key \n```\n\n\nWe also specified a `VirtualService` which selected these inbound gateways to the `myapp` service:  This configuration was defined when we applied `istio-fev1-bev1.yaml`:\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: VirtualService\nmetadata:\n  name: myapp-virtualservice\nspec:\n  hosts:\n  - \"*\"\n  gateways:\n  - my-gateway\n  - my-gateway-ilb  \n  http:\n  - route:\n    - destination:\n        host: myapp\n        subset: v1\n      weight: 100\n```\n\nNote the `gateways:` entry in the `VirtualService` includes `my-gateway-ilb` which is what defines `host:myapp, subset:v1` as a target for the ILB\n\n```yaml\n  gateways:\n  - my-gateway\n  - my-gateway-ilb\n```\n\nAs mentioned above, we had to _manually_ specify the `port` the ILB will listen on for traffic inbound to this service. \\\n\nFinally, the certficates `Secret` mounted at `/etc/istio/ilbgateway-certs/` was specified this in the initial `all-istio.yaml` file:\n\n```yaml\napiVersion: v1\ndata:\n  tls.crt: LS0tLS1CR...\n  tls.key: LS0tLS1CR...\nkind: Secret\nmetadata:\n  name: istio-ilbgateway-certs\n  namespace: istio-system\ntype: kubernetes.io/tls\n```\n\nNow that the service is setup, acquire the ILB IP allocated\n\n```bash\nexport ILB_GATEWAY_IP=$(kubectl -n istio-system get service istio-ilbgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\necho $ILB_GATEWAY_IP\n```\n\n![images/ilb.png](images/ilb.png)\n\nThen from a GCE VM in the same VPC, send some traffic over on the internal address\n\n```bash\n$ curl -vk https://10.128.0.122/\n\n* ALPN, server accepted to use h2\n* Server certificate:\n*  subject: C=US; ST=California; O=Google; OU=Enterprise; CN=gke.default.svc.cluster.local\n*  start date: Dec 24 18:17:46 2017 GMT\n*  expire date: Jun 11 18:17:46 2020 GMT\n*  issuer: C=US; ST=California; L=Mountain View; O=Google; OU=Enterprise; CN=TestCAforESO\n*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.\n\n\u003e GET / HTTP/2\n\u003e Host: 10.128.0.122\n\u003e User-Agent: curl/7.64.0\n\u003e Accept: */*\n\n\u003c HTTP/2 200 \n\u003c x-powered-by: Express\n\u003c content-type: text/html; charset=utf-8\n\u003c content-length: 19\n\u003c etag: W/\"13-tsbq4e7agwVV6r9iE+Lb/lLwlzw\"\n\u003c date: Tue, 22 Sep 2020 16:24:55 GMT\n\u003c x-envoy-upstream-service-time: 3\n\u003c server: istio-envoy\n\n\nHello from Express!\n```\n\n- The Kiali console should show traffic from both gateways (if you recently sent traffic in externally and internally):\n\n![images/ilb_traffic.png](images/ilb_traffic.png)\n\n### Egress Rules\n\nBy default, istio blocks the cluster from making outbound requests.  There are several options to allow your service to connect externally:\n\n* Egress Rules\n* Egress Gateway\n* Setting `global.proxy.includeIPRanges`\n\nEgress rules prevent outbound calls from the server except with whitelisted addresses.\n\nFor example:\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: ServiceEntry\nmetadata:\n  name: bbc-ext\nspec:\n  hosts:\n  - www.bbc.com\n  ports:\n  - number: 80\n    name: http\n    protocol: HTTP\n  resolution: DNS\n  location: MESH_EXTERNAL\n---\napiVersion: networking.istio.io/v1\nkind: ServiceEntry\nmetadata:\n  name: google-ext\nspec:\n  hosts:\n  - www.google.com\n  ports:\n  - number: 443\n    name: https\n    protocol: HTTPS\n  resolution: DNS\n  location: MESH_EXTERNAL\n---\napiVersion: networking.istio.io/v1\nkind: VirtualService\nmetadata:\n  name: google-ext\nspec:\n  hosts:\n  - www.google.com\n  tls:\n  - match:\n    - port: 443\n      sni_hosts:\n      - www.google.com\n    route:\n    - destination:\n        host: www.google.com\n        port:\n          number: 443\n      weight: 100\n\n```\n\n\nAllows only `http://www.bbc.com/*` and `https://www.google.com/*`\n\nTo test the default policies, the `/requestz` endpoint tries to fetch the following URLs:\n\n```javascript\n    var urls = [\n                'https://www.google.com/robots.txt',\n                'http://www.bbc.com/robots.txt',\n                'http://www.google.com:443/robots.txt',\n                'https://www.cornell.edu/robots.txt',\n                'https://www.uwo.ca/robots.txt',\n                'http://www.yahoo.com/robots.txt'\n    ]\n```\n\nFirst make sure there is an inbound rule already running:\n\n```bash\nkubectl replace -f istio-fev1-bev1.yaml\n```\n\nAnd that you're using `REGISTRY_ONLY`:\n\n```bash\nkubectl get configmap istio -n istio-system -o yaml | grep -o \"mode: REGISTRY_ONLY\"\n```\n\n- Without egress rule, requests will fail:\n\n```bash\ncurl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/requestz | jq  '.'\n```\n\ngives\n\n```bash\n[\n  {\n    \"url\": \"https://www.google.com/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n  },\n  {\n    \"url\": \"http://www.google.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"http://www.bbc.com/robots.txt\",\n    \"body\": \"\",\n    \"statusCode\": 502\n  },\n  {\n    \"url\": \"https://www.cornell.edu/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"https://www.uwo.ca/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n  },\n  {\n    \"url\": \"https://www.yahoo.com/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n  },\n  {\n    \"url\": \"http://www.yahoo.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n]\n\n```\n\n\u003e Note: the `502` response for the `bbc.com` entry is the actual denial rule from the istio-proxy (`502`-\u003eBad Gateway)\n\n\nthen apply the egress policy which allows `www.bbc.com:80` and `www.google.com:443`\n\n```bash\nkubectl apply -f istio-egress-rule.yaml\n```\n\ngives\n\n```bash\ncurl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/requestz | jq  '.'\n```\n\n```bash\n[\n  {\n    \"url\": \"https://www.google.com/robots.txt\",\n    \"statusCode\": 200\n  },\n  {\n    \"url\": \"http://www.google.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"http://www.bbc.com/robots.txt\",\n    \"statusCode\": 200\n  },\n  {\n    \"url\": \"https://www.cornell.edu/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"https://www.uwo.ca/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"https://www.yahoo.com/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"http://www.yahoo.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n]\n\n```\n\nNotice that only one of the hosts worked over SSL worked\n\n### Egress Gateway\n\nTHe egress rule above initiates the proxied connection from each sidecar....but why not initiate the SSL connection from a set of bastion/egress\ngateways we already setup?   THis is where the [Egress Gateway](https://istio.io/docs/examples/advanced-egress/egress-gateway/) configurations come up but inorder to use this:  The following configuration will allow egress traffic for `www.yahoo.com` via the gateway.  See [HTTPS Egress Gateway](https://istio.io/docs/examples/advanced-gateways/egress-gateway/#egress-gateway-for-https-traffic)\n\n\nSo.. lets revert the config we setup above\n\n```bash\nkubectl delete -f istio-egress-rule.yaml\n```\n\nthen lets apply the rule for the gateway:\n\n```bash\nkubectl apply -f istio-egress-gateway.yaml\n```\n\nNotice the gateway TLS mode is `PASSTHROUGH` (\"_Note the PASSTHROUGH TLS mode which instructs the gateway to pass the ingress traffic AS IS, without terminating TLS._\")\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: Gateway\nmetadata:\n  name: istio-egressgateway\nspec:\n  selector:\n    istio: egressgateway\n  servers:\n  - port:\n      number: 443\n      name: tls\n      protocol: TLS\n    hosts:\n    - www.yahoo.com\n    tls:\n      mode: PASSTHROUGH\n```\n\n```bash\ncurl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/requestz | jq  '.'\n```\n\n```bash\n[\n  {\n    \"url\": \"https://www.google.com/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"http://www.google.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"http://www.bbc.com/robots.txt\",\n    \"body\": \"\",\n    \"statusCode\": 502\n  },\n  {\n    \"url\": \"https://www.cornell.edu/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"https://www.uwo.ca/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n  },\n  {\n    \"url\": \"https://www.yahoo.com/robots.txt\",\n    \"statusCode\": 200                  \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n  },\n  {\n    \"url\": \"http://www.yahoo.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n    }\n  }\n]\n\n```\n\n\nYou can also tail the egress gateway logs:\n\n```bash\n$  kubectl logs -f --tail=0  -l istio=egressgateway -n istio-system\n[2020-04-29T15:23:39.949Z] \"- - -\" 0 - \"-\" \"-\" 829 5706 144 - \"-\" \"-\" \"-\" \"-\" \"72.30.35.10:443\" outbound|443||www.yahoo.com 10.12.1.4:57332 10.12.1.4:443 10.12.2.10:41592 www.yahoo.com -\n[2020-04-29T15:23:48.195Z] \"- - -\" 0 - \"-\" \"-\" 829 5722 138 - \"-\" \"-\" \"-\" \"-\" \"98.138.219.231:443\" outbound|443||www.yahoo.com 10.12.1.4:40632 10.12.1.4:443 10.12.2.10:41658 www.yahoo.com -\n```\n\n### TLS Origination for Egress Traffic\n\nIn this mode, traffic exits the pod unencrypted but gets proxied via the gateway for an https destination.  For this to work, traffic must originate from the pod unencrypted but specify the port as an SSL port.  In current case, if you want to send traffic for `https://www.yahoo.com/robots.txt`, emit the request from the pod as `http://www.yahoo.com:443/robots.txt`.  Note the traffic is `http://` and the port is specified: `:443`\n\n\nOk, lets try it out, apply:\n\n```bash\nkubectl apply -f istio-egress-gateway-tls-origin.yaml\n```\n\nThen notice just the last, unencrypted traffic to yahoo succeeds\n\n```bash\n curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/requestz | jq  '.'\n \n[\n  {\n    \"url\": \"https://www.google.com/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n    }\n  },\n  {\n    \"url\": \"http://www.google.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n    }\n  },\n  {\n    \"url\": \"http://www.bbc.com/robots.txt\",\n    \"body\": \"\",\n    \"statusCode\": 502\n  },\n  {\n    \"url\": \"https://www.cornell.edu/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n  },\n  {\n    \"url\": \"https://www.uwo.ca/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n    }\n  },\n  {\n    \"url\": \"http://www.yahoo.com/robots.txt\",\n    \"statusCode\": 200\n  },\n  {\n    \"url\": \"https://www.yahoo.com/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: Client network socket disconnected before secure TLS connection was established\",\n    }\n  },\n  {\n    \"url\": \"http://www.yahoo.com:443/robots.txt\",\n    \"statusCode\": {\n      \"name\": \"RequestError\",\n      \"message\": \"Error: read ECONNRESET\",\n    }\n  }\n]\n\n```\n\n### Bypass Envoy entirely\n\nYou can also configure the `global.proxy.includeIPRanges=` variable to completely bypass the IP ranges for certain serivces.   This setting is described under [Calling external services directly](https://istio.io/docs/tasks/traffic-management/egress/#calling-external-services-directly) and details the ranges that _should_ get covered by the proxy.  For GKE, you need to cover the subnets included and allocated:\n\n\n### Access GCE MetadataServer (GKE only)\n\nThe `/metadata` endpoint access the GCE metadata server and returns the current projectID.  This endpoint makes three separate requests using the three formats I've see GCP client libraries use.  (note: the hostnames are supposed to resolve to the link local IP address shown below)\n\n```javascript\napp.get('/metadata', (request, response) =\u003e {\n\n  var resp_promises = []\n  var urls = [\n              'http://metadata.google.internal/computeMetadata/v1/project/project-id',\n              'http://metadata/computeMetadata/v1/project/project-id',\n              'http://169.254.169.254/computeMetadata/v1/project/project-id'\n  ]\n```\n\nSo if you make an inital request, you'll see `404` errors from Envoy since we did not setup any rules.\n\n```json\n[\n  {\n    \"url\": \"http://metadata.google.internal/computeMetadata/v1/project/project-id\",\n    \"body\": \"\",\n    \"statusCode\": 502\n  },\n  {\n    \"url\": \"http://metadata/computeMetadata/v1/project/project-id\",\n    \"body\": \"\",\n    \"statusCode\": 502\n  },\n  {\n    \"url\": \"http://169.254.169.254/computeMetadata/v1/project/project-id\",\n    \"body\": \"\",\n    \"statusCode\": 502\n  }\n]\n```\n\nSo lets do just that:\n\n```\n  kubectl apply -f istio-egress-rule-metadata.yaml\n```\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: ServiceEntry\nmetadata:\n  name: metadata-ext\nspec:\n  addresses: \n  - 169.254.169.254    \n  hosts:\n  - metadata.google.internal\n  ports:\n  - number: 80\n    name: http\n    protocol: HTTP\n  resolution: STATIC\n  location: MESH_EXTERNAL\n  endpoints:\n  - address: 169.254.169.254\n```\n\nTry it again and you should see \n\n```json\n[\n  {\n    \"url\": \"http://metadata.google.internal/computeMetadata/v1/project/project-id\",\n    \"statusCode\": 200\n  },\n  {\n    \"url\": \"http://metadata/computeMetadata/v1/project/project-id\",\n    \"statusCode\": 502\n  },\n  {\n    \"url\": \"http://169.254.169.254/computeMetadata/v1/project/project-id\",\n    \"statusCode\": 200\n  }\n]\n\n```\n\n### WebAssembly\n\nRef: [Redefining extensibility in proxies - introducing WebAssembly to Envoy and Istio](https://istio.io/blog/2020/wasm-announce/)\n\nThe following steps will deploy a trivial `wasm` module to the cluster that returns `hello world` back as a header.\n\nWe are going to compile and use the main upstream istio envoy example for wasm.  The expected output is a new response header and replaced `location` attribute\n\nsee [envoy_filter_http_wasm_example.cc](https://github.com/istio/envoy/blob/release-1.7/examples/wasm/envoy_filter_http_wasm_example.cc#L56)\n\nTo use this, you need bazel installed and ready to compile a c++ app from scratch\n\n```bash\ngit clone --single-branch --branch  release-1.7 https://github.com/istio/envoy.git\nbazel build examples/wasm:envoy_filter_http_wasm_example.wasm\n```\n\nOnce you have that, upload the binary as a config map called `example-filter`\n\n```bash\nkubectl create cm -n default example-filter  --from-file=`pwd`/bazel-bin/examples/wasm/envoy_filter_http_wasm_example.wasm       \n```\n\nThen direct inte sidecar to use a mounted wasm filter \n\n```bash\nkubectl apply -f fe-v1-wasm-inject.yaml\nkubectl replace -f fe-v1-wasm.yaml\n```\n\nOnce thats done, invoke the frontend:\n\n```bash\n$ curl -v --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/version\n\n\u003e GET /version HTTP/2\n\u003e Host: 34.123.13.130\n\u003e user-agent: curl/7.72.0\n\u003e accept: */*\n\n\u003c HTTP/2 200 \n\u003c x-powered-by: Express\n\u003c content-type: text/html; charset=utf-8\n\u003c content-length: 1\n\u003c etag: W/\"1-NWoZK3kTsExUV00Ywo1G5jlUKKs\"\n\u003c date: Tue, 22 Sep 2020 18:08:35 GMT\n\u003c x-envoy-upstream-service-time: 38\n\u003c newheader: newheadervalue\n\u003c location: envoy-wasm                    \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n\u003c server: istio-envoy                     \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n\u003c \n```\n\nYou'll see the two new headers.\n\nTODO: use `wasme`  cli\n\n### LUA HTTPFilter\n\nThe following will setup a simple Request/Response LUA `EnvoyFilter` for the frontent `myapp`:\n\nThe settings below injects headers in both the request and response streams:\n\n```bash\nkubectl apply -f istio-fev1-httpfilter-lua.yaml\n```\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: EnvoyFilter\nmetadata:\n  name: ui-examplefilter\n  namespace: default\nspec:\n  configPatches:\n  - applyTo: HTTP_FILTER\n    match:\n      context: SIDECAR_INBOUND\n      proxy:\n        proxyVersion: '1\\.9.*'      \n      listener:\n        filterChain:\n          filter:\n            name: envoy.http_connection_manager\n            subFilter:\n              name: envoy.router\n    patch:\n      operation: INSERT_BEFORE\n      value:\n        name: envoy.filters.http.lua\n        typed_config:\n          '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua\n          inlineCode: |\n            function envoy_on_request(request_handle)\n              request_handle:headers():add(\"foo\", \"bar\")\n            end\n            function envoy_on_response(response_handle)\n              response_handle:headers():add(\"foo2\", \"bar2\")\n            end\n  workloadSelector:\n    labels:\n      app: myapp\n      version: v1\n```\n\nNote the response headers back to the caller (`foo2:bar2`) and the echo of the headers as received by the service _from_ envoy (`foo:bar`)\n\n```bash\n$ curl -v --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/headerz \n\n\u003e GET /headerz HTTP/2\n\u003e Host: 35.184.101.110\n\u003e User-Agent: curl/7.60.0\n\u003e Accept: */*\n\n\u003c HTTP/2 200 \n\u003c x-powered-by: Express\n\u003c content-type: application/json; charset=utf-8\n\u003c contLUAent-length: 626\n\u003c etag: W/\"272-vkps3sJOT8NW67CxK6gzGw\"\n\u003c date: Fri, 22 Mar 2019 00:40:36 GMT\n\u003c x-envoy-upstream-service-time: 7\n\u003c foo2: bar2                                                    \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n\u003c server: istio-envoy\n\n{\n  \"host\": \"34.123.13.130\",\n  \"user-agent\": \"curl/7.72.0\",\n  \"accept\": \"*/*\",\n  \"x-forwarded-for\": \"10.128.0.121\",\n  \"x-forwarded-proto\": \"https\",\n  \"x-request-id\": \"52fb996a-2f7a-9352-be5e-025c4328bcae\",\n  \"x-envoy-attempt-count\": \"1\",\n  \"content-length\": \"0\",\n  \"x-envoy-internal\": \"true\",\n  \"x-forwarded-client-cert\": \"By=spiffe://cluster.local/ns/default/sa/myapp-sa;Hash=3cb34c33d650cdc2b9c62ad7d617be39dd778ec34895e03a1a405137a0fcf3f0;Subject=\\\"\\\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account\",\n  \"foo\": \"bar\",                                                      \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n  \"x-b3-traceid\": \"ec14fdbbe9ffd9d0499bc785667ed21f\",\n  \"x-b3-spanid\": \"63d7f435af04f296\",\n  \"x-b3-parentspanid\": \"499bc785667ed21f\",\n  \"x-b3-sampled\": \"1\"\n}\n```\n\nYou can also see the backend request header by running an echo back of those headers\n\n```bash\ncurl -v --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  https://istio.domain.com/hostz\n\n\u003c HTTP/2 200 \n\u003c x-powered-by: Express\n\u003c content-type: application/json; charset=utf-8\n\u003c content-length: 168\n\u003c etag: W/\"a8-+rQK5xf1qR07k9sBV9qawQ\"\n\u003c date: Fri, 22 Mar 2019 00:44:30 GMT\n\u003c x-envoy-upstream-service-time: 33\n\u003c foo2: bar2   \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n\u003c server: istio-envoy\n\n```\n\n### Authorization and Authorization\n\nThe following steps is basically another walkthrough of the [RequestAuthentication](https://istio.io/docs/reference/config/security/request_authentication/) and [AuthorizationPolicy](https://istio.io/docs/reference/config/security/authorization-policy/)\n\n\n#### JWT Authentication and RBAC Authorization\n\nIn this section, we will extend the sample to implement JWT authentication from the client and also use claims within the JWT payload for an enhanced [Service Specific Policy](https://istio.io/docs/tasks/security/authn-policy/#service-specific-policy).\n\nSpecifically, this section will add perimeter [Authentication](https://istio.io/docs/concepts/security/#authentication) that validates a JWT token at ingress gateway and then RBAC policies at the Service level will further restrict requests.\n\nThere are two users: Alice, Bob and two services `svc1`, `svc2`. Alice should be allowed to access _only_ `svc1`, Bob should only access `svc2`.  Both users must present a JWT issued by the same issuer.  In this case, a Self Signed JWT certificate issued by Google.  You can also use Fireabase/Cloud Identity or any other JWT that provides a JWK URL)\n\nThis section involves several steps...first delete any configurations that may still be active.  We need to do this because we will create two _new_ services on the frontend `svc1`, `svc2`\n\n```bash\nkubectl delete -f istio-fev1-httpfilter-lua.yaml\nkubectl delete -f istio-fev1-httpfilter-ext_authz.yaml \nkubectl delete -f istio-fev1-bev1v2.yaml\t\nkubectl delete -f all-istio.yaml\n\n\nkubectl apply -f istio-lb-certs.yaml\nkubectl apply -f istio-ingress-gateway.yaml\nkubectl apply -f istio-ingress-ilbgateway.yaml \n```\n\nYou can verify the configuration that are active by running:\n\n```bash\n$ kubectl get svc,deployments,po,serviceaccounts,serviceentry,VirtualService,DestinationRule,Secret,Gateway\n```\n\nSince the authentication mode described here involes a JWT, we will setup a Google Cloud Service Account the JWT provider.  You are ofcourse free to use any identity provide or even Firebase/[Cloud Identity](https://cloud.google.com/identity/docs/how-to/setup) \n\nFirst redeploy an application that has two frontend services `svc1`, `svc2` accessible using the `Host:` headervalues (`svc1.domain.com` and `svc2.domain.com`)\n\n```bash\ncd auth_rbac_policy/\n\nkubectl apply -f auth-deployment.yaml -f istio-fe-svc1-fe-svc2.yaml\n```\n\nCheck the application still works (it should; we didn't apply policies yet yet)\n\n```bash\n curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP -H \"Host: svc1.example.com\" -w \"\\n\" https://istio.domain.com/version\n```\n\n\nApply the authentication policy that checks for a JWT signed by the service account and audience match on the service.  THe following policy will allow all three audience values through the ingress gateway but only those JWTs that match the audience for the service through at the service level:\n\nTo bootstrap all this, first we need some JWTS.  In this case, we will use GCP serice accounts\n\nTo bootstrap the sample client, go to the Google Cloud Console and download a service account JSON file as described [here](https://cloud.google.com/iam/docs/creating-managing-service-account-keys).  Copy the service account to the `auth_rbac_policy/jwt_cli` folder and save the JSON file as `svc_account.json`.\n\nFirst get the name of the serice account that will sign the JWT:\n\n```bash\nkubectl apply -f auth-policy.yaml\n```\n\nNote that by default we have mTLS and deny by default\n\n```yaml\napiVersion: security.istio.io/v1\nkind: AuthorizationPolicy\nmetadata:\n name: deny-all-authz-ns\nspec:\n  {} \n---\napiVersion: security.istio.io/v1\nkind: PeerAuthentication\nmetadata:\n  name: default-peerauth\n  namespace: default\nspec:\n  mtls:\n    mode: STRICT\n```\n\nmake an api call with a malformed authentication header:\n\n```bash\n$  curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP -H \"Host: svc1.example.com\" -H \"Authorization: Bearer foo\" -w \"\\n\" https://istio.domain.com/version\n\n   Jwt is not in the form of Header.Payload.Signature\n```\n\nnow try without a header entirely:\n\n```bash\n$  curl  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP -H \"Host: svc1.example.com\"  -w \"\\n\" https://istio.domain.com/version\n\n   RBAC: access denied\n```\n\nThe error indicates we did not send in the required header.   In the next setp, we will use a small *sample* client library to acquire a JWT.  You can also use google OIDC tokens or any other provider (Firebase, Auth0)\n\nThe policy above looks for a specific issuer and audience value.  THe `jwksUri` field maps to the public certificate set for a TEST OIDC signer here:\n\n* [https://github.com/salrashid123/diy_oidc](https://github.com/salrashid123/diy_oidc)\n\n\n```bash\nexport URL=\"https://idp-on-cloud-run-3kdezruzua-uc.a.run.app\"\nexport IAT=`date -u +%s`\nexport EXP=`date -u +%s -d \"+3600 seconds\"`\nenvsubst \u003c \"alice.tmpl\" \u003e \"/tmp/alice.json\"\nenvsubst \u003c \"bob.tmpl\" \u003e \"/tmp/bob.json\"\nenvsubst \u003c \"bob_no_groups.tmpl\" \u003e \"/tmp/bob_no_groups.json\"\n\n# simply post the JSON Claims...\nexport TOKEN_ALICE=`curl -s -X POST -d @/tmp/alice.json  $URL/token?kid=rsaKeyID_1`\nexport TOKEN_BOB=`curl -s -X POST -d @/tmp/bob.json  $URL/token?kid=rsaKeyID_1`\nexport TOKEN_BOB_NO_GROUPS=`curl -s -X POST -d @/tmp/bob_no_groups.json  $URL/token?kid=rsaKeyID_1`\n\n\necho $TOKEN_ALICE\necho $TOKEN_BOB\necho $TOKEN_BOB_NO_GROUPS\n```\n\nThe command line utility will generate two tokens with different specifications.  \n\nFor Alice, \n\n```json\n{\n  \"aud\": \"https://svc1.example.com\",\n  \"exp\": 1712160374,\n  \"iat\": 1712156774,\n  \"iss\": \"https://idp-on-cloud-run-3kdezruzua-uc.a.run.app\",\n  \"sub\": \"alice\"\n}\n```\n\nAnd Bob\n```json\n{\n  \"aud\": \"https://svc2.example.com\",\n  \"exp\": 1712160374,\n  \"groups\": [\n    \"group1\",\n    \"group2\"\n  ],\n  \"iat\": 1712156774,\n  \"iss\": \"https://idp-on-cloud-run-3kdezruzua-uc.a.run.app\",\n  \"sub\": \"bob\"\n}\n```\n\nBob, no groups\n```json\n{\n  \"aud\": \"https://svc2.example.com\",\n  \"exp\": 1712160374,\n  \"iat\": 1712156774,\n  \"iss\": \"https://idp-on-cloud-run-3kdezruzua-uc.a.run.app\",\n  \"sub\": \"bob\"\n}\n```\n\n\n\u003e\u003e **WARNING**  the sample code to generate the jwt at the client side uses a service account JWT where the client itself is minting the JWT specifications (meaning it can setup any claimsets it wants, any `sub` field.). In reality, you wouild want to use some other mechanism to acquire a token (Auth0, Firebase Custom Claims, etc).\n\n\nNow inject the token into the `Authorization: Bearer` header and try to access the protected service:\n\n```bash\nfor i in {1..1000}; do curl  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP -H \"Host: svc1.example.com\" -H \"Authorization: Bearer $TOKEN_ALICE\" -w \"\\n\" https://istio.domain.com/version; sleep 1; done\n```\n\nThe request should now pass validation and you're in.  What we just did is have one policy that globally to the ingress-gateway.  Note, we also applied per-service policies in `auth-policy.yaml` that checks for the `aud:` value in the inbound token.\n\nWhat that means is if you use Alice's token to access `svc2`, you'll see an authentication validation error because that token doesn't have `\"https://svc2.example.com\"` in the audience\n\n```bash\n$ curl --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_ALICE\" -w \"\\n\" https://istio.domain.com/version\n\n   Audiences in Jwt are not allowed\n```\n\nIn our example, we had a self-signed JWT locally meaning if the end-user had a service account capable of singing, they coudl setup any audience value (i.,e Alice could create a JWT token with the audience of `svc`).  We need to back up and apply addtional controls through RBAC.\n\n##### Authorization using JWT Claims\n\nThe other way is to push the allow/deny decision down from Authentication to Authorization and then using claims on the Authz polic \n\nIn `auth-policy.yaml`, uncomment  the `AuthorizationPolicy` stanza which does the first check for correct audience value in the inbound token for `svc2` (the one bob uses):\n\n```yaml\napiVersion: security.istio.io/v1\nkind: AuthorizationPolicy\nmetadata:\n name: svc2-az\nspec:\n action: ALLOW  \n selector:\n   matchLabels:\n     app: svc2\n rules:\n - to:\n   - operation:\n       methods: [\"GET\"]  \n   when:\n   - key: request.auth.claims[iss]\n     values: [\"sa-istio@mineral-minutia-820.iam.gserviceaccount.com\"]\n   - key: request.auth.claims[aud]\n     values: [\"https://svc2.example.com\"]\n  #  - key: request.auth.claims[groups]\n  #    values: [\"group1\", \"group2\"]\n   - key: request.auth.claims[sub]\n     values: [\"bob\"]\n```\n\n```bash\nkubectl apply -f auth-policy.yaml\n```\n\nConsider we have two JWT tokens for `Bob`:\n\nOne with groups\n\n```json\n{\n  \"groups\": [\n    \"group1\",\n    \"group2\"\n  ],\n  \"sub\": \"bob\",\n  \"exp\": 1571188782,\n  \"iss\": \"source-service-account@fabled-ray-104117.iam.gserviceaccount.com\",\n  \"iat\": 1571185182,\n  \"aud\": \"https://svc2.example.com\"\n}\n```\n\nAnd one without\n```json\n{\n  \"iss\": \"source-service-account@fabled-ray-104117.iam.gserviceaccount.com\",\n  \"iat\": 1571185734,\n  \"sub\": \"bob\",\n  \"exp\": 1571189334,\n  \"aud\": \"https://svc2.example.com\"\n}\n```\n\nBoth Tokens allow access through to the serivce because they pass authentication (the audience and subject):\n\n```bash\n$ curl -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n    -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_BOB\" -o /dev/null -w \"%{http_code}\\n\"  https://istio.domain.com/version\n\n  200\n\n$ curl -s -s --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n   -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_BOB_NO_GROUPS\" -o /dev/null -w \"%{http_code}\\n\"  https://istio.domain.com/version\n\n  200\n```\n\nBut what we want to do is deny a request if the token does not include the group header (i know, if Bob had the service account file, he could \"just set it\"...anyway)\n\nFor now, edit `auth-policy.yaml` and modify the authorization policy for the backend service to make sure the groups are specified and the groups claims are set\n\n```yaml\n---\napiVersion: security.istio.io/v1\nkind: AuthorizationPolicy\nmetadata:\n name: svc2-az\nspec:\n selector:\n   matchLabels:\n     app: svc2\n rules:\n - to:\n   - operation:\n       methods: [\"GET\"]\n   when:\n   - key: request.auth.claims[iss]\n     values: [\"sa-istio@mineral-minutia-820.iam.gserviceaccount.com\"]\n   - key: request.auth.claims[aud]\n     values: [\"https://svc2.example.com\"]\n   - key: request.auth.claims[groups]\n     values: [\"group1\", \"group2\"]\n   - key: request.auth.claims[sub]\n     values: [\"bob\"]\n```\n\nApply again,\n\n```bash\nkubectl apply -f auth-policy.yaml\n```\n\nWait maybe 30seconds (it takes time for the policy to propagte)\n\nOnce you set that, only Alice should be able to access `svc1` and only Bob access `svc2` except when no group info is provided in the JWT\n\n```bash\n$ curl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP  \\\n    -H \"Host: svc1.example.com\" -H \"Authorization: Bearer $TOKEN_ALICE\"  -w \"%{http_code}\\n\" https://istio.domain.com/version\n\n  200\n\n$ curl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n   -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_ALICE\"   -w \"%{http_code}\\n\" https://istio.domain.com/version\n\n  403\n  Audiences in Jwt are not allowed\n\n$ curl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n   -H \"Host: svc1.example.com\" -H \"Authorization: Bearer $TOKEN_BOB\"   -w \"%{http_code}\\n\" https://istio.domain.com/version\n\n  403\n  Audiences in Jwt are not allowed\n\n$ curl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n   -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_BOB\" -o /dev/null -w \"%{http_code}\\n\" https://istio.domain.com/version\n\n  200\n\n$ curl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n    -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_BOB_NO_GROUPS\" -o /dev/null --w \"%{http_code}\\n\"  https://istio.domain.com/version\n\n  403\n  RBAC: access denied\n```\n\nNotice that bob was only allowed in when the token carried group info.\n\n#### Service to Service and Authentication Policy\n\nIn this section, we extend the working set to allow Alice and Bob to access frontend services and ALSO setup an RBAC policy that allows `svcA` to access `svcB`.\n\n\nWhen we deployed the application, we associated a service account with each workoad\n```yaml\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: svc1-sa\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: svc2-sa\n---\n```\n\nWe can use this service acount to say: 'only allow requests from svc1-sa to access svc2'.  We do this by placing another `AuthorizationPolicy` policy rule in for `svc2`\n\n```yaml\n - from:\n   - source:\n       principals: [\"cluster.local/ns/default/sa/svc1-sa\"] \n```       \n That is, \n\n```yaml\napiVersion: security.istio.io/v1\nkind: AuthorizationPolicy\nmetadata:\n name: svc2-az\nspec:\n selector:\n   matchLabels:\n     app: svc2\n rules:\n - from:\n   - source:\n       principals: [\"cluster.local/ns/default/sa/svc1-sa\"] \n   to:\n   - operation:\n       methods: [\"GET\"]\n   when:\n   - key: request.auth.claims[iss]\n     values: [\"sa-istio@mineral-minutia-820.iam.gserviceaccount.com\"]\n   - key: request.auth.claims[aud]\n     values: [\"https://svc2.example.com\"]\n   - key: request.auth.claims[groups]\n     values: [\"group1\", \"group2\"]\n   - key: request.auth.claims[sub]\n     values: [\"bob\"]\n```\n\nApply again,\n\n```\nkubectl apply -f auth-policy.yaml\n```\n\nNow, if bob tries to access `svc2` externally even with a correct token, he will see\n\n```bash\n$ curl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n   -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_BOB\"  -w \"%{http_code}\\n\" https://istio.domain.com/version\n\n  RBAC: access denied\n```\n\nLet try to exc **into** a pod where `svc1` is running and access `svc2`:\n\n```bash\n$ kubectl get po\nNAME                    READY   STATUS    RESTARTS   AGE\nsvc1-77b6bd69cc-bldf8   2/2     Running   0          29m\nsvc2-bcf6cbd55-hrp25    2/2     Running   0          29m\n\n\n\n$ kubectl exec -ti svc1-77b6bd69cc-bldf8 -- /bin/bash\n```\n\nFirst try to access the backend service:\n\n```bash\ncurl -s -w \"%{http_code}\\n\"  http://svc2.default.svc.cluster.local:8080/version\n403\nRBAC: access denied\n```\n\nYou'll see a 403 because although the request was inbound from `svc1` which is using PEER authentication, we did not add Bob's JWT token.  So set an env-var and execute the request again:\n```\nroot@svc1-7489fbf8d4-8tffm:/# export TOKEN_BOB=eyJhbGciOi...\n\nroot@svc1-7489fbf8d4-8tffm:/# curl -s -w \"%{http_code}\\n\" -H \"Authorization: Bearer $TOKEN_BOB\" http://svc2.default.svc.cluster.local:8080/version\n200\n```\n\nYou are now in!\n\nThis is a bit silly since we needed to use the JWT token for bob for just service to serice traffic.\n\nYou dont' ofcourse need to do that: just edit the `AuthorizationPolicy` for `svc2` and comment out\n\n```yaml\napiVersion: security.istio.io/v1\nkind: AuthorizationPolicy\nmetadata:\n name: svc2-az\nspec:\n action: ALLOW  \n selector:\n   matchLabels:\n     app: svc2\n rules:\n - to:\n   - operation:\n       methods: [\"GET\"]  \n   from:\n   - source:\n       principals: [\"cluster.local/ns/default/sa/svc1-sa\"] \n  #  when:\n  #  - key: request.auth.claims[iss]\n  #    values: [\"sa-istio@mineral-minutia-820.iam.gserviceaccount.com\"]\n  #  - key: request.auth.claims[aud]\n  #    values: [\"https://svc2.example.com\"]\n  #  - key: request.auth.claims[groups]\n  #    values: [\"group1\", \"group2\"]\n  #  - key: request.auth.claims[sub]\n  #    values: [\"bob\"]\n```\nBob can't access `svc2` from the outside but `svc1` can access `svc2`\n\n\n\n```bash\n# apply\n\n$ kubectl apply -f auth-policy.yaml \n\n# from external -\u003e svc1\ncurl -s  --cacert certs/root-ca.crt  --resolve istio.domain.com:443:$GATEWAY_IP \\\n    -H \"Host: svc2.example.com\" -H \"Authorization: Bearer $TOKEN_BOB\"  -w \"%{http_code}\\n\" https://istio.domain.com/version\n\n403\nRBAC: access denied\n\n# from svc1-\u003esvc\ncurl -s -w \"%{http_code}\\n\"  http://svc2.default.svc.cluster.local:8080/version\n200\n```\n\n### External Authorization HTTPFilter\n\nYou can also setup `envoy.ext_authz` Filter in this cluster.  When using the `ext_authz` filter on the frontend service, any request for `app: myapp, version: v1` will undergo an external authorization check by a serivce you run elsewhere.    The external serivice will only allow a request through if it carries `Authorizaton: Bearer foo` in the  header.\n\n\n```yaml\napiVersion: networking.istio.io/v1\nkind: EnvoyFilter\nmetadata:\n  name: ext-authz-filter\nspec:\n  workloadSelector:\n    labels:\n      app: myapp\n      version: v1\n  configPatches:\n    - applyTo: HTTP_FILTER\n      match:\n        proxy:\n          proxyVersion: ^1\\.7.*      \n        context: SIDECAR_INBOUND\n        listener:\n          portNumber: 8080\n          filterChain:\n            filter:\n              name: \"envoy.http_connection_manager\"\n              subFilter:\n                name: \"envoy.router\"\n      patch:\n        operation: INSERT_BEFORE\n        value:\n         name: envoy.filters.http.ext_authz\n         typed_config:\n           \"@type\": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz\n           grpc_service:\n            google_grpc:\n              target_uri: \"your_grpc_server_ip:50051\"\n              stat_prefix: \"ext_authz\"               \n```\n\nTo use this type of authorization check, you will need to run a serivce somewhere (either within istio (*strongly* preferred for latency) or external to istio).  The following runs the serivce external to istio:\n\n- [Istio External Authorization Server](https://github.com/salrashid123/istio_external_authorization_server)\n- [Envoy External Authorization server (envoy.ext_authz) HelloWorld](https://github.com/salrashid123/envoy_external_authz)\n\nFirst spin up a GCP VM that has an external IP, install golang there and startup the `authz` server in the git repo provided.  You'll also need to open up port `:50051` to that VM.  \n\nAfter that, add in the ip address of yoru vm to the yaml file and apply the envoy filter:\n\n```bash\nkubectl apply -f  istio-fev1-httpfilter-ext_authz.yaml\n```\n\nOnce you do that, every request to the fronend service will fail unless the specific header is sent through.\n\n\u003e\u003e Note you'll ofcourse not want to run this serivce anywhere thas externally accessible!...this is just for a demo!!\n\nTHis is what an inbound request from istio to the authorization server may look like:\n\n```bash\n$ go run grpc_server.go\n2020/02/20 20:41:40 Starting gRPC Server at :50051\n2020/02/20 20:42:41 \u003e\u003e\u003e Authorization called check()\n2020/02/20 20:42:41 Inbound Headers:\n2020/02/20 20:42:41 {\n  \":authority\": \"35.238.81.95\",\n  \":method\": \"GET\",\n  \":path\": \"/version\",\n  \"accept\": \"*/*\",\n  \"authorization\": \"Bearer foo\",\n  \"content-length\": \"0\",\n  \"user-agent\": \"curl/7.66.0\",\n  \"x-b3-sampled\": \"0\",\n  \"x-b3-spanid\": \"b228f9e2179794c5\",\n  \"x-b3-traceid\": \"725c448565d59423b228f9e2179794c5\",\n  \"x-envoy-internal\": \"true\",\n  \"x-forwarded-client-cert\": \"By=spiffe://cluster.local/ns/default/sa/myapp-sa;Hash=ae6b57b6ce2932c74b54c40c5e1a7a13daf2828edeb688f9d273a6ea54f38dbf;Subject=\\\"\\\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account\",\n  \"x-forwarded-for\": \"10.128.0.61\",\n  \"x-forwarded-proto\": \"https\",\n  \"x-istio-attributes\": \"CiMKGGRlc3RpbmF0aW9uLnNlcnZpY2UubmFtZRIHEgVteWFwcAoqCh1kZXN0aW5hdGlvbi5zZXJ2aWNlLm5hbWVzcGFjZRIJEgdkZWZhdWx0Ck4KCnNvdXJjZS51aWQSQBI+a3ViZXJuZXRlczovL2lzdGlvLWluZ3Jlc3NnYXRld2F5LTk3ZGNkN2Y4Ny02MnpjZC5pc3Rpby1zeXN0ZW0KPQoYZGVzdGluYXRpb24uc2VydmljZS5ob3N0EiESH215YXBwLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwKOwoXZGVzdGluYXRpb24uc2VydmljZS51aWQSIBIeaXN0aW86Ly9kZWZhdWx0L3NlcnZpY2VzL215YXBw\",\n  \"x-request-id\": \"e7932678-b3a2-40b8-bc49-6b645448ae28\"\n}\n```\n\n\n## Cleanup\n\nThe easiest way to clean up what you did here is to delete the GKE cluster!\n\n```\ngcloud container clusters delete cluster-1\n```\n\n## Conclusion\n\nThe steps i outlined above is just a small set of what Istio has in store.  I'll keep updating this as it move towards ```1.0``` and subsequent releases.\n\nIf you find any are for improvements, please submit a comment or git issue in this [repo](https://github.com/salrashid123/istio_helloworld),.\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fistio_helloworld","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalrashid123%2Fistio_helloworld","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fistio_helloworld/lists"}