{"id":13407602,"url":"https://github.com/srinandan/istio-workshop","last_synced_at":"2025-03-14T12:31:16.976Z","repository":{"id":102914523,"uuid":"120063843","full_name":"srinandan/istio-workshop","owner":"srinandan","description":"In this workshop, you'll learn how to install and configure Istio, an open source framework for connecting, securing, and managing microservices, on Google Kubernetes Engine, Google’s hosted Kubernetes product. You will also deploy an Istio-enabled multi-service application","archived":true,"fork":false,"pushed_at":"2019-03-16T05:10:17.000Z","size":5551,"stargazers_count":117,"open_issues_count":4,"forks_count":49,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-07-31T20:27:41.712Z","etag":null,"topics":["api-gateway","api-management","fault-injection","google-cloud","google-kubernetes-engine","istio","istio-workshop","kubernetes","lab","rate-limiting","service-graph","servicemesh","websocket"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","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/srinandan.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}},"created_at":"2018-02-03T05:54:08.000Z","updated_at":"2023-05-31T16:39:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"59a5e2c3-e4d2-45b4-931e-3279c8f36bf3","html_url":"https://github.com/srinandan/istio-workshop","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srinandan%2Fistio-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srinandan%2Fistio-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srinandan%2Fistio-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srinandan%2Fistio-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/srinandan","download_url":"https://codeload.github.com/srinandan/istio-workshop/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243577888,"owners_count":20313714,"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":["api-gateway","api-management","fault-injection","google-cloud","google-kubernetes-engine","istio","istio-workshop","kubernetes","lab","rate-limiting","service-graph","servicemesh","websocket"],"created_at":"2024-07-30T20:00:44.903Z","updated_at":"2025-03-14T12:31:16.202Z","avatar_url":"https://github.com/srinandan.png","language":"Dockerfile","funding_links":[],"categories":["Workshop","Resources"],"sub_categories":["Tutorials"],"readme":"# Istio Service Management and API Management Workshop\n\n\u003cimg src=\"media/istio.png\" align=\"middle\" width=\"150px\"/\u003e\n\n## Summary\n\nIn this lab, you will learn how to install and configure Istio, an open source framework for connecting, securing, and managing microservices, on Google Kubernetes Engine, Google's hosted Kubernetes product. You will also deploy an Istio-enabled multi-service application. Once you complete this lab, you can try managing APIs with Istio and Apigee Edge.\n\n## Table of Contents\n\n1. [Introduction](#introduction)\n2. [Setup and Requirements](#setup-and-requirements)\n3. [Prepare your Kubernetes/GKE cluster](#prepare-your-kubernetes-cluster)\n4. [Installing Istio](#installing-istio)\n5. [Verifying the installation](#verifying-the-installation)\n6. [Deploying an application](#deploying-an-application)\n7. [Use the application](#use-the-application)\n8. [Dynamically change request routing](#dynamically-change-request-routing)\n9. Monitoring and Observability\n   - [View metrics and tracing](#viewing-metrics-and-tracing)\n   - [Monitoring for Istio](#monitoring-for-istio)\n   - [Generating a Service Graph](#generate-graph)\n10. [Fault Injection](#fault-injection)\n11. [Circuit Breaker](#circuit)\n12. [Security](#security)\n    - [Testing Istio mutual TLS authentication](#mutual)\n    - [Testing Istio RBAC](#rbac)\n    - [Testing Istio JWT Policy](#jwt)\n13. [Mesh Expansion](./mesh)\n14. [Multi-Cluster Mesh Expansion](./multi)\n15. [Miscellaneous](./misc)\n    - Websockets\n    - Rate Limiting\n    - Expose external services (egress traffic)\n15. [API Management](./apimanagement)\n    - Installing API Management\n    - Publish the API as a product\n    - Consume an API Product\n    - Obtain an OAuth token\n    - View API Analytics\n    - Expose APIs to third parties\n    - Restrict access to IPs\n16. [Uninstall Istio](#uninstall-istio)\n\n## Introduction \u003ca name=\"introduction\"/\u003e\n\n[Istio](http://istio.io) is an open source framework for connecting, securing, and managing microservices, including services running on Google Kubernetes Engine (GKE). It lets you create a network of deployed services with load balancing, service-to-service authentication, monitoring, and more, without requiring any changes in service code.\n\nYou add Istio support to services by deploying a special Envoy sidecar proxy to each of your application\u0026#39;s pods in your environment that intercepts all network communication between microservices, configured and managed using Istio'\u0026#39;'s control plane functionality.\n\n## Setup and Requirements \u003ca name=\"setup-and-requirements\"/\u003e\n\nIf you don\u0026#39;t already have a Google Account (Gmail or Google Apps), you must [create one](https://accounts.google.com/SignUp). Sign-in to Google Cloud Platform console ( [console.cloud.google.com](http://console.cloud.google.com)) and create a new project:\n ![NewProject1](media/setup-req-0.png)\n ![NewProject2](media/setup-req-1.png)\n ![NewProject3](media/setup-req-4.png)\n\nRemember the project ID, a unique name across all Google Cloud projects (the name above has already been taken and will not work for you, sorry!). It will be referred to later in this codelab as PROJECT\\_ID.\n\nNext, you\u0026#39;ll need to [enable billing](https://console.cloud.google.com/billing) in the Developers Console in order to use Google Cloud resources.\n\nRunning through this codelab shouldn\u0026#39;t cost you more than a few dollars, but it could be more if you decide to use more resources or if you leave them running (see \u0026quot;cleanup\u0026quot; section at the end of this document). Google Kubernetes Engine pricing is documented [here](https://cloud.google.com/kubernetes-engine/docs/#pricing).\n\nNew users of Google Cloud Platform are eligible for a [$300 free trial](https://console.developers.google.com/billing/freetrial?hl=en).\n\n### Enable API\n\nEnable the Kubernetes Engine API:\n1. First click on APIs and Services on the right pane\n![api_services](media/apis_and_services.png)\n\n2. Check if the Kubernetes APIs are enabled\n![checkapis](media/check_enabled.png)\n\n3. If you **CANNOT** find this in your project, then Kubernetes APIs are not enabled. Proceed further. Otherwise skip the following steps.\n\n4. Click on **ENABLE APIS AND SERVICES**\n![enableapiservice](media/enable_apis_services.png)\n\n5. Start typing _**ku**_ in the search bar\n![search](media/search_kub.png) \n\n6. Select _Google Kubernetes Engine API_\n\n7. Enable the API. This step could take 2 or 3 minutes.\n\n![gkeapi](media/enable_api.png)\n\n### Google Cloud Shell\n\nWhile Google Cloud and Kubernetes can be operated remotely from your laptop, in this workshop we will be using Google Cloud Shell, a command line environment running in the Cloud.\n\nThis Debian-based virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory, and runs on the Google Cloud, greatly enhancing network performance and authentication. This means that all you will need for this codelab is a browser (yes, it works on a Chromebook).\n\nTo activate Google Cloud Shell, from the developer console simply click the button on the top right-hand side (it should only take a few moments to provision and connect to the environment):\n\n![NewProject3](media/setup-req-2.png)\n\nThen accept the terms of service and click the \"Start Cloud Shell\" link:\n\n![NewProject3](media/setup-req-3.png)\n\nOnce connected to the cloud shell, you should see that you are already authenticated and that the project is already set to your _PROJECT_ID_\n\n## Prepare your Kubernetes/GKE cluster \u003ca name=\"prepare-your-kubernetes-cluster\"/\u003e\n\nThe requirements for this Istio lab are as follows:\n\n- your cluster should use Kubernetes 1.9.0 or newer, which includes [role-based access control (RBAC)](https://cloud-dot-devsite.googleplex.com/container-engine/docs/role-based-access-control) support.\n- you need to [create your cluster with alpha feature support](https://cloud.google.com/container-engine/docs/alpha-clusters), as Istio makes use of [initializers](https://kubernetes.io/docs/admin/extensible-admission-controllers/#enable-initializers-alpha-feature) to [automatically install the Istio Proxy into every Pod](https://istio.io/docs/setup/kubernetes/sidecar-injection.html#automatic-sidecar-injection)\n\nTo create a new cluster that meets these requirements, including alpha features, run the following commands (this assumes that you have correctly set a zone as indicated in the setup) :\n\n```\n    gcloud container clusters create hello-istio \\\n    --machine-type=n1-standard-2 \\\n    --num-nodes=6 \\\n    --no-enable-legacy-authorization \\\n    --zone=us-west1-b \\\n    --cluster-version=1.11.7-gke.4\n```\n\nSetup Kubernetes CLI Content:\n\n```gcloud container clusters get-credentials hello-istio --zone us-west1-b --project PROJECT_ID```\n\nNow, grant cluster admin permissions to the current user. You need these permissions to create the necessary RBAC rules for Istio.\n\n```\n    kubectl create clusterrolebinding cluster-admin-binding \\\n    --clusterrole=cluster-admin \\\n    --user=$(gcloud config get-value core/account)\n```\n\nIf you navigate in the GCP console to Kubernetes clusters you should see a screen similar to this:\n\n![setupcluster](media/setup-cluster-1.png)\n\n## Installing Istio \u003ca name=\"installing-istio\"/\u003e\n\nNow, let\u0026#39;s install Istio. Istio is installed in its own Kubernetes istio-system namespace, and can manage microservices from all other namespaces. The installation includes Istio core components, tools, and samples.\n\nThe [Istio release page](https://github.com/istio/istio/releases) offers download artifacts for several OSs. In our case, with CloudShell we\u0026#39;ll be using this command to download and extract the latest release automatically:\n\n```curl -L https://git.io/getLatestIstio | sh -```\n\nThe installation directory contains the following:\n\n- Installation .yaml files for Kubernetes in **install/**\n- Sample applications in **samples/**\n- The istioctl client binary in the **bin/** directory. This tool is used when manually injecting Envoy as a sidecar proxy and for creating routing rules and policies.\n- The VERSION configuration file\n\nChange to the istio install directory:\n\n```cd ./istio-* ```\n\nAdd the istioctl client to your PATH:\n\n```export PATH=$PWD/bin:$PATH```\n\nLet\u0026#39;s now install Istio\u0026#39;s core components. We will install the Istio Auth components which enable [**mutual TLS authentication**](https://istio.io/docs/concepts/security/mutual-tls.html) between sidecars:\n\n1. Create the custome resource definitions\n```kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml```\n\n2. Create the helm service account\n```kubectl create -f install/kubernetes/helm/helm-service-account.yaml```\n\n3. Initialize helm\n```helm init --service-account tiller```\n\n4. Render Istio’s core components to a Kubernetes manifest called istio.yaml\n```helm template install/kubernetes/helm/istio --name istio --namespace istio-system \u003e $HOME/istio.yaml```\nNOTE: See here for details on how to install the [helm client](https://docs.helm.sh/using_helm/).\n\n4. Install the components\n```\nkubectl create namespace istio-system\nkubectl apply -f $HOME/istio.yaml\n```\nThis creates the istio-system namespace along with the required RBAC permissions, and deploys Istio-Pilot, Istio-Mixer, Istio-Ingress, Istio-Egress, and Istio-CA (Certificate Authority).\n\n## Verifying the installation \u003ca name=\"verifying-the-installation\"/\u003e\n\nFirst, ensure the following Kubernetes services are deployed: istio-pilot, istio-mixer, istio-ingress, and istio-egress.\n\nRun the command:\n```\nkubectl get svc -n istio-system\n```\nOUTPUT:\n\n```\nNAME            CLUSTER-IP      EXTERNAL-IP       PORT(S)                       AGE\ngrafana                    ClusterIP      10.35.241.104   \u003cnone\u003e           3000/TCP                                                              18m\nistio-citadel              ClusterIP      10.35.252.114   \u003cnone\u003e           8060/TCP,9093/TCP                                                     18m\nistio-egressgateway        ClusterIP      10.35.255.114   \u003cnone\u003e           80/TCP,443/TCP                                                        18m\nistio-galley               ClusterIP      10.35.240.201   \u003cnone\u003e           443/TCP                                                               18m\nistio-ingressgateway       LoadBalancer   10.35.247.245   xx.xxx.xxx.xxx   80:31380/TCP,443:31390/TCP,31400:31400/TCP                            18m\nistio-pilot                ClusterIP      10.35.243.14    \u003cnone\u003e           15003/TCP,15005/TCP,15007/TCP,15010/TCP,15011/TCP,8080/TCP,9093/TCP   18m\nistio-policy               ClusterIP      10.35.251.186   \u003cnone\u003e           9091/TCP,15004/TCP,9093/TCP                                           18m\nistio-sidecar-injector     ClusterIP      10.35.253.208   \u003cnone\u003e           443/TCP                                                               18m\nistio-statsd-prom-bridge   ClusterIP      10.35.254.35    \u003cnone\u003e           9102/TCP,9125/UDP                                                     18m\nistio-telemetry            ClusterIP      10.35.254.188   \u003cnone\u003e           9091/TCP,15004/TCP,9093/TCP,42422/TCP                                 18m\nprometheus                 ClusterIP      10.35.253.203   \u003cnone\u003e           9090/TCP                                                              18m\nservicegraph               ClusterIP      10.35.250.205   \u003cnone\u003e           8088/TCP                                                              18m\ntracing                    ClusterIP      10.35.242.39    \u003cnone\u003e           80/TCP                                                                18m\nzipkin                     ClusterIP      10.35.247.252   \u003cnone\u003e           9411/TCP                                                              18m\n```\n\nThen make sure that the corresponding Kubernetes pods are deployed and all containers are up and running.\n\nRun the command:\n```\nkubectl get pods -n istio-system\n```\nOUTPUT:\n```\nNAME                                READY     STATUS    RESTARTS   AGE\ngrafana-69fc7b47bd-v4qm8                   1/1       Running   0          17m\nistio-citadel-857cf5dc8c-hkdrm             1/1       Running   0          17m\nistio-egressgateway-dbf9c5d7c-87d8s        1/1       Running   0          17m\nistio-galley-6496b645bf-khw6b              1/1       Running   0          17m\nistio-ingressgateway-596bdb588c-zxprt      1/1       Running   0          17m\nistio-pilot-7db88954f4-s26fc               2/2       Running   0          17m\nistio-policy-6bb954c589-9fvqk              2/2       Running   0          17m\nistio-sidecar-injector-57657b649d-vhlmg    1/1       Running   0          17m\nistio-statsd-prom-bridge-59b45fd6d-5n5nd   1/1       Running   0          17m\nistio-telemetry-66bd668dfd-6st47           2/2       Running   0          17m\nistio-tracing-647f8c48f8-fcznc             1/1       Running   0          17m\nprometheus-ffd95f9f6-hz5r4                 1/1       Running   0          17m\nservicegraph-78fddd97cb-9blxc              1/1       Running   0          17m\n```\n\nWhen all the pods are running, you can proceed.\n\n## Deploying an application \u003ca name=\"deploying-an-application\"/\u003e\n\nNow Istio is installed and verified, you can deploy one of the sample applications provided with the installation — [BookInfo](https://istio.io/docs/guides/bookinfo.html). This is a simple mock bookstore application made up of four services that provide a web product page, book details, reviews (with several versions of the review service), and ratings - all managed using Istio.\n\nYou will find the source code and all the other files used in this example in your Istio [samples/bookinfo](https://github.com/istio/istio/tree/master/samples/bookinfo) directory. These steps will deploy the BookInfo application\u0026#39;s services in an Istio-enabled environment, with Envoy sidecar proxies injected alongside each service to provide Istio functionality.\n\n### Overview\nIn this guide we will deploy a simple application that displays information about a book, similar to a single catalog entry of an online book store. Displayed on the page is a description of the book, book details (ISBN, number of pages, and so on), and a few book reviews.\n\nThe BookInfo application is broken into four separate microservices:\n\n* productpage. The productpage microservice calls the details and reviews microservices to populate the page.\n* details. The details microservice contains book information.\n* reviews. The reviews microservice contains book reviews. It also calls the ratings microservice.\n* ratings. The ratings microservice contains book ranking information that accompanies a book review.\n\nThere are 3 versions of the reviews microservice:\n\n* Version v1 doesn’t call the ratings service.\n* Version v2 calls the ratings service, and displays each rating as 1 to 5 black stars.\n* Version v3 calls the ratings service, and displays each rating as 1 to 5 red stars.\n\nThe end-to-end architecture of the application is shown below.\n\n![bookinfo](media/bookinfo.png)\n\n### Deploy Bookinfo\n\nWe deploy our application directly using kubectl create and its regular YAML deployment file. We will inject Envoy containers into your application pods using istioctl:\n\n```kubectl create -f \u003c(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)```\n\nFinally, confirm that the application has been deployed correctly by running the following commands:\n\nRun the command:\n```\nkubectl get services\n```\nOUTPUT:\n```\nNAME                       CLUSTER-IP   EXTERNAL-IP   PORT(S)              AGE\ndetails       ClusterIP   10.35.240.243   \u003cnone\u003e        9080/TCP   14s\nkubernetes    ClusterIP   10.35.240.1     \u003cnone\u003e        443/TCP    14d\nproductpage   ClusterIP   10.35.255.218   \u003cnone\u003e        9080/TCP   14s\nratings       ClusterIP   10.35.244.227   \u003cnone\u003e        9080/TCP   14s\nreviews       ClusterIP   10.35.252.163   \u003cnone\u003e        9080/TCP   14s\n```\n\nRun the command:\n```\nkubectl get pods\n```\n\nOUTPUT:\n```\nNAME                                        READY     STATUS    RESTARTS   AGE\ndetails-v1-568f787b57-ml486       2/2       Running   0          36s\nproductpage-v1-74cc57988f-28nxg   2/2       Running   0          36s\nratings-v1-5bb4b7c645-8xbp8       2/2       Running   0          36s\nreviews-v1-5b95b546f7-cdlww       2/2       Running   0          36s\nreviews-v2-5799c54cb5-ffjv4       2/2       Running   0          36s\nreviews-v3-5df5bd8dfc-9ldnx       2/2       Running   0          36s\n```\n\nWith Envoy sidecars injected along side each service, the architecture will look like this:\n\n![bookinfoistio](media/bookinfo-istio.png)\n\nFinally, expose the service to be consumeable on the ingress\n\n```\ncat \u003c\u003cEOF | kubectl apply -f -\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: bookinfo\n  namespace: default\nspec:\n  gateways:\n  - bookinfo-gateway\n  hosts:\n  - '*'\n  http:\n  - match:\n    - uri:\n        exact: /productpage\n    - uri:\n        exact: /login\n    - uri:\n        exact: /logout\n    - uri:\n        prefix: /api/v1/products\n    route:\n    - destination:\n        host: productpage\n        port:\n          number: 9080\nEOF\n```\n\n```\ncat \u003c\u003cEOF | kubectl apply -f -\napiVersion: networking.istio.io/v1alpha3\nkind: Gateway\nmetadata:\n  name: bookinfo-gateway\nspec:\n  selector:\n    istio: ingressgateway # use istio default controller\n  servers:\n  - port:\n      number: 80\n      name: http\n      protocol: HTTP\n    hosts:\n    - \"*\"\nEOF\n```\n\n\n## Use the application \u003ca name=\"use-the-application\"/\u003e\n\nNow that it\u0026#39;s deployed, let\u0026#39;s see the BookInfo application in action.\n\nFirst you need to get the ingress IP and port, as follows:\n\n```\nkubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' \n```\nOUTPUT:\n```\n35.xxx.xxx.xxx\n```\n\nBased on this information (Address), set the GATEWAY\\_URL environment variable:\n\n```export GATEWAY_URL=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')```\n\nCheck that the BookInfo app is running with curl:\n\nRun the command:\n```\ncurl -o /dev/null -s -w \"%{http_code}\\n\" http://${GATEWAY_URL}/productpage\n```\nOUTPUT:\n```\n200\n```\n\nThen point your browser to _**http://$GATEWAY\\_URL/productpage**_ to view the BookInfo web page. If you refresh the page several times, you should see different versions of reviews shown in the product page, presented in a round robin style (red stars, black stars, no stars), since we haven\u0026#39;t yet used Istio to control the version routing\n\n![Istio](media/use-app-1.png)\n\n## Dynamically change request routing \u003ca name=\"dynamically-change-request-routing\"/\u003e\n\nThe BookInfo sample deploys three versions of the reviews microservice. When you accessed the application several times, you will have noticed that the output sometimes contains star ratings and sometimes it does not. This is because without an explicit default version set, Istio will route requests to all available versions of a service in a random fashion.\n\nWe use the istioctl command line tool to control routing, adding a route rule that says all traffic should go to the v1 service. First, confirm there are no route rules installed :\n\n```istioctl get destinationrules -n default```\n\nNo Resouces will be found. Now, create the rule (check out the source yaml file it you\u0026#39;d like to understand how rules are specified) :\n\nRun the command:\n```\nkubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml -n default\n```\nOUTPUT:\n```\nvirtualservice \"productpage\" created\nvirtualservice \"reviews\" created\nvirtualservice \"ratings\" created\nvirtualservice \"details\" created\ndestinationrule \"productpage\" created\ndestinationrule \"reviews\" created\ndestinationrule \"ratings\" created\ndestinationrule \"details\" created\n```\n\nLook at the rule you\u0026#39;ve just created:\n\n```\nistioctl get destinationrules\n```\nOUTPUT:\n```\nDESTINATION-RULE NAME   HOST          SUBSETS                      NAMESPACE   AGE\ndetails                 details       v1,v2                        default     13s\nproductpage             productpage   v1                           default     13s\nratings                 ratings       v1,v2,v2-mysql,v2-mysql-vm   default     13s\nreviews                 reviews       v1,v2,v3                     default     13s\n```\n\nGo back to the Bookinfo application (http://$GATEWAY\\_URL/productpage) in your browser. You should see the BookInfo application productpage displayed. Notice that the productpage is displayed with no rating stars since reviews:v1 does not access the ratings service.\n\nTo test reviews:v2, but only for a certain user, let\u0026#39;s create this rule:\n\n```\nkubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml -n default\n```\n\nCheck out the route-rule-reviews-test-v2.yaml file to see how this virtual service is specified :\n\n```\n$ cat samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml\n```\nOUTPUT:\n```\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: reviews\nspec:\n  hosts:\n    - reviews\n  http:\n  - match:\n    - headers:\n        cookie:\n          regex: \"^(.*?;)?(user=jason)(;.*)?$\"\n    route:\n    - destination:\n        host: reviews\n        subset: v2\n  - route:\n    - destination:\n        host: reviews\n        subset: v1\n```\n\nLook at the virtual service you\u0026#39;ve just created :\n\n```istioctl get virtualservices reviews -o yaml```\n\nWe now have a way to route some requests to use the reviews:v2 service. Can you guess how? (Hint: no passwords are needed) See how the page behaviour changes if you are logged in as no-one and \u0026#39;jason\u0026#39;.\n\nYou can read the [documentation page](https://istio.io/docs/tasks/traffic-management/request-routing.html) for further details on Istio\u0026#39;s request routing.\n\nOnce the v2 version has been tested to our satisfaction, we could use Istio to send traffic from all users to v2, optionally in a gradual fashion.\n\nFor now, let\u0026#39;s clean up the routing rules:\n\n```\nkubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml -n default\nkubectl delete -f samples/bookinfo/networking/destination-rule-all-mtls.yaml -n default\n```\n\n## View metrics and tracing \u003ca name=\"viewing-metrics-and-tracing\"/\u003e\n\nIstio-enabled applications can be configured to collect trace spans using, for instance, the popular [Jaeger](https://www.jaegertracing.io/docs/) distributed tracing system. Distributed tracing lets you see the flow of requests a user makes through your system, and Istio\u0026#39;s model allows this regardless of what language/framework/platform you use to build your application.\n\nConfigure port forwarding (works on Google Cloud Shell only):\n\n```kubectl port-forward -n istio-system $(kubectl get pod -n istio-system -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 8080:16686 \u0026```\n\nOpen your browser by clicking on \"Preview on port 8080\":\n![Istio](media/preview.png)\n\nLoad the Bookinfo application again (http://$GATEWAY_URL/productpage).\n\nSelect a service  from the list (ex: istio-ingressgateway), and you will now see something similar to the following:\n\n![Istio](media/metrics-1.png)\n\nYou can see how long each microservice call took, including the Istio checks.\n\nYou can read the [documentation page](https://istio.io/docs/tasks/telemetry/distributed-tracing.html) for further details on Istio\u0026#39;s distributed request tracing.\n\nTo stop the port forward, \n```\nctrl + c\n```\nThen bring the process to the foreground\n```\nfg\n```\nThen stop it again\n```\nctrl + c\n```\n\n\n## Monitoring for Istio \u003ca name=\"monitoring-for-istio\"/\u003e\n\nThis task shows you how to setup and use the Istio Dashboard to monitor mesh traffic. As part of this task, you will install the Grafana Istio addon and use the web-based interface for viewing service mesh traffic data.\n\nFirst we install the Grafana addon:\n\n```kubectl apply -f install/kubernetes/addons/grafana.yaml```\n\nGrafana will be used to visualize the data prometheus.\n\nConfigure port forwarding (works on Google shell only):\n\n```kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 8080:3000 \u0026```\n\nOpen your browser by clicking on \"Preview on port 8080\":\n![Istio](media/preview.png)\n\nLoad the Bookinfo application again (http://$GATEWAY_URL/productpage).\n\nSelect a trace from the list, and you will now see something similar to the following:\n\n ![monitoring](media/monitoring-1.png)\n\n To stop the port forward, \n```\nctrl + c\n```\nThen bring the process to the foreground\n```\nfg\n```\nThen stop it again\n```\nctrl + c\n```\n\n## Generating a Service Graph \u003ca name=\"generate-graph\"/\u003e\n \nThis task shows you how to generate a graph of services within an Istio mesh. As part of this task, you will install the ServiceGraph addon and use the web-based interface for viewing service graph of the service mesh.\n\nConfigure port forwarding (works on Google Cloud Shell only):\n\n```kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=servicegraph -o jsonpath='{.items[0].metadata.name}') 8080:8088 \u0026```\n\nOpen your browser by clicking on \"Preview on port 8080\":\n![Istio](media/preview.png)\n\nNOTE: Edit the browser to add `/dotviz` manually. Like this: `https://8080-dot-2997305-dot-devshell.appspot.com/dotviz?authuser=0`\n\nYou will now see something similar to the following:\n\n![servicegraph](media/servicegraph-1.png)\n\nTo stop the port forward, \n```\nctrl + c\n```\nThen bring the process to the foreground\n```\nfg\n```\nThen stop it again\n```\nctrl + c\n```\n\n## Fault Injection \u003ca name=\"fault-injection\"/\u003e\n\n### Fault Injection using HTTP Delay\nThis task shows how to inject delays and test the resiliency of your application.\n\n*_Note: This assumes you don’t have any routes set yet. If you’ve already created conflicting route rules for the sample, you’ll need to use replace rather than create in one or both of the following commands._*\n\nTo test our BookInfo application microservices for resiliency, we will inject a 7s delay between the reviews:v2 and ratings microservices, for user “jason”. Since the reviews:v2 service has a 10s timeout for its calls to the ratings service, we expect the end-to-end flow to continue without any errors.\n\nCreate a fault injection rule to delay traffic coming from user “jason” (our test user)\n\n```\nkubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml\nkubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml\n```\n\nRun the command:\n```\nkubectl apply -f samples/bookinfo/routing/route-rule-ratings-test-delay.yaml\n```\nYou should see the yaml for the routing rule. Allow several seconds to account for rule propagation delay to all pods.\n\n##### Observe application behavior\n\nLog in as user “jason”. If the application’s front page was set to correctly handle delays, we expect it to load within approximately 7 seconds. To see the web page response times, open the Developer Tools menu in IE, Chrome or Firefox (typically, key combination _Ctrl+Shift+I or Alt+Cmd+I_), tab Network, and reload the _productpage_ web page.\n\nYou will see that the webpage loads in about 6 seconds. The reviews section will show _Sorry, product reviews are currently unavailable for this book_.\n\n#### Understanding what happened\nThe reason that the entire reviews service has failed is because our BookInfo application has a bug. The timeout between the productpage and reviews service is less (3s + 1 retry = 6s total) than the timeout between the reviews and ratings service (10s). These kinds of bugs can occur in typical enterprise applications where different teams develop different microservices independently. Istio’s fault injection rules help you identify such anomalies without impacting end users.\n\n**Notice that we are restricting the failure impact to user “jason” only. If you login as any other user, you would not experience any delays**\n\n### Fault Injection using HTTP Abort\nAs another test of resiliency, we will introduce an HTTP abort to the ratings microservices for the user “jason”. We expect the page to load immediately unlike the delay example and display the “product ratings not available” message.\n\nCreate a fault injection rule to send an HTTP abort for user “jason”\n\n```\nkubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml\n```\n\n#### Observe application behavior\n\nLogin as user “jason”. If the rule propagated successfully to all pods, you should see the page load immediately with the “product ratings not available” message. Logout from user “jason” and you should see reviews with rating stars show up successfully on the productpage web page\n\n#### Remove the fault rules\nClean up the fault rules with the command:\n\n```\nkubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml\n```\n## Circuit Breaker \u003ca name=\"circuit\"/\u003e\nThis task demonstrates the circuit-breaking capability for resilient applications. Circuit breaking allows developers to write applications that limit the impact of failures, latency spikes, and other undesirable effects of network peculiarities.\n\n### Define a Destination Rule\nDestinationRule defines policies that apply to traffic intended for a service after routing has occurred. These rules specify configuration for load balancing, connection pool size from the sidecar, and outlier detection settings to detect and evict unhealthy hosts from the load balancing pool.\n\nRun the following command:\n```\ncat \u003c\u003cEOF | istioctl create -f -\napiVersion: networking.istio.io/v1alpha3\nkind: DestinationRule\nmetadata:\n  name: details-breaker\n  namespace: default\nspec:\n  host: details.default.svc.cluster.local\n  trafficPolicy:\n    tls:\n      mode: ISTIO_MUTUAL\n    connectionPool:\n      tcp:\n        maxConnections: 1\n      http:\n        http1MaxPendingRequests: 1\n        maxRequestsPerConnection: 1\n    outlierDetection:\n      http:\n        consecutiveErrors: 1\n        interval: 1s\n        baseEjectionTime: 3m\n        maxEjectionPercent: 100\n```\nThis enables a destination rule that applies a circuit breaker to the details service. \n\n### Setup a Client application\n\nRun the command:\n```\nkubectl apply -f \u003c(istioctl kube-inject -f samples/httpbin/sample-client/fortio-deploy.yaml)\n```\n\nStore the pod name in an env var\n\n```\nexport FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')\n```\n\nGenerate some load\n```\nkubectl exec -it $FORTIO_POD  -c fortio /usr/local/bin/fortio -- load -c 2 -qps 0 -n 20 -loglevel Warning http://details:9080/details/0\n```\nOUTPUT:\n```\nFortio 1.0.1 running at 0 queries per second, 1-\u003e1 procs, for 20 calls: http://details:9080/details/0\nStarting at max qps with 2 thread(s) [gomax 1] for exactly 20 calls (10 per thread + 0)\n05:18:06 W http_client.go:604\u003e Parsed non ok code 503 (HTTP/1.1 503)\n....\nSockets used: 13 (for perfect keepalive, would be 2)\nCode 200 : 8 (40.0 %)\nCode 503 : 12 (60.0 %)\nResponse Header Sizes : count 20 avg 63.3 +/- 77.53 min 0 max 159 sum 1266\nResponse Body/Total Sizes : count 20 avg 264.7 +/- 58.42 min 217 max 337 sum 5294\nAll done 20 calls (plus 0 warmup) 4.333 ms avg, 320.2 qps\n```\n\nOnly 40% of requests made it through, the rest were blocked by the circuit breaker.\n\n### Cleanup\n```\nistioctl delete destinationrule details-breaker\n```\n\n## Security \u003ca name=\"security\"/\u003e\n### Testing Istio mutual TLS authentication \u003ca name=\"mutual\"/\u003e\nThrough this task, you will learn how to:\n* Verify the Istio mutual TLS Authentication setup\n* Manually test the authentication\n#### Verifying Istio CA\nVerify the cluster-level CA is running:\n\n```\nkubectl get deploy -l istio=citadel -n istio-system\n```\nOUTPUT:\n```\nNAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE\nistio-citadel   1         1         1            1           3h\n```\n#### Verify Service Configuration \nCheck installation mode. If mutual TLS is enabled by default (e.g istio-demo-auth.yaml was used when installing Istio), you can expect to see uncommented \n```\nkubectl get destinationrules.networking.istio.io --all-namespaces -o yaml\n```\n\n#### Enable mTLS on all services\nNOTE 1: Starting Istio 0.8, enabling mTLS is controlled through the authentication policy.\nNOTE 2: A policy with no targets (i.e., apply to all targets in namespace) must be named `default`\n\nTo enable mTLS all services deployed in the default namesapce,\n```\ncat \u003c\u003cEOF | istioctl create -f -\napiVersion: authentication.istio.io/v1alpha1\nkind: Policy\nmetadata:\n  name: default\n  namespace: default\nspec:\n  peers:\n  - mtls:\nEOF\n```\n\n#### Testing the authentication setup\nWe are going to install a sample application into the cluster and try and access the services directly.\n\n1. Switch to the sample app folder\n```\ngit clone https://github.com/srinandan/istio-workshop.git \u0026\u0026 cd istio-workshop/mtlstest\n```\n\n2. Set the PROJECT_ID as the environment variable\n```\nexport PROJECT_ID=$(gcloud info --format='value(config.project)')\n```\n\n3. Edit the Kubernetes configuration file (mtlstest.yaml) and add the PROJECT_ID\n```\nvi mtlstest.yaml\n```\n\nchange this and add the project id:\n```\nimage: gcr.io/PROJECT_ID/mtlstest:latest\n```\nsave the file.\n\n4. Build the docker image and push it to GCR (Google Container Repo)\n```\n./dockerbuild.sh\n```\nNOTE: you may have to run \"chmod +x dockerbuild.sh\"\n\n5. Deploy the app to Kubernetes\n```\n./k8ssetup.sh\n```\n\n6. Verify the application was deployed successfully\n```\nkubectl get pods\n```\n\nOUTPUT:\n```\nNAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE\ndetails       ClusterIP   10.59.254.1     \u003cnone\u003e        9080/TCP   12m\nkubernetes    ClusterIP   10.59.240.1     \u003cnone\u003e        443/TCP    18m\nmtlstest      ClusterIP   10.59.253.170   \u003cnone\u003e        8080/TCP   7m\nproductpage   ClusterIP   10.59.251.133   \u003cnone\u003e        9080/TCP   12m\nratings       ClusterIP   10.59.251.105   \u003cnone\u003e        9080/TCP   12m\nreviews       ClusterIP   10.59.250.46    \u003cnone\u003e        9080/TCP   12m\n```\nNOTE: The cluster IP for the **details** app. This app is running on port 9080\n\n7. Access the mtltest pod\n```\nkubectl exec -it mtlstest-bbf7bd6c-9rmwn /bin/bash\n```\n\n8. Run cURL to access to the details app\n```\ncurl -k -v https://details:9080/details/0\n```\n\nOUTPUT:\n```\n*   Trying 10.35.255.72...\n* TCP_NODELAY set\n* Connected to details (10.35.255.72) port 9080 (#0)\n* ALPN, offering h2\n* ALPN, offering http/1.1\n* successfully set certificate verify locations:\n*   CAfile: /etc/ssl/certs/ca-certificates.crt\n  CApath: /etc/ssl/certs\n* TLSv1.2 (OUT), TLS handshake, Client hello (1):\n* error:1408F10B:SSL routines:ssl3_get_record:wrong version number\n* Closing connection 0\ncurl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number\n```\n**NOTE**: If security (mTLS) was **NOT** enabled on the services, you would have see the output (status 200)\n#### Accessing the Service\n\nWe are now going to access the service with the appropriate keys and certs.\n\n1. Get the CA Root Cert, Certificate and Key from Kubernetes secrets\n```\nkubectl get secret istio.default -o jsonpath='{.data.root-cert\\.pem}' | base64 --decode \u003e root-cert.pem\nkubectl get secret istio.default -o jsonpath='{.data.cert-chain\\.pem}' | base64 --decode \u003e cert-chain.pem\nkubectl get secret istio.default -o jsonpath='{.data.key\\.pem}' | base64 --decode \u003e key.pem\n```\n\n2. Copy the files to the mtlstest POD\n```\nkubectl cp root-cert.pem mtlstest-854c4c9b85-gwr82:/tmp -c mtlstest\nkubectl cp cert-chain.pem mtlstest-854c4c9b85-gwr82:/tmp -c mtlstest\nkubectl cp key.pem mtlstest-854c4c9b85-gwr82:/tmp -c mtlstest\n```\n\n3. Start a bash to the mtlstest POD\n```\nkubectl get pods\n```\nOUTPUT:\n```\nNAME                              READY     STATUS    RESTARTS   AGE\ndetails-v1-845458947b-4xt2j       2/2       Running   0          5h\nmtlstest-bbf7bd6c-gfpjk           2/2       Running   0          45m\nproductpage-v1-54d4776d48-z8xxv   2/2       Running   0          5h\n```\n\n```\nkubectl exec -it mtlstest-854c4c9b85-gwr82 /bin/bash\n```\n\n4. Move the PEM files to the appropriate folder (/etc/certs - which is the default folder)\n```\nmkdir /etc/certs\n```\n```\nmv /tmp/*.pem /etc/certs/\n```\n\n5. Access the application\n```\ncurl -v http://details:9080/details/0\n```\nOUTPUT:\n```\n*   Trying 10.35.255.72...\n* TCP_NODELAY set\n* Connected to details (10.35.255.72) port 9080 (#0)\n\u003e GET /details/0 HTTP/1.1\n\u003e Host: details:9080\n\u003e User-Agent: curl/7.58.0\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 200 OK\n\u003c content-type: application/json\n\u003c server: envoy\n\u003c date: Mon, 25 Jun 2018 03:50:17 GMT\n\u003c content-length: 178\n\u003c x-envoy-upstream-service-time: 19\n\u003c\n* Connection #0 to host details left intact\n{\"id\":0,\"author\":\"William Shakespeare\",\"year\":1595,\"type\":\"paperback\",\"pages\":200,\"publisher\":\"PublisherA\",\"language\":\"English\",\"ISBN-10\":\"1234567890\",\"ISBN-13\":\"123-1234567890\"}root@mtlstest-854c4c9b85-gwr82:/tmp\n```\n**NOTE**: \n1. You didn't have to specify _https_ when accessing the service.\n2. Envoy automatically established mTLS between the consumer (mtlstest) and the provider (details) \n\n#### Preventing Unauthorized access\nWe saw how an application (mtlstest) was able access the service with the necessary key and cert. Istio also helps you prevent such access. In the application we have, the _details_ application must only be accessed by the _productpage_ application. \n\nWe are first going to create a service account for the _productpage_ application. For more information about service accounts, please refer [here](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/). Run the command:\n\n```\nkubectl apply -f \u003c(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo-add-serviceaccount.yaml)\n```\n\nOutput:\n```\nserviceaccount \"bookinfo-productpage\" created\ndeployment \"productpage-v1\" configured\nserviceaccount \"bookinfo-reviews\" created\ndeployment \"reviews-v2\" configured\ndeployment \"reviews-v3\" configured\n```\n\nWe are now going to deploy a mixer rule that denies access to other services (services that are not _productpage_). Review this snippet:\n\n```\nspec:\n  match: destination.labels[\"app\"] == \"details\" \u0026\u0026 source.user != \"cluster.local/ns/default/sa/bookinfo-productpage\"\n  actions:\n  - handler: denyproductpagehandler.denier\n    instances: [ denyproductpagerequest.checknothing ]\n```\nThe match string says if the target/destination service is _details_ and the source (service account) is not productpage, then deny access. The term _source.user_ is automatically populated by Envoy during the mTLS handshake. It is the identity of the immediate sender of the request, authenticated by mTLS. Therefore we can trust the value contained within it. \n\n\n```\ncat \u003c\u003c EOF | kubectl create -f - \napiVersion: \"config.istio.io/v1alpha2\"\nkind: denier\nmetadata:\n  name: denyproductpagehandler\nspec:\n  status:\n    code: 7\n    message: Not allowed\n---\napiVersion: \"config.istio.io/v1alpha2\"\nkind: checknothing\nmetadata:\n  name: denyproductpagerequest\nspec:\n---\napiVersion: \"config.istio.io/v1alpha2\"\nkind: rule\nmetadata:\n  name: denyproductpage\nspec:\n  match: destination.labels[\"app\"] == \"details\" \u0026\u0026 source.user != \"cluster.local/ns/default/sa/bookinfo-productpage\"\n  actions:\n  - handler: denyproductpagehandler.denier\n    instances: [ denyproductpagerequest.checknothing ]\nEOF\n```\nOutput:\n```\nCreated config denier/default/denyproductpagehandler at revision 32311\nCreated config checknothing/default/denyproductpagerequest at revision 32312\nCreated config rule/default/denyproductpage at revision 32313\n``` \n\nNow, try to access the service again.\n\n```\nkubectl exec -it mtlstest-bbf7bd6c-gfpjk /bin/bash\n```\n\n```\ncurl -v http://details:9080/details/0\n```\nOutput:\n```\n*   Trying 10.35.255.72...\n* TCP_NODELAY set\n* Connected to details (10.35.255.72) port 9080 (#0)\n\u003e GET /details/0 HTTP/1.1\n\u003e Host: details:9080\n\u003e User-Agent: curl/7.58.0\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 403 Forbidden\n\u003c content-length: 67\n\u003c content-type: text/plain\n\u003c date: Mon, 25 Jun 2018 04:06:05 GMT\n\u003c server: envoy\n\u003c x-envoy-upstream-service-time: 5\n\u003c\n* Connection #0 to host details left intact\nPERMISSION_DENIED:denyproductpagehandler.denier.default:Not allowed\n```\n\n### Further Reading\nLearn more about the design principles behind Istio’s automatic mTLS authentication between all services in this [blog](https://istio.io/blog/istio-auth-for-microservices.html)\n\n### Testing Istio RBAC \u003ca name=\"rbac\"/\u003e\nIstio Role-Based Access Control (RBAC) provides namespace-level, service-level, method-level access control for services in the Istio Mesh. It features:\n* Role-Based semantics, which is simple and easy to use.\n* Service-to-service and endUser-to-Service authorization.\n* Flexibility through custom properties support in roles and role-bindings.\n\nIn this part of the lab, we will create a service role  that gives read only access to a certain set of services. First we enable RBAC.\n```\nistioctl create -f samples/bookinfo/platform/kube/istio-rbac-enable.yaml\n```\nOUTPUT:\n```\nCreated config authorization/istio-system/requestcontext at revision 197480\nCreated config rbac/istio-system/handler at revision 197481\nCreated config rule/istio-system/rbaccheck at revision 197482\n```\n\nNow, create a service role and service role binding\n```\napiVersion: \"config.istio.io/v1alpha2\"\nkind: ServiceRole\nmetadata:\n  name: service-viewer\n  namespace: default\nspec:\n  rules:\n  - services: [\"*\"]\n    methods: [\"GET\"]\n    constraints:\n    - key: \"app\"\n      values: [\"productpage\", \"details\", \"reviews\", \"ratings\", \"mtlstest\"]\n```\n\nThis service role allows only the GET operation on all the services listed in `values`. Deploy the rule\n\n```\nistioctl create -f samples/bookinfo/platform/kube/istio-rbac-namespace.yaml\n```\n\nOUTPUT:\n```\nCreated config service-role/default/service-viewer at revision 196402\nCreated config service-role-binding/default/bind-service-viewer at revision 196403\n```\n\nAccess the mtlstest POD\n```\nkubectl exec -it mtlstest-854c4c9b85-gwr82 /bin/bash\n```\n\nTry to access the application\n```\ncurl -v http://details:9080/details/0\n```\n\nThis should work successfully because we did not block GET calls. Now let's try to create/POST\n```\ncurl -v http://details:9080/details/0 -X POST -d '{}'\n```\n\nOUTPUT:\n```\nNote: Unnecessary use of -X or --request, POST is already inferred.\n*   Trying 10.35.255.72...\n* TCP_NODELAY set\n* Connected to details (10.35.255.72) port 9080 (#0)\n\u003e POST /details/0 HTTP/1.1\n\u003e Host: details:9080\n\u003e User-Agent: curl/7.58.0\n\u003e Accept: */*\n\u003e Content-Length: 2\n\u003e Content-Type: application/x-www-form-urlencoded\n\u003e\n* upload completely sent off: 2 out of 2 bytes\n\u003c HTTP/1.1 403 Forbidden\n\u003c content-length: 68\n\u003c content-type: text/plain\n\u003c date: Tue, 26 Jun 2018 05:39:51 GMT\n\u003c server: envoy\n\u003c x-envoy-upstream-service-time: 7\n\u003c\n* Connection #0 to host details left intact\nPERMISSION_DENIED:handler.rbac.istio-system:RBAC: permission denied.\n```\n\nThe create/POST failed. You can learn more about Istio RBAC [here](https://istio.io/docs/concepts/security/rbac/)\n\nDelete RBAC resources\n\n```\nistioctl delete -f rbac/istio-rbac-namespace.yaml\nistioctl delete -f samples/bookinfo/kube/istio-rbac-enable.yaml\n```\n\n### Testing Istio JWT Policy \u003ca name=\"jwt\"/\u003e\nThrough this task, you will learn how to enable JWT validation on specific services in the mesh.\n\n#### Scenario\nLet's assume you want to expose the details API outside the service mesh (available on the ingress). To do this, first we look at the virtual service\n\n```\nistioctl get virtualservices bookinfo -o yaml \u003e bookinfo.yaml\n```\n\nEdit the file to expose the details service\n```\n.....\n    route:\n    - destination:\n        host: productpage\n        port:\n          number: 9080\n  - match:\n    - uri:\n        prefix: /details\n    route:\n    - destination:\n        host: details\n        port:\n           number: 9080\n        subset: v1\n```\n\nDeploy the virtual service\n\n```\nkubectl apply -f bookinfo.yaml\n```\nTest access to the service.\n```\ncurl GATEWAY_URL/details/0 \n```\n\nOUTPUT:\n```\n{\"id\":0,\"author\":\"William Shakespeare\",\"year\":1595,\"type\":\"paperback\",\"pages\":200,\"publisher\":\"PublisherA\",\"language\":\"English\",\"ISBN-10\":\"1234567890\",\"ISBN-13\":\"123-1234567890\"}\n```\nAlright, so now we can access this API. But, we have just opened the API to everyone. It is not always possible to use mTLS to protect traffic exposed on the ingress. Using a JWT policy at the ingress works great in such cases.\n\n#### Enable JWT Policy\nIn this step we will enable the JWT policy on the details service. Take a look at the details-jwt.yaml file. \n\nThe first section is defining how to enable the JWT\n```\napiVersion: \"authentication.istio.io/v1alpha1\"\nkind: Policy\nmetadata:\n  name: details-auth-spec\n  namespace: default\nspec:\n  targets:\n  - name: details\n  peers:\n  - mtls:\n  origins:\n  - jwt:\n      issuer: https://amer-demo13-test.apigee.net/istio-auth/token\n      jwks_uri: https://amer-demo13-test.apigee.net/istio-auth/certs\n  principalBinding: USE_ORIGIN\n```\nThere are two critical pieces here:\n* The _Issuer_, every JWT token must match the issuer specified here\n* The _jwks_url_, this is an endpoint to where [JSON Web Key](https://tools.ietf.org/html/rfc7517) based public keys are hosted. Here is an [example](https://www.googleapis.com/oauth2/v2/certs) from Google. These public keys are used to verify the JWT.\n\nNow, apply the policy\n\n```\nkubectl apply -f jwttest/details-jwt.yaml\n```\n\nOUTPUT:\n```\npolicy \"details-auth-spec\" created\n```\n\nNow let's try and access the API from the ingress.\n```\ncurl -v http://$GATEWAY_URL/details/0\n```\n\nOUTPUT:\n```\n*   Trying 35.227.168.43...\n* TCP_NODELAY set\n* Connected to 35.227.168.43 (35.227.168.43) port 80 (#0)\n\u003e GET /details/0 HTTP/1.1\n\u003e Host: 35.227.168.43\n\u003e User-Agent: curl/7.52.1\n\u003e Accept: */*\n\u003e\n\u003c HTTP/1.1 401 Unauthorized\n\u003c content-length: 29\n\u003c content-type: text/plain\n\u003c date: Mon, 25 Jun 2018 16:04:56 GMT\n\u003c server: envoy\n\u003c x-envoy-upstream-service-time: 1\n\u003c\n* Curl_http_done: called premature == 0\n* Connection #0 to host 35.227.168.43 left intact\nOrigin authentication failed.\n```\nThis is expected, we did not pass a JWT token. It is left to the reader on how to obtain a JWT and pass it in the header.\n\n## API Management \u003ca name=\"apim\"/\u003e\nTo see how you can manage your APIs, take a look at this next section [API Management for Istio](./apimanagement/README.md)\n\n## Uninstall Istio \u003ca name=\"uninstall-istio\"/\u003e\n\nHere\u0026#39;s how to uninstall Istio.\n\n```\nkubectl delete -f bookinfo/platform/kube/bookinfo.yaml\n```\nOUTPUT:\n```\nservice    'details'    deleted\ndeployment 'details-v1' deleted\nservice    'ratings'    deleted\ndeployment 'ratings-v1' deleted\nservice    'reviews'    deleted\ndeployment 'reviews-v1' deleted\ndeployment 'reviews-v2' deleted\ndeployment 'reviews-v3' deleted\nservice    'productpage' deleted\ndeployment 'productpage-v1' deleted\n```\n \n```kubectl delete -f $HOME/istio.yaml```\n\nIn addition to uninstalling Istio, you should also delete the Kubernetes cluster created in the setup phase (to save on cost and to be a good cloud citizen):\n\n```gcloud container clusters delete hello-istio``` \n\nOUTPUT\n```\nThe following clusters will be deleted. - [hello-istio] in [west1-b]\nDo you want to continue (Y/n)?  Y\nDeleting cluster hello-istio...done.\n\n[https://container.googleapis.com/v1/projects/codelab-test/zones/us-central1-f/clusters/hello-istio].\n```\n\nOf course, you can also delete the entire project but you would lose any billing setup you have done (disabling project billing first is required). Additionally, deleting a project will only stop all billing after the current billing cycle ends.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrinandan%2Fistio-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsrinandan%2Fistio-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrinandan%2Fistio-workshop/lists"}