├── LICENSE ├── README.md ├── apigee ├── .DS_Store ├── details.zip └── importproxy.sh ├── apimanagement └── README.md ├── jwttest └── details-jwt.yaml ├── media ├── .DS_Store ├── New-product.png ├── analytics.png ├── apis_and_services.png ├── app-details.png ├── apps.png ├── bookinfo-istio.png ├── bookinfo.png ├── check_enabled.png ├── create-instance.png ├── credentials.png ├── enable_api.png ├── enable_apis_services.png ├── istio.png ├── login.png ├── metrics-1.png ├── metrics-2.png ├── monitoring-1.png ├── new-app.png ├── preview.png ├── product-details.png ├── product.png ├── publish.png ├── search_kub.png ├── servicegraph-1.png ├── setup-cluster-1.png ├── setup-req-0.png ├── setup-req-1.png ├── setup-req-2.png ├── setup-req-3.png ├── setup-req-4.png └── use-app-1.png ├── mesh └── README.md ├── misc ├── README.md ├── media │ ├── devtools-cmds.png │ ├── hello-websocket.png │ ├── open-devtools.png │ └── websockets-apikey.png └── websocket │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── dockerbuild.sh │ ├── dockerpush.sh │ ├── dockerrun.sh │ ├── index.html │ ├── src │ └── main.go │ ├── websockets-api.yaml │ ├── websockets-rule.yaml │ └── websockets.yaml ├── mtlstest ├── Dockerfile ├── bookinfo-add-serviceaccount.yaml ├── dockerbuild.sh ├── k8ssetup.sh ├── mixer-rule-deny-others.yaml └── mtlstest.yaml ├── multi └── README.md └── rbac └── istio-rbac-namespace.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Istio Service Management and API Management Workshop 2 | 3 | 4 | 5 | ## Summary 6 | 7 | In 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. 8 | 9 | ## Table of Contents 10 | 11 | 1. [Introduction](#introduction) 12 | 2. [Setup and Requirements](#setup-and-requirements) 13 | 3. [Prepare your Kubernetes/GKE cluster](#prepare-your-kubernetes-cluster) 14 | 4. [Installing Istio](#installing-istio) 15 | 5. [Verifying the installation](#verifying-the-installation) 16 | 6. [Deploying an application](#deploying-an-application) 17 | 7. [Use the application](#use-the-application) 18 | 8. [Dynamically change request routing](#dynamically-change-request-routing) 19 | 9. Monitoring and Observability 20 | - [View metrics and tracing](#viewing-metrics-and-tracing) 21 | - [Monitoring for Istio](#monitoring-for-istio) 22 | - [Generating a Service Graph](#generate-graph) 23 | 10. [Fault Injection](#fault-injection) 24 | 11. [Circuit Breaker](#circuit) 25 | 12. [Security](#security) 26 | - [Testing Istio mutual TLS authentication](#mutual) 27 | - [Testing Istio RBAC](#rbac) 28 | - [Testing Istio JWT Policy](#jwt) 29 | 13. [Mesh Expansion](./mesh) 30 | 14. [Multi-Cluster Mesh Expansion](./multi) 31 | 15. [Miscellaneous](./misc) 32 | - Websockets 33 | - Rate Limiting 34 | - Expose external services (egress traffic) 35 | 15. [API Management](./apimanagement) 36 | - Installing API Management 37 | - Publish the API as a product 38 | - Consume an API Product 39 | - Obtain an OAuth token 40 | - View API Analytics 41 | - Expose APIs to third parties 42 | - Restrict access to IPs 43 | 16. [Uninstall Istio](#uninstall-istio) 44 | 45 | ## Introduction 46 | 47 | [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. 48 | 49 | You add Istio support to services by deploying a special Envoy sidecar proxy to each of your application's pods in your environment that intercepts all network communication between microservices, configured and managed using Istio'''s control plane functionality. 50 | 51 | ## Setup and Requirements 52 | 53 | If you don'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: 54 | ![NewProject1](media/setup-req-0.png) 55 | ![NewProject2](media/setup-req-1.png) 56 | ![NewProject3](media/setup-req-4.png) 57 | 58 | Remember 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. 59 | 60 | Next, you'll need to [enable billing](https://console.cloud.google.com/billing) in the Developers Console in order to use Google Cloud resources. 61 | 62 | Running through this codelab shouldn'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 "cleanup" section at the end of this document). Google Kubernetes Engine pricing is documented [here](https://cloud.google.com/kubernetes-engine/docs/#pricing). 63 | 64 | New users of Google Cloud Platform are eligible for a [$300 free trial](https://console.developers.google.com/billing/freetrial?hl=en). 65 | 66 | ### Enable API 67 | 68 | Enable the Kubernetes Engine API: 69 | 1. First click on APIs and Services on the right pane 70 | ![api_services](media/apis_and_services.png) 71 | 72 | 2. Check if the Kubernetes APIs are enabled 73 | ![checkapis](media/check_enabled.png) 74 | 75 | 3. If you **CANNOT** find this in your project, then Kubernetes APIs are not enabled. Proceed further. Otherwise skip the following steps. 76 | 77 | 4. Click on **ENABLE APIS AND SERVICES** 78 | ![enableapiservice](media/enable_apis_services.png) 79 | 80 | 5. Start typing _**ku**_ in the search bar 81 | ![search](media/search_kub.png) 82 | 83 | 6. Select _Google Kubernetes Engine API_ 84 | 85 | 7. Enable the API. This step could take 2 or 3 minutes. 86 | 87 | ![gkeapi](media/enable_api.png) 88 | 89 | ### Google Cloud Shell 90 | 91 | While 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. 92 | 93 | This 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). 94 | 95 | To 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): 96 | 97 | ![NewProject3](media/setup-req-2.png) 98 | 99 | Then accept the terms of service and click the "Start Cloud Shell" link: 100 | 101 | ![NewProject3](media/setup-req-3.png) 102 | 103 | Once connected to the cloud shell, you should see that you are already authenticated and that the project is already set to your _PROJECT_ID_ 104 | 105 | ## Prepare your Kubernetes/GKE cluster 106 | 107 | The requirements for this Istio lab are as follows: 108 | 109 | - 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. 110 | - 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) 111 | 112 | To 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) : 113 | 114 | ``` 115 | gcloud container clusters create hello-istio \ 116 | --machine-type=n1-standard-2 \ 117 | --num-nodes=6 \ 118 | --no-enable-legacy-authorization \ 119 | --zone=us-west1-b \ 120 | --cluster-version=1.11.7-gke.4 121 | ``` 122 | 123 | Setup Kubernetes CLI Content: 124 | 125 | ```gcloud container clusters get-credentials hello-istio --zone us-west1-b --project PROJECT_ID``` 126 | 127 | Now, grant cluster admin permissions to the current user. You need these permissions to create the necessary RBAC rules for Istio. 128 | 129 | ``` 130 | kubectl create clusterrolebinding cluster-admin-binding \ 131 | --clusterrole=cluster-admin \ 132 | --user=$(gcloud config get-value core/account) 133 | ``` 134 | 135 | If you navigate in the GCP console to Kubernetes clusters you should see a screen similar to this: 136 | 137 | ![setupcluster](media/setup-cluster-1.png) 138 | 139 | ## Installing Istio 140 | 141 | Now, let'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. 142 | 143 | The [Istio release page](https://github.com/istio/istio/releases) offers download artifacts for several OSs. In our case, with CloudShell we'll be using this command to download and extract the latest release automatically: 144 | 145 | ```curl -L https://git.io/getLatestIstio | sh -``` 146 | 147 | The installation directory contains the following: 148 | 149 | - Installation .yaml files for Kubernetes in **install/** 150 | - Sample applications in **samples/** 151 | - 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. 152 | - The VERSION configuration file 153 | 154 | Change to the istio install directory: 155 | 156 | ```cd ./istio-* ``` 157 | 158 | Add the istioctl client to your PATH: 159 | 160 | ```export PATH=$PWD/bin:$PATH``` 161 | 162 | Let's now install Istio'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: 163 | 164 | 1. Create the custome resource definitions 165 | ```kubectl apply -f install/kubernetes/helm/istio/templates/crds.yaml``` 166 | 167 | 2. Create the helm service account 168 | ```kubectl create -f install/kubernetes/helm/helm-service-account.yaml``` 169 | 170 | 3. Initialize helm 171 | ```helm init --service-account tiller``` 172 | 173 | 4. Render Istio’s core components to a Kubernetes manifest called istio.yaml 174 | ```helm template install/kubernetes/helm/istio --name istio --namespace istio-system > $HOME/istio.yaml``` 175 | NOTE: See here for details on how to install the [helm client](https://docs.helm.sh/using_helm/). 176 | 177 | 4. Install the components 178 | ``` 179 | kubectl create namespace istio-system 180 | kubectl apply -f $HOME/istio.yaml 181 | ``` 182 | This 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). 183 | 184 | ## Verifying the installation 185 | 186 | First, ensure the following Kubernetes services are deployed: istio-pilot, istio-mixer, istio-ingress, and istio-egress. 187 | 188 | Run the command: 189 | ``` 190 | kubectl get svc -n istio-system 191 | ``` 192 | OUTPUT: 193 | 194 | ``` 195 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE 196 | grafana ClusterIP 10.35.241.104 3000/TCP 18m 197 | istio-citadel ClusterIP 10.35.252.114 8060/TCP,9093/TCP 18m 198 | istio-egressgateway ClusterIP 10.35.255.114 80/TCP,443/TCP 18m 199 | istio-galley ClusterIP 10.35.240.201 443/TCP 18m 200 | istio-ingressgateway LoadBalancer 10.35.247.245 xx.xxx.xxx.xxx 80:31380/TCP,443:31390/TCP,31400:31400/TCP 18m 201 | istio-pilot ClusterIP 10.35.243.14 15003/TCP,15005/TCP,15007/TCP,15010/TCP,15011/TCP,8080/TCP,9093/TCP 18m 202 | istio-policy ClusterIP 10.35.251.186 9091/TCP,15004/TCP,9093/TCP 18m 203 | istio-sidecar-injector ClusterIP 10.35.253.208 443/TCP 18m 204 | istio-statsd-prom-bridge ClusterIP 10.35.254.35 9102/TCP,9125/UDP 18m 205 | istio-telemetry ClusterIP 10.35.254.188 9091/TCP,15004/TCP,9093/TCP,42422/TCP 18m 206 | prometheus ClusterIP 10.35.253.203 9090/TCP 18m 207 | servicegraph ClusterIP 10.35.250.205 8088/TCP 18m 208 | tracing ClusterIP 10.35.242.39 80/TCP 18m 209 | zipkin ClusterIP 10.35.247.252 9411/TCP 18m 210 | ``` 211 | 212 | Then make sure that the corresponding Kubernetes pods are deployed and all containers are up and running. 213 | 214 | Run the command: 215 | ``` 216 | kubectl get pods -n istio-system 217 | ``` 218 | OUTPUT: 219 | ``` 220 | NAME READY STATUS RESTARTS AGE 221 | grafana-69fc7b47bd-v4qm8 1/1 Running 0 17m 222 | istio-citadel-857cf5dc8c-hkdrm 1/1 Running 0 17m 223 | istio-egressgateway-dbf9c5d7c-87d8s 1/1 Running 0 17m 224 | istio-galley-6496b645bf-khw6b 1/1 Running 0 17m 225 | istio-ingressgateway-596bdb588c-zxprt 1/1 Running 0 17m 226 | istio-pilot-7db88954f4-s26fc 2/2 Running 0 17m 227 | istio-policy-6bb954c589-9fvqk 2/2 Running 0 17m 228 | istio-sidecar-injector-57657b649d-vhlmg 1/1 Running 0 17m 229 | istio-statsd-prom-bridge-59b45fd6d-5n5nd 1/1 Running 0 17m 230 | istio-telemetry-66bd668dfd-6st47 2/2 Running 0 17m 231 | istio-tracing-647f8c48f8-fcznc 1/1 Running 0 17m 232 | prometheus-ffd95f9f6-hz5r4 1/1 Running 0 17m 233 | servicegraph-78fddd97cb-9blxc 1/1 Running 0 17m 234 | ``` 235 | 236 | When all the pods are running, you can proceed. 237 | 238 | ## Deploying an application 239 | 240 | Now 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. 241 | 242 | You 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's services in an Istio-enabled environment, with Envoy sidecar proxies injected alongside each service to provide Istio functionality. 243 | 244 | ### Overview 245 | In 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. 246 | 247 | The BookInfo application is broken into four separate microservices: 248 | 249 | * productpage. The productpage microservice calls the details and reviews microservices to populate the page. 250 | * details. The details microservice contains book information. 251 | * reviews. The reviews microservice contains book reviews. It also calls the ratings microservice. 252 | * ratings. The ratings microservice contains book ranking information that accompanies a book review. 253 | 254 | There are 3 versions of the reviews microservice: 255 | 256 | * Version v1 doesn’t call the ratings service. 257 | * Version v2 calls the ratings service, and displays each rating as 1 to 5 black stars. 258 | * Version v3 calls the ratings service, and displays each rating as 1 to 5 red stars. 259 | 260 | The end-to-end architecture of the application is shown below. 261 | 262 | ![bookinfo](media/bookinfo.png) 263 | 264 | ### Deploy Bookinfo 265 | 266 | We deploy our application directly using kubectl create and its regular YAML deployment file. We will inject Envoy containers into your application pods using istioctl: 267 | 268 | ```kubectl create -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)``` 269 | 270 | Finally, confirm that the application has been deployed correctly by running the following commands: 271 | 272 | Run the command: 273 | ``` 274 | kubectl get services 275 | ``` 276 | OUTPUT: 277 | ``` 278 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE 279 | details ClusterIP 10.35.240.243 9080/TCP 14s 280 | kubernetes ClusterIP 10.35.240.1 443/TCP 14d 281 | productpage ClusterIP 10.35.255.218 9080/TCP 14s 282 | ratings ClusterIP 10.35.244.227 9080/TCP 14s 283 | reviews ClusterIP 10.35.252.163 9080/TCP 14s 284 | ``` 285 | 286 | Run the command: 287 | ``` 288 | kubectl get pods 289 | ``` 290 | 291 | OUTPUT: 292 | ``` 293 | NAME READY STATUS RESTARTS AGE 294 | details-v1-568f787b57-ml486 2/2 Running 0 36s 295 | productpage-v1-74cc57988f-28nxg 2/2 Running 0 36s 296 | ratings-v1-5bb4b7c645-8xbp8 2/2 Running 0 36s 297 | reviews-v1-5b95b546f7-cdlww 2/2 Running 0 36s 298 | reviews-v2-5799c54cb5-ffjv4 2/2 Running 0 36s 299 | reviews-v3-5df5bd8dfc-9ldnx 2/2 Running 0 36s 300 | ``` 301 | 302 | With Envoy sidecars injected along side each service, the architecture will look like this: 303 | 304 | ![bookinfoistio](media/bookinfo-istio.png) 305 | 306 | Finally, expose the service to be consumeable on the ingress 307 | 308 | ``` 309 | cat < 359 | 360 | Now that it's deployed, let's see the BookInfo application in action. 361 | 362 | First you need to get the ingress IP and port, as follows: 363 | 364 | ``` 365 | kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 366 | ``` 367 | OUTPUT: 368 | ``` 369 | 35.xxx.xxx.xxx 370 | ``` 371 | 372 | Based on this information (Address), set the GATEWAY\_URL environment variable: 373 | 374 | ```export GATEWAY_URL=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')``` 375 | 376 | Check that the BookInfo app is running with curl: 377 | 378 | Run the command: 379 | ``` 380 | curl -o /dev/null -s -w "%{http_code}\n" http://${GATEWAY_URL}/productpage 381 | ``` 382 | OUTPUT: 383 | ``` 384 | 200 385 | ``` 386 | 387 | Then 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't yet used Istio to control the version routing 388 | 389 | ![Istio](media/use-app-1.png) 390 | 391 | ## Dynamically change request routing 392 | 393 | The 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. 394 | 395 | We 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 : 396 | 397 | ```istioctl get destinationrules -n default``` 398 | 399 | No Resouces will be found. Now, create the rule (check out the source yaml file it you'd like to understand how rules are specified) : 400 | 401 | Run the command: 402 | ``` 403 | kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml -n default 404 | ``` 405 | OUTPUT: 406 | ``` 407 | virtualservice "productpage" created 408 | virtualservice "reviews" created 409 | virtualservice "ratings" created 410 | virtualservice "details" created 411 | destinationrule "productpage" created 412 | destinationrule "reviews" created 413 | destinationrule "ratings" created 414 | destinationrule "details" created 415 | ``` 416 | 417 | Look at the rule you've just created: 418 | 419 | ``` 420 | istioctl get destinationrules 421 | ``` 422 | OUTPUT: 423 | ``` 424 | DESTINATION-RULE NAME HOST SUBSETS NAMESPACE AGE 425 | details details v1,v2 default 13s 426 | productpage productpage v1 default 13s 427 | ratings ratings v1,v2,v2-mysql,v2-mysql-vm default 13s 428 | reviews reviews v1,v2,v3 default 13s 429 | ``` 430 | 431 | Go 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. 432 | 433 | To test reviews:v2, but only for a certain user, let's create this rule: 434 | 435 | ``` 436 | kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml -n default 437 | ``` 438 | 439 | Check out the route-rule-reviews-test-v2.yaml file to see how this virtual service is specified : 440 | 441 | ``` 442 | $ cat samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml 443 | ``` 444 | OUTPUT: 445 | ``` 446 | apiVersion: networking.istio.io/v1alpha3 447 | kind: VirtualService 448 | metadata: 449 | name: reviews 450 | spec: 451 | hosts: 452 | - reviews 453 | http: 454 | - match: 455 | - headers: 456 | cookie: 457 | regex: "^(.*?;)?(user=jason)(;.*)?$" 458 | route: 459 | - destination: 460 | host: reviews 461 | subset: v2 462 | - route: 463 | - destination: 464 | host: reviews 465 | subset: v1 466 | ``` 467 | 468 | Look at the virtual service you've just created : 469 | 470 | ```istioctl get virtualservices reviews -o yaml``` 471 | 472 | We 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 'jason'. 473 | 474 | You can read the [documentation page](https://istio.io/docs/tasks/traffic-management/request-routing.html) for further details on Istio's request routing. 475 | 476 | Once 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. 477 | 478 | For now, let's clean up the routing rules: 479 | 480 | ``` 481 | kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml -n default 482 | kubectl delete -f samples/bookinfo/networking/destination-rule-all-mtls.yaml -n default 483 | ``` 484 | 485 | ## View metrics and tracing 486 | 487 | Istio-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's model allows this regardless of what language/framework/platform you use to build your application. 488 | 489 | Configure port forwarding (works on Google Cloud Shell only): 490 | 491 | ```kubectl port-forward -n istio-system $(kubectl get pod -n istio-system -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 8080:16686 &``` 492 | 493 | Open your browser by clicking on "Preview on port 8080": 494 | ![Istio](media/preview.png) 495 | 496 | Load the Bookinfo application again (http://$GATEWAY_URL/productpage). 497 | 498 | Select a service from the list (ex: istio-ingressgateway), and you will now see something similar to the following: 499 | 500 | ![Istio](media/metrics-1.png) 501 | 502 | You can see how long each microservice call took, including the Istio checks. 503 | 504 | You can read the [documentation page](https://istio.io/docs/tasks/telemetry/distributed-tracing.html) for further details on Istio's distributed request tracing. 505 | 506 | To stop the port forward, 507 | ``` 508 | ctrl + c 509 | ``` 510 | Then bring the process to the foreground 511 | ``` 512 | fg 513 | ``` 514 | Then stop it again 515 | ``` 516 | ctrl + c 517 | ``` 518 | 519 | 520 | ## Monitoring for Istio 521 | 522 | This 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. 523 | 524 | First we install the Grafana addon: 525 | 526 | ```kubectl apply -f install/kubernetes/addons/grafana.yaml``` 527 | 528 | Grafana will be used to visualize the data prometheus. 529 | 530 | Configure port forwarding (works on Google shell only): 531 | 532 | ```kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 8080:3000 &``` 533 | 534 | Open your browser by clicking on "Preview on port 8080": 535 | ![Istio](media/preview.png) 536 | 537 | Load the Bookinfo application again (http://$GATEWAY_URL/productpage). 538 | 539 | Select a trace from the list, and you will now see something similar to the following: 540 | 541 | ![monitoring](media/monitoring-1.png) 542 | 543 | To stop the port forward, 544 | ``` 545 | ctrl + c 546 | ``` 547 | Then bring the process to the foreground 548 | ``` 549 | fg 550 | ``` 551 | Then stop it again 552 | ``` 553 | ctrl + c 554 | ``` 555 | 556 | ## Generating a Service Graph 557 | 558 | This 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. 559 | 560 | Configure port forwarding (works on Google Cloud Shell only): 561 | 562 | ```kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=servicegraph -o jsonpath='{.items[0].metadata.name}') 8080:8088 &``` 563 | 564 | Open your browser by clicking on "Preview on port 8080": 565 | ![Istio](media/preview.png) 566 | 567 | NOTE: Edit the browser to add `/dotviz` manually. Like this: `https://8080-dot-2997305-dot-devshell.appspot.com/dotviz?authuser=0` 568 | 569 | You will now see something similar to the following: 570 | 571 | ![servicegraph](media/servicegraph-1.png) 572 | 573 | To stop the port forward, 574 | ``` 575 | ctrl + c 576 | ``` 577 | Then bring the process to the foreground 578 | ``` 579 | fg 580 | ``` 581 | Then stop it again 582 | ``` 583 | ctrl + c 584 | ``` 585 | 586 | ## Fault Injection 587 | 588 | ### Fault Injection using HTTP Delay 589 | This task shows how to inject delays and test the resiliency of your application. 590 | 591 | *_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._* 592 | 593 | To 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. 594 | 595 | Create a fault injection rule to delay traffic coming from user “jason” (our test user) 596 | 597 | ``` 598 | kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml 599 | kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml 600 | ``` 601 | 602 | Run the command: 603 | ``` 604 | kubectl apply -f samples/bookinfo/routing/route-rule-ratings-test-delay.yaml 605 | ``` 606 | You should see the yaml for the routing rule. Allow several seconds to account for rule propagation delay to all pods. 607 | 608 | ##### Observe application behavior 609 | 610 | Log 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. 611 | 612 | You will see that the webpage loads in about 6 seconds. The reviews section will show _Sorry, product reviews are currently unavailable for this book_. 613 | 614 | #### Understanding what happened 615 | The 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. 616 | 617 | **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** 618 | 619 | ### Fault Injection using HTTP Abort 620 | As 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. 621 | 622 | Create a fault injection rule to send an HTTP abort for user “jason” 623 | 624 | ``` 625 | kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml 626 | ``` 627 | 628 | #### Observe application behavior 629 | 630 | Login 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 631 | 632 | #### Remove the fault rules 633 | Clean up the fault rules with the command: 634 | 635 | ``` 636 | kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml 637 | ``` 638 | ## Circuit Breaker 639 | This 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. 640 | 641 | ### Define a Destination Rule 642 | DestinationRule 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. 643 | 644 | Run the following command: 645 | ``` 646 | cat <1 procs, for 20 calls: http://details:9080/details/0 692 | Starting at max qps with 2 thread(s) [gomax 1] for exactly 20 calls (10 per thread + 0) 693 | 05:18:06 W http_client.go:604> Parsed non ok code 503 (HTTP/1.1 503) 694 | .... 695 | Sockets used: 13 (for perfect keepalive, would be 2) 696 | Code 200 : 8 (40.0 %) 697 | Code 503 : 12 (60.0 %) 698 | Response Header Sizes : count 20 avg 63.3 +/- 77.53 min 0 max 159 sum 1266 699 | Response Body/Total Sizes : count 20 avg 264.7 +/- 58.42 min 217 max 337 sum 5294 700 | All done 20 calls (plus 0 warmup) 4.333 ms avg, 320.2 qps 701 | ``` 702 | 703 | Only 40% of requests made it through, the rest were blocked by the circuit breaker. 704 | 705 | ### Cleanup 706 | ``` 707 | istioctl delete destinationrule details-breaker 708 | ``` 709 | 710 | ## Security 711 | ### Testing Istio mutual TLS authentication 712 | Through this task, you will learn how to: 713 | * Verify the Istio mutual TLS Authentication setup 714 | * Manually test the authentication 715 | #### Verifying Istio CA 716 | Verify the cluster-level CA is running: 717 | 718 | ``` 719 | kubectl get deploy -l istio=citadel -n istio-system 720 | ``` 721 | OUTPUT: 722 | ``` 723 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 724 | istio-citadel 1 1 1 1 3h 725 | ``` 726 | #### Verify Service Configuration 727 | Check 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 728 | ``` 729 | kubectl get destinationrules.networking.istio.io --all-namespaces -o yaml 730 | ``` 731 | 732 | #### Enable mTLS on all services 733 | NOTE 1: Starting Istio 0.8, enabling mTLS is controlled through the authentication policy. 734 | NOTE 2: A policy with no targets (i.e., apply to all targets in namespace) must be named `default` 735 | 736 | To enable mTLS all services deployed in the default namesapce, 737 | ``` 738 | cat < 9080/TCP 12m 794 | kubernetes ClusterIP 10.59.240.1 443/TCP 18m 795 | mtlstest ClusterIP 10.59.253.170 8080/TCP 7m 796 | productpage ClusterIP 10.59.251.133 9080/TCP 12m 797 | ratings ClusterIP 10.59.251.105 9080/TCP 12m 798 | reviews ClusterIP 10.59.250.46 9080/TCP 12m 799 | ``` 800 | NOTE: The cluster IP for the **details** app. This app is running on port 9080 801 | 802 | 7. Access the mtltest pod 803 | ``` 804 | kubectl exec -it mtlstest-bbf7bd6c-9rmwn /bin/bash 805 | ``` 806 | 807 | 8. Run cURL to access to the details app 808 | ``` 809 | curl -k -v https://details:9080/details/0 810 | ``` 811 | 812 | OUTPUT: 813 | ``` 814 | * Trying 10.35.255.72... 815 | * TCP_NODELAY set 816 | * Connected to details (10.35.255.72) port 9080 (#0) 817 | * ALPN, offering h2 818 | * ALPN, offering http/1.1 819 | * successfully set certificate verify locations: 820 | * CAfile: /etc/ssl/certs/ca-certificates.crt 821 | CApath: /etc/ssl/certs 822 | * TLSv1.2 (OUT), TLS handshake, Client hello (1): 823 | * error:1408F10B:SSL routines:ssl3_get_record:wrong version number 824 | * Closing connection 0 825 | curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number 826 | ``` 827 | **NOTE**: If security (mTLS) was **NOT** enabled on the services, you would have see the output (status 200) 828 | #### Accessing the Service 829 | 830 | We are now going to access the service with the appropriate keys and certs. 831 | 832 | 1. Get the CA Root Cert, Certificate and Key from Kubernetes secrets 833 | ``` 834 | kubectl get secret istio.default -o jsonpath='{.data.root-cert\.pem}' | base64 --decode > root-cert.pem 835 | kubectl get secret istio.default -o jsonpath='{.data.cert-chain\.pem}' | base64 --decode > cert-chain.pem 836 | kubectl get secret istio.default -o jsonpath='{.data.key\.pem}' | base64 --decode > key.pem 837 | ``` 838 | 839 | 2. Copy the files to the mtlstest POD 840 | ``` 841 | kubectl cp root-cert.pem mtlstest-854c4c9b85-gwr82:/tmp -c mtlstest 842 | kubectl cp cert-chain.pem mtlstest-854c4c9b85-gwr82:/tmp -c mtlstest 843 | kubectl cp key.pem mtlstest-854c4c9b85-gwr82:/tmp -c mtlstest 844 | ``` 845 | 846 | 3. Start a bash to the mtlstest POD 847 | ``` 848 | kubectl get pods 849 | ``` 850 | OUTPUT: 851 | ``` 852 | NAME READY STATUS RESTARTS AGE 853 | details-v1-845458947b-4xt2j 2/2 Running 0 5h 854 | mtlstest-bbf7bd6c-gfpjk 2/2 Running 0 45m 855 | productpage-v1-54d4776d48-z8xxv 2/2 Running 0 5h 856 | ``` 857 | 858 | ``` 859 | kubectl exec -it mtlstest-854c4c9b85-gwr82 /bin/bash 860 | ``` 861 | 862 | 4. Move the PEM files to the appropriate folder (/etc/certs - which is the default folder) 863 | ``` 864 | mkdir /etc/certs 865 | ``` 866 | ``` 867 | mv /tmp/*.pem /etc/certs/ 868 | ``` 869 | 870 | 5. Access the application 871 | ``` 872 | curl -v http://details:9080/details/0 873 | ``` 874 | OUTPUT: 875 | ``` 876 | * Trying 10.35.255.72... 877 | * TCP_NODELAY set 878 | * Connected to details (10.35.255.72) port 9080 (#0) 879 | > GET /details/0 HTTP/1.1 880 | > Host: details:9080 881 | > User-Agent: curl/7.58.0 882 | > Accept: */* 883 | > 884 | < HTTP/1.1 200 OK 885 | < content-type: application/json 886 | < server: envoy 887 | < date: Mon, 25 Jun 2018 03:50:17 GMT 888 | < content-length: 178 889 | < x-envoy-upstream-service-time: 19 890 | < 891 | * Connection #0 to host details left intact 892 | {"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 893 | ``` 894 | **NOTE**: 895 | 1. You didn't have to specify _https_ when accessing the service. 896 | 2. Envoy automatically established mTLS between the consumer (mtlstest) and the provider (details) 897 | 898 | #### Preventing Unauthorized access 899 | We 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. 900 | 901 | We 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: 902 | 903 | ``` 904 | kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo-add-serviceaccount.yaml) 905 | ``` 906 | 907 | Output: 908 | ``` 909 | serviceaccount "bookinfo-productpage" created 910 | deployment "productpage-v1" configured 911 | serviceaccount "bookinfo-reviews" created 912 | deployment "reviews-v2" configured 913 | deployment "reviews-v3" configured 914 | ``` 915 | 916 | We are now going to deploy a mixer rule that denies access to other services (services that are not _productpage_). Review this snippet: 917 | 918 | ``` 919 | spec: 920 | match: destination.labels["app"] == "details" && source.user != "cluster.local/ns/default/sa/bookinfo-productpage" 921 | actions: 922 | - handler: denyproductpagehandler.denier 923 | instances: [ denyproductpagerequest.checknothing ] 924 | ``` 925 | The 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. 926 | 927 | 928 | ``` 929 | cat << EOF | kubectl create -f - 930 | apiVersion: "config.istio.io/v1alpha2" 931 | kind: denier 932 | metadata: 933 | name: denyproductpagehandler 934 | spec: 935 | status: 936 | code: 7 937 | message: Not allowed 938 | --- 939 | apiVersion: "config.istio.io/v1alpha2" 940 | kind: checknothing 941 | metadata: 942 | name: denyproductpagerequest 943 | spec: 944 | --- 945 | apiVersion: "config.istio.io/v1alpha2" 946 | kind: rule 947 | metadata: 948 | name: denyproductpage 949 | spec: 950 | match: destination.labels["app"] == "details" && source.user != "cluster.local/ns/default/sa/bookinfo-productpage" 951 | actions: 952 | - handler: denyproductpagehandler.denier 953 | instances: [ denyproductpagerequest.checknothing ] 954 | EOF 955 | ``` 956 | Output: 957 | ``` 958 | Created config denier/default/denyproductpagehandler at revision 32311 959 | Created config checknothing/default/denyproductpagerequest at revision 32312 960 | Created config rule/default/denyproductpage at revision 32313 961 | ``` 962 | 963 | Now, try to access the service again. 964 | 965 | ``` 966 | kubectl exec -it mtlstest-bbf7bd6c-gfpjk /bin/bash 967 | ``` 968 | 969 | ``` 970 | curl -v http://details:9080/details/0 971 | ``` 972 | Output: 973 | ``` 974 | * Trying 10.35.255.72... 975 | * TCP_NODELAY set 976 | * Connected to details (10.35.255.72) port 9080 (#0) 977 | > GET /details/0 HTTP/1.1 978 | > Host: details:9080 979 | > User-Agent: curl/7.58.0 980 | > Accept: */* 981 | > 982 | < HTTP/1.1 403 Forbidden 983 | < content-length: 67 984 | < content-type: text/plain 985 | < date: Mon, 25 Jun 2018 04:06:05 GMT 986 | < server: envoy 987 | < x-envoy-upstream-service-time: 5 988 | < 989 | * Connection #0 to host details left intact 990 | PERMISSION_DENIED:denyproductpagehandler.denier.default:Not allowed 991 | ``` 992 | 993 | ### Further Reading 994 | Learn 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) 995 | 996 | ### Testing Istio RBAC 997 | Istio Role-Based Access Control (RBAC) provides namespace-level, service-level, method-level access control for services in the Istio Mesh. It features: 998 | * Role-Based semantics, which is simple and easy to use. 999 | * Service-to-service and endUser-to-Service authorization. 1000 | * Flexibility through custom properties support in roles and role-bindings. 1001 | 1002 | In 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. 1003 | ``` 1004 | istioctl create -f samples/bookinfo/platform/kube/istio-rbac-enable.yaml 1005 | ``` 1006 | OUTPUT: 1007 | ``` 1008 | Created config authorization/istio-system/requestcontext at revision 197480 1009 | Created config rbac/istio-system/handler at revision 197481 1010 | Created config rule/istio-system/rbaccheck at revision 197482 1011 | ``` 1012 | 1013 | Now, create a service role and service role binding 1014 | ``` 1015 | apiVersion: "config.istio.io/v1alpha2" 1016 | kind: ServiceRole 1017 | metadata: 1018 | name: service-viewer 1019 | namespace: default 1020 | spec: 1021 | rules: 1022 | - services: ["*"] 1023 | methods: ["GET"] 1024 | constraints: 1025 | - key: "app" 1026 | values: ["productpage", "details", "reviews", "ratings", "mtlstest"] 1027 | ``` 1028 | 1029 | This service role allows only the GET operation on all the services listed in `values`. Deploy the rule 1030 | 1031 | ``` 1032 | istioctl create -f samples/bookinfo/platform/kube/istio-rbac-namespace.yaml 1033 | ``` 1034 | 1035 | OUTPUT: 1036 | ``` 1037 | Created config service-role/default/service-viewer at revision 196402 1038 | Created config service-role-binding/default/bind-service-viewer at revision 196403 1039 | ``` 1040 | 1041 | Access the mtlstest POD 1042 | ``` 1043 | kubectl exec -it mtlstest-854c4c9b85-gwr82 /bin/bash 1044 | ``` 1045 | 1046 | Try to access the application 1047 | ``` 1048 | curl -v http://details:9080/details/0 1049 | ``` 1050 | 1051 | This should work successfully because we did not block GET calls. Now let's try to create/POST 1052 | ``` 1053 | curl -v http://details:9080/details/0 -X POST -d '{}' 1054 | ``` 1055 | 1056 | OUTPUT: 1057 | ``` 1058 | Note: Unnecessary use of -X or --request, POST is already inferred. 1059 | * Trying 10.35.255.72... 1060 | * TCP_NODELAY set 1061 | * Connected to details (10.35.255.72) port 9080 (#0) 1062 | > POST /details/0 HTTP/1.1 1063 | > Host: details:9080 1064 | > User-Agent: curl/7.58.0 1065 | > Accept: */* 1066 | > Content-Length: 2 1067 | > Content-Type: application/x-www-form-urlencoded 1068 | > 1069 | * upload completely sent off: 2 out of 2 bytes 1070 | < HTTP/1.1 403 Forbidden 1071 | < content-length: 68 1072 | < content-type: text/plain 1073 | < date: Tue, 26 Jun 2018 05:39:51 GMT 1074 | < server: envoy 1075 | < x-envoy-upstream-service-time: 7 1076 | < 1077 | * Connection #0 to host details left intact 1078 | PERMISSION_DENIED:handler.rbac.istio-system:RBAC: permission denied. 1079 | ``` 1080 | 1081 | The create/POST failed. You can learn more about Istio RBAC [here](https://istio.io/docs/concepts/security/rbac/) 1082 | 1083 | Delete RBAC resources 1084 | 1085 | ``` 1086 | istioctl delete -f rbac/istio-rbac-namespace.yaml 1087 | istioctl delete -f samples/bookinfo/kube/istio-rbac-enable.yaml 1088 | ``` 1089 | 1090 | ### Testing Istio JWT Policy 1091 | Through this task, you will learn how to enable JWT validation on specific services in the mesh. 1092 | 1093 | #### Scenario 1094 | Let'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 1095 | 1096 | ``` 1097 | istioctl get virtualservices bookinfo -o yaml > bookinfo.yaml 1098 | ``` 1099 | 1100 | Edit the file to expose the details service 1101 | ``` 1102 | ..... 1103 | route: 1104 | - destination: 1105 | host: productpage 1106 | port: 1107 | number: 9080 1108 | - match: 1109 | - uri: 1110 | prefix: /details 1111 | route: 1112 | - destination: 1113 | host: details 1114 | port: 1115 | number: 9080 1116 | subset: v1 1117 | ``` 1118 | 1119 | Deploy the virtual service 1120 | 1121 | ``` 1122 | kubectl apply -f bookinfo.yaml 1123 | ``` 1124 | Test access to the service. 1125 | ``` 1126 | curl GATEWAY_URL/details/0 1127 | ``` 1128 | 1129 | OUTPUT: 1130 | ``` 1131 | {"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"} 1132 | ``` 1133 | Alright, 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. 1134 | 1135 | #### Enable JWT Policy 1136 | In this step we will enable the JWT policy on the details service. Take a look at the details-jwt.yaml file. 1137 | 1138 | The first section is defining how to enable the JWT 1139 | ``` 1140 | apiVersion: "authentication.istio.io/v1alpha1" 1141 | kind: Policy 1142 | metadata: 1143 | name: details-auth-spec 1144 | namespace: default 1145 | spec: 1146 | targets: 1147 | - name: details 1148 | peers: 1149 | - mtls: 1150 | origins: 1151 | - jwt: 1152 | issuer: https://amer-demo13-test.apigee.net/istio-auth/token 1153 | jwks_uri: https://amer-demo13-test.apigee.net/istio-auth/certs 1154 | principalBinding: USE_ORIGIN 1155 | ``` 1156 | There are two critical pieces here: 1157 | * The _Issuer_, every JWT token must match the issuer specified here 1158 | * 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. 1159 | 1160 | Now, apply the policy 1161 | 1162 | ``` 1163 | kubectl apply -f jwttest/details-jwt.yaml 1164 | ``` 1165 | 1166 | OUTPUT: 1167 | ``` 1168 | policy "details-auth-spec" created 1169 | ``` 1170 | 1171 | Now let's try and access the API from the ingress. 1172 | ``` 1173 | curl -v http://$GATEWAY_URL/details/0 1174 | ``` 1175 | 1176 | OUTPUT: 1177 | ``` 1178 | * Trying 35.227.168.43... 1179 | * TCP_NODELAY set 1180 | * Connected to 35.227.168.43 (35.227.168.43) port 80 (#0) 1181 | > GET /details/0 HTTP/1.1 1182 | > Host: 35.227.168.43 1183 | > User-Agent: curl/7.52.1 1184 | > Accept: */* 1185 | > 1186 | < HTTP/1.1 401 Unauthorized 1187 | < content-length: 29 1188 | < content-type: text/plain 1189 | < date: Mon, 25 Jun 2018 16:04:56 GMT 1190 | < server: envoy 1191 | < x-envoy-upstream-service-time: 1 1192 | < 1193 | * Curl_http_done: called premature == 0 1194 | * Connection #0 to host 35.227.168.43 left intact 1195 | Origin authentication failed. 1196 | ``` 1197 | This 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. 1198 | 1199 | ## API Management 1200 | To see how you can manage your APIs, take a look at this next section [API Management for Istio](./apimanagement/README.md) 1201 | 1202 | ## Uninstall Istio 1203 | 1204 | Here's how to uninstall Istio. 1205 | 1206 | ``` 1207 | kubectl delete -f bookinfo/platform/kube/bookinfo.yaml 1208 | ``` 1209 | OUTPUT: 1210 | ``` 1211 | service 'details' deleted 1212 | deployment 'details-v1' deleted 1213 | service 'ratings' deleted 1214 | deployment 'ratings-v1' deleted 1215 | service 'reviews' deleted 1216 | deployment 'reviews-v1' deleted 1217 | deployment 'reviews-v2' deleted 1218 | deployment 'reviews-v3' deleted 1219 | service 'productpage' deleted 1220 | deployment 'productpage-v1' deleted 1221 | ``` 1222 | 1223 | ```kubectl delete -f $HOME/istio.yaml``` 1224 | 1225 | In 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): 1226 | 1227 | ```gcloud container clusters delete hello-istio``` 1228 | 1229 | OUTPUT 1230 | ``` 1231 | The following clusters will be deleted. - [hello-istio] in [west1-b] 1232 | Do you want to continue (Y/n)? Y 1233 | Deleting cluster hello-istio...done. 1234 | 1235 | [https://container.googleapis.com/v1/projects/codelab-test/zones/us-central1-f/clusters/hello-istio]. 1236 | ``` 1237 | 1238 | Of 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. 1239 | -------------------------------------------------------------------------------- /apigee/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/apigee/.DS_Store -------------------------------------------------------------------------------- /apigee/details.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/apigee/details.zip -------------------------------------------------------------------------------- /apigee/importproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl -u $1:$2 -F "file=@details.zip" https://api.enterprise.apigee.com/v1/organizations/$3/apis?action=import&name=details 3 | 4 | curl -u $1:$2 -H "Content-Type: application/x-www-form-urlencoded" https://api.enterprise.apigee.com/v1/organizations/$3/environments/$4/apis/details/revisions/1/deployments -------------------------------------------------------------------------------- /apimanagement/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Summary 3 | 4 | In this lab, you will learn how to configure and use Apigee API Management for Istio. Apigee API Management for Istio provides basic API gateway policies that can be applied to your microservices in a service mesh. 5 | 6 | # Table of Contents 7 | 8 | 1. [Setup and Requirements](#setup-and-requirements) 9 | 2. [Installing Apigee API Management](#install) 10 | 3. [Recap](#recap) 11 | 4. [Publish the API as a Product](#publish) 12 | 5. [Consume an API Product](#consume) 13 | 6. [Obtain a JWT Token](#obtain) 14 | 7. [View API Analytics](#analytics) 15 | 8. [Full API Management](#fullapi) 16 | - [Expose APIs to third parties](#accessapi) 17 | - [Restrict access to IPs](#restrictip) 18 | 19 | ## Setup and Requirements 20 | 21 | 1. This lab assumes you have completed the last step of the previous lab (Enabling JWT in the security section). 22 | 2. You must have an [Apigee Edge](https://login.apigee.com) account. If you need one, you can create one [here](https://login.apigee.com/sign_up). 23 | 24 | ## Installing Apigee API Management for Istio 25 | 26 | Apigee Istio Mixer Adapter releases can be found [here](https://github.com/apigee/istio-mixer-adapter/releases) 27 | 28 | Download the appropriate release package for your operating system and extract it. You should a file list similar to: 29 | 30 | LICENSE 31 | README.md 32 | samples/apigee/authentication-policy.yaml 33 | samples/apigee/definitions.yaml 34 | samples/apigee/handler.yaml 35 | samples/apigee/httpapispec.yaml 36 | samples/apigee/rule.yaml 37 | samples/istio/helloworld.yaml 38 | samples/istio/istio-demo.yaml 39 | samples/istio/istio-demo-auth.yaml 40 | apigee-istio 41 | 42 | `apigee-istio` (or apigee-istio.exe on Windows) is the Command Line Interface (CLI) for this project 43 | You may add it to your PATH for quick access - or remember to specify the path for the commands below. 44 | 45 | ### Upgrade Istio 46 | 47 | Apigee's Istio Mixer adapter only requires istio-policy and istio-telemetry to be updated. We could have a deployment that only updates those components. But in this case we're upgrading all the components (most of which should be unchanged anyway). 48 | 49 | ```shell 50 | kubectl -n istio-system set image deployment/istio-telemetry mixer=gcr.io/apigee-api-management-istio/istio-mixer:1.0.0 51 | 52 | kubectl -n istio-system set image deployment/istio-policy mixer=gcr.io/apigee-api-management-istio/istio-mixer:1.0.0 53 | ``` 54 | 55 | ### Provision Apigee for Istio 56 | 57 | Configuring Apigee for Istio is a four step process: 58 | 1. Configure your Apigee Edge instance to manage Istio (issue credentials, productize APIs in a service mesh, communicate securely to Apigee Edge etc.) 59 | 2. Configure Istio to create definitions for Apigee 60 | 61 | The first thing you'll need to do is provision your Apigee environment to work with the Istio adapter. 62 | This will install a proxy, set up a certificate, and generate some credentials for you: 63 | 64 | ```shell 65 | 66 | apigee-istio -u {your username} -p {your password} -o {your organization name} -e {your environment name} provision > samples/apigee/handler.yaml 67 | 68 | ``` 69 | 70 | Once it completes, check your `samples/apigee/handler.yaml` file. It should look like this (with different values): 71 | ``` 72 | 73 | # istio handler configuration for apigee adapter 74 | # generated by apigee-istio provision on 2018-06-18 15:29:31 75 | apiVersion: config.istio.io/v1alpha2 76 | kind: apigee 77 | metadata: 78 | name: apigee-handler 79 | namespace: istio-system 80 | spec: 81 | apigee_base: https://istioservices.apigee.net/edgemicro 82 | customer_base: https://myorg-myenv.apigee.net/istio-auth 83 | org_name: myorg 84 | env_name: myenv 85 | key: 06a40b65005d03ea24c0d53de69ab795590b0c332526e97fed549471bdea00b9 86 | secret: 93550179f344150c6474956994e0943b3e93a3c90c64035f378dc05c98389633 87 | 88 | ``` 89 | 90 | Apply the Apigee definitions for Istio. This defines the CRDs for Apigee. 91 | 92 | ``` 93 | 94 | kubectl apply -f samples/apigee/definitions.yaml 95 | 96 | ``` 97 | OUTPUT: 98 | ``` 99 | 100 | customresourcedefinition "apigees.config.istio.io" created 101 | customresourcedefinition "analytics.config.istio.io" created 102 | analytics "apigee" created 103 | authorization "apigee" created 104 | 105 | ``` 106 | 107 | NOTE: if you notice a failure when running this command, please run it again. The error should be resolved. 108 | 109 | Apply the Apigee handler to Istio. The handler tells Mixer how to connect (securely) to Apigee. 110 | 111 | ``` 112 | kubectl apply -f samples/apigee/handler.yaml 113 | ``` 114 | 115 | OUTPUT: 116 | ``` 117 | apigee "apigee-handler" created 118 | ``` 119 | 120 | and finally, apply the rule. This tells Istio when to apply Apigee rules. 121 | 122 | ``` 123 | kubectl apply -f samples/apigee/rule.yaml 124 | ``` 125 | OUTPUT: 126 | ``` 127 | rule "apigee-rule" created 128 | ``` 129 | NOTE: in the sample rule, we apply Apigee rules to any service in the default namespace. This will prevent your UI from showing book details. But that is expected. We expect JWT tokens to access the `details` service and the `productspage` is not sending it. 130 | 131 | ## Recap 132 | In the previous workshop we deploy the bookinfo application, exposed the details API and protected it via JWT. In this workshop, we're going to provide secure access to the API and generate usage/analytics metrics. 133 | 134 | ## Publish the API as a Product 135 | The first step will be to create an API Product in Apigee Edge. 136 | 137 | 1. Login to Apigee Edge 138 | Use your Apigee credentials to login in. 139 | 140 | 141 | 142 | 2. Select Publish from the Edge UI 143 | 144 | 145 | 146 | 3. Select API Products under publish 147 | 148 | 149 | 150 | 4. Create a new product 151 | 152 | 153 | 154 | 5. Enter Product details 155 | 156 | * Name: A Product Name 157 | * Environment: which environment the API Product is available in 158 | * Resouces: Which API Paths you want to expose 159 | * Attributes: Add a custom attribute called `istio-services`. The values are a comma separated list of Istio services (FQDN). 160 | 161 | ![productdetails](../media/product-details.png) 162 | 163 | ## Consume an API Product 164 | Generally speaking, you would now go to the Apigee portal and request keys for the API Product we just created. To keep the lab simple, we will create those artifacts a portal would have through the Edge UI (Admin interface) 165 | 166 | 1. Select Developer App from the Edge UI 167 | 168 | 169 | 170 | 2. Create a new Developer App 171 | 172 | 173 | 174 | 3. Enter Developer App details 175 | * Name: A new for the developer app 176 | * Developer: The name of the developer who is authoring the app (client application) 177 | * Product: A list of API Products 178 | 179 | ![app-details](../media/app-details.png) 180 | 181 | 4. Make a note of the credentials 182 | 183 | ![credentials](../media/credentials.png) 184 | 185 | ## Obtain a JWT Token 186 | We will now use the `apigee-istio` CLI interface to obtain a new JWT token. The CLI interface is for convenience only. In production, client applications will use APIs to get an new JWT token. 187 | 188 | ``` 189 | export TOKEN=`apigee-istio token create -o amer-demo13 -e test -i xxx -s xxx` 190 | ``` 191 | 192 | The output is stored in an environment variable. 193 | 194 | ### Make an API Call 195 | Now, we are ready to try the API again: 196 | 197 | ``` 198 | curl $GATEAWY_URL/details/0 -H "Authorization: Bearer $TOKEN" 199 | ``` 200 | 201 | OUTPUT: 202 | ``` 203 | {"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"} 204 | ``` 205 | We have now successfully exposed an API to consumers outside the service mesh. 206 | 207 | ## View API Analytics 208 | The Apigee adapter for Istio is able to send API usage/metrics asyncronously to the Edge UI. In about 5-6 mins, you should be able to see usage metric for details showing up like this: 209 | 210 | ![analytics](../media/analytics.png) 211 | 212 | ## Expose the API to third parties 213 | When exposing APIs externally, especially to third parties, the API Management policies you want enforced are typically different (more security focused) than when the API is used internally. 214 | 215 | For APIs are exposed externally, you'd probably want: 216 | * Some form of rate limiting 217 | * JSON/XML threat protection (Minimizes the risk posed by content-level attacks by enabling you to specify limits on various XXML/SON structures, such as arrays and strings) 218 | * Quotas (different from the ones you'd give internal users) 219 | 220 | Apigee's API gateway provides with exactly such policies. In this part of the lab, you will create a proxy in Apigee Edge and have external users proxy requests through the Apigee Gateway. 221 | 222 | ``` 223 | ./importproxy.sh {username} {password} {orgname} {envname} 224 | ``` 225 | 226 | This should deploy a proxy called `details` in your org and deploy it to the environment that was specified in the CLI. 227 | 228 | ### Access the API 229 | Try accessing the API from the endpoint published in Apigee. 230 | 231 | ``` 232 | curl https://{org}-{env}.apigee.net/details/0 -H "Authorization: Bearer $TOKEN" 233 | ``` 234 | 235 | ## Restrict access to IPs 236 | The details API is available on a public IP `GATEWAY_URL`. Nothing prevents an external user to bypass Apigee and access the endpoint directly. It is a good thing we still require OAuth tokens to access the endpoint, but we still want only Apigee's proxy to access the endpoint. 237 | 238 | 239 | Istio provides a native adapter (listchecker) to whitelist or blacklist IPs. The following steps will show you how to use it. 240 | 241 | 1. Obtain the IP address of Apigee Edge 242 | ``` 243 | curl -X GET https://api.enterprise.apigee.com/v1/o/{org}/eips -u {user}:{pass} 244 | ``` 245 | OUTPUT: 246 | ``` 247 | { 248 | "podEips" : [ { 249 | "eips" : [ ], 250 | "pod" : { 251 | "name" : "pxx0rt000-0", 252 | "region" : "us-east-1" 253 | } 254 | }, { 255 | "eips" : [ "xxx.xx.xxx.xx", "xx.xxx.xxx.xx" ], 256 | "pod" : { 257 | "name" : "pxx0mp000-0", 258 | "region" : "us-east-1" 259 | } 260 | } ] 261 | } 262 | ``` 263 | The `eips` field contains the IP addresses assigned to the Apigee gateways. 264 | 265 | 2. Configure Mixer to allow only those IPs 266 | This section contains three parts: 267 | * listchecker: provide a list of ips to whitelist 268 | * listentry: provide the location of the ip 269 | * rule: when do i apply this adapter, in this case, when the call comes to the ingress 270 | 271 | ``` 272 | apiVersion: "config.istio.io/v1alpha2" 273 | kind: listchecker 274 | metadata: 275 | name: ip-listchecker 276 | namespace: istio-system 277 | spec: 278 | entryType: IP_ADDRESSES 279 | overrides: [ "107.23.127.92", "54.210.253.51" ] 280 | blacklist: false 281 | --- 282 | apiVersion: config.istio.io/v1alpha2 283 | kind: listentry 284 | metadata: 285 | name: ip-value 286 | namespace: istio-system 287 | spec: 288 | value: source.ip 289 | --- 290 | apiVersion: "config.istio.io/v1alpha2" 291 | kind: rule 292 | metadata: 293 | name: ip-rule 294 | namespace: istio-system 295 | spec: 296 | match: destination.labels["istio"] == "ingressgateway" && source.service == "details.default.svc.cluster.local" 297 | actions: 298 | - handler: ip-listchecker.listchecker 299 | instances: 300 | - ip-value.listentry 301 | ``` 302 | 303 | [WIP: this step is not complete yet] -------------------------------------------------------------------------------- /jwttest/details-jwt.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "authentication.istio.io/v1alpha1" 2 | kind: Policy 3 | metadata: 4 | name: details-auth-spec 5 | namespace: default 6 | spec: 7 | targets: 8 | - name: details 9 | peers: 10 | - mtls: 11 | origins: 12 | - jwt: 13 | issuer: https://amer-demo13-test.apigee.net/istio-auth/token 14 | jwks_uri: https://amer-demo13-test.apigee.net/istio-auth/certs 15 | principalBinding: USE_ORIGIN -------------------------------------------------------------------------------- /media/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/.DS_Store -------------------------------------------------------------------------------- /media/New-product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/New-product.png -------------------------------------------------------------------------------- /media/analytics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/analytics.png -------------------------------------------------------------------------------- /media/apis_and_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/apis_and_services.png -------------------------------------------------------------------------------- /media/app-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/app-details.png -------------------------------------------------------------------------------- /media/apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/apps.png -------------------------------------------------------------------------------- /media/bookinfo-istio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/bookinfo-istio.png -------------------------------------------------------------------------------- /media/bookinfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/bookinfo.png -------------------------------------------------------------------------------- /media/check_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/check_enabled.png -------------------------------------------------------------------------------- /media/create-instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/create-instance.png -------------------------------------------------------------------------------- /media/credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/credentials.png -------------------------------------------------------------------------------- /media/enable_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/enable_api.png -------------------------------------------------------------------------------- /media/enable_apis_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/enable_apis_services.png -------------------------------------------------------------------------------- /media/istio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/istio.png -------------------------------------------------------------------------------- /media/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/login.png -------------------------------------------------------------------------------- /media/metrics-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/metrics-1.png -------------------------------------------------------------------------------- /media/metrics-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/metrics-2.png -------------------------------------------------------------------------------- /media/monitoring-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/monitoring-1.png -------------------------------------------------------------------------------- /media/new-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/new-app.png -------------------------------------------------------------------------------- /media/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/preview.png -------------------------------------------------------------------------------- /media/product-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/product-details.png -------------------------------------------------------------------------------- /media/product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/product.png -------------------------------------------------------------------------------- /media/publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/publish.png -------------------------------------------------------------------------------- /media/search_kub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/search_kub.png -------------------------------------------------------------------------------- /media/servicegraph-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/servicegraph-1.png -------------------------------------------------------------------------------- /media/setup-cluster-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/setup-cluster-1.png -------------------------------------------------------------------------------- /media/setup-req-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/setup-req-0.png -------------------------------------------------------------------------------- /media/setup-req-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/setup-req-1.png -------------------------------------------------------------------------------- /media/setup-req-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/setup-req-2.png -------------------------------------------------------------------------------- /media/setup-req-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/setup-req-3.png -------------------------------------------------------------------------------- /media/setup-req-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/setup-req-4.png -------------------------------------------------------------------------------- /media/use-app-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/media/use-app-1.png -------------------------------------------------------------------------------- /mesh/README.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | In this lab, you will learn how to expand the service mesh to include VM. Mesh expansion refers to a pattern where the Istio control plane (Pilot, Mixer & Citadel) are on Kubernetes and the sidecar envoy is on VMs. With this pattern you can bring workloads running on VMs into the Istio Service Mesh. 3 | 4 | # Table of Contents 5 | 1. [Pre-requisites](#prereq) 6 | 2. [Setup a GCE Instance](#gce) 7 | 3. [Testing the mesh expansion setup](#meshtest) 8 | 4. [Access services in the mesh](#access) 9 | 5. [Expose a service to the mesh](#expose) 10 | 11 | ## Pre-requisites 12 | In order to complete this lab, you should have completed the instructions in the Istio Workshop. 13 | 14 | ## Setup a GCE Instance 15 | Create a new GCE instance. Let's call it `meshexpand` (this name will be used later). 16 | 17 | 1. Create a new Instance 18 | * Zone: us-west1-a (this will be needed later) 19 | * Name: meshexpand 20 | * Boot Disk: Google Drawfork Ubuntu 16.04 21 | * Allow HTTP and HTTPS traffic 22 | 23 | 24 | 25 | 2. In the Google Cloud Shell, run the following commands 26 | - Generate ssh keys 27 | ``` 28 | ssh-keygen -t rsa -b 4096 -C "youremail" 29 | ``` 30 | - Add ssh key 31 | ``` 32 | ssh-add ~/.ssh/id_rsa 33 | ``` 34 | NOTE: if you get the error "Could not open a connection to your authentication agent.", then run 35 | ``` 36 | eval `ssh-agent -s` 37 | ``` 38 | - Test ssh connection 39 | ``` 40 | ssh vmUser@vmIP 41 | ``` 42 | NOTE: If your ssh times out, ssh port (22) is probably blocked. Then run the following commands 43 | ``` 44 | gcloud compute firewall-rules create open-22 --allow tcp:22 --source-ranges 0.0.0.0/0 --target-tags open-22 45 | ``` 46 | ``` 47 | gcloud compute instances add-tags meshexpand --tags open-22 48 | ``` 49 | 3. Enable the Kuernetes cluster for mesh expansion 50 | 51 | ``` 52 | kubectl apply -f install/kubernetes/mesh-expansion.yaml 53 | ``` 54 | OUTPUT: 55 | ``` 56 | service "istio-pilot-ilb" created 57 | service "dns-ilb" created 58 | service "mixer-ilb" created 59 | service "citadel-ilb" created 60 | ``` 61 | 62 | Confirm that the load balancers are running and that they have EXTERNAL-IP values: 63 | 64 | ``` 65 | kubectl get services -n istio-system 66 | ``` 67 | 68 | Caution: The EXTERNAL-IP column might show `` until the services are fully up and running. Do not proceed with the installation until they have EXTERNAL-IP values. 69 | 70 | 4. Export environment variables 71 | ``` 72 | export GCP_OPTS="--zone {zone} --project {project}" 73 | export SERVICE_NAMESPACE=default 74 | ``` 75 | 5. Generate the cluster configuration file 76 | ``` 77 | install/tools/setupMeshEx.sh generateClusterEnv {clustername} 78 | ``` 79 | This command creates a file named cluster.env in the current directory that contains a single line in the form: 80 | ``` 81 | ISTIO_SERVICE_CIDR=10.35.240.0/20 82 | ISTIO_SYSTEM_NAMESPACE=istio-system 83 | CONTROL_PLANE_AUTH_POLICY=MUTUAL_TLS 84 | ``` 85 | 86 | 6. Generate the DNS configuration file 87 | ``` 88 | install/tools/setupMeshEx.sh generateDnsmasq 89 | ``` 90 | OUTPUT: 91 | ``` 92 | Generated Dnsmaq config file 'kubedns'. Install it in /etc/dnsmasq.d and restart dnsmasq. 93 | install/tools/setupMeshEx.sh machineSetup does this for you. 94 | ``` 95 | 7. Setup the GCE instance (note this only works for GCE) 96 | ``` 97 | install/tools/setupMeshEx.sh gceMachineSetup meshexpand 98 | ``` 99 | Here, `meshexpand` is the VM name. 100 | 101 | OUTPUT: 102 | ``` 103 | ......lot of lines 104 | Selecting previously unselected package host. 105 | (Reading database ... 98786 files and directories currently installed.) 106 | Preparing to unpack .../host_1%3a9.10.3.dfsg.P4-8ubuntu1.10_all.deb ... 107 | Unpacking host (1:9.10.3.dfsg.P4-8ubuntu1.10) ... 108 | Setting up host (1:9.10.3.dfsg.P4-8ubuntu1.10) ... 109 | *** Restarting istio proxy... 110 | ``` 111 | 8. Complete the setup 112 | Login to the VM and enable the certs to be read by users 113 | 114 | ``` 115 | chmod +r /etc/certs/*.pem 116 | ``` 117 | 118 | Restart istio-proxy and the node-agent 119 | ``` 120 | systemctl restart istio 121 | systemctl restart istio-auth-node-agent 122 | ``` 123 | 124 | Create a user. The sidecar does not intercept traffic from root. To test our setup, we will create a new user 125 | 126 | ``` 127 | groupadd meshexpand 128 | useradd meshexpand -g meshexpand -m -d /opt/meshexpand 129 | ``` 130 | 131 | ## Testing the mesh expansion setup 132 | 133 | Run the command 134 | ``` 135 | host istio-pilot.istio-system 136 | ``` 137 | OUTPUT: 138 | ``` 139 | istio-pilot.istio-system has address 10.138.0.18 140 | ``` 141 | 142 | Run the command 143 | ``` 144 | host istio-pilot.istio-system.svc.cluster.local. 145 | ``` 146 | OUTPUT: 147 | ``` 148 | istio-pilot.istio-system.svc.cluster.local has address 10.35.244.91 149 | ``` 150 | 151 | Run the command 152 | ``` 153 | curl 'http://istio-pilot.istio-system:8080/v1/registration/istio-pilot.istio-system.svc.cluster.local|http-discovery' 154 | ``` 155 | OUTPUT: 156 | ``` 157 | { 158 | "hosts": [ 159 | { 160 | "ip_address": "10.32.0.7", 161 | "port": 15007, 162 | "tags": { 163 | "az": "us-west1/us-west1-a" 164 | } 165 | } 166 | ] 167 | } 168 | ``` 169 | ## Access services in the mesh 170 | Access the details service from the VM. 171 | ``` 172 | curl details.default.svc.cluster.local:9080/details/0 -v 173 | ``` 174 | OUTPUT: 175 | ``` 176 | * Trying 10.35.255.72... 177 | * Connected to details.default.svc.cluster.local (10.35.255.72) port 9080 (#0) 178 | > GET /details/0 HTTP/1.1 179 | > Host: details.default.svc.cluster.local:9080 180 | > User-Agent: curl/7.47.0 181 | > Accept: */* 182 | > 183 | < HTTP/1.1 200 OK 184 | < content-type: application/json 185 | < server: envoy 186 | < date: Sat, 30 Jun 2018 17:45:27 GMT 187 | < content-length: 178 188 | < x-envoy-upstream-service-time: 15 189 | < 190 | * Connection #0 to host details.default.svc.cluster.local left intact 191 | {"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"} 192 | ``` 193 | 194 | At this point, you have added this VM into the mesh. This VM can access services in the mesh as if that VM were in Kubernetes. 195 | 196 | ## Expose a service to the mesh 197 | 1. We will install a basic node.js application. Run the following commands: 198 | ``` 199 | apt-get update && apt-get install -y gnupg curl 200 | curl -sL https://deb.nodesource.com/setup_8.x | bash - 201 | apt-get install -y nodejs 202 | ``` 203 | 2. Switch to the `meshexpand` user 204 | 205 | 3. Create a package.json 206 | ``` 207 | echo "{\"name\": \"mtlstest\",\"version\": \"1.0.0\",\"main\": \"index.js\",\"scripts\": {\"start\": \"node index.js\"},\"dependencies\": {\"express\": \"^4.16.1\"}}" >> package.json 208 | ``` 209 | 210 | 4. Create index.js 211 | Paste the contents into index..js 212 | ``` 213 | var express = require('express');var app = express();app.get('/*', function (req, res) {res.send('Hello World!');});app.listen(8080, function () {}); 214 | ``` 215 | 216 | 5. Install npm packages and start 217 | ``` 218 | npm install --save express 219 | ``` 220 | ``` 221 | nohup node index.js & 222 | ``` 223 | 6. Switch back to root user and get cluster credentials 224 | ``` 225 | gcloud container clusters get-credentials istio --zone us-west1-a --project nandanks-151422 226 | ``` 227 | 7. Get the service account 228 | ``` 229 | gcloud compute instances describe meshexpand 230 | ``` 231 | The output of this command includes the email address of the service account, in the from: 232 | ``` 233 | serviceAccounts: 234 | - email: 10570444441-compute@developer.gserviceaccount.com 235 | ``` 236 | 8. Register the service on the VM into the mesh 237 | ``` 238 | ./bin/istioctl -n default register --serviceaccount 10570444441-compute@developer.gserviceaccount.com meshexpand 10.138.0.17 8080 -l version=v1 239 | ``` 240 | OUTPUT: 241 | ``` 242 | 2018-06-30T22:33:16.302271Z info Registering for service 'meshexpand' ip '10.138.0.17', ports list [{8080 http}] 243 | 2018-06-30T22:33:16.302562Z info 1 labels ([version=v1]) and 1 annotations ([alpha.istio.io/kubernetes-serviceaccounts=102128743119-compute@developer.gserviceaccount.com]) 244 | .... 245 | 2018-06-30T22:33:16.343740Z info On ports [{Name:http Port:8080 Protocol:TCP}] 246 | 2018-06-30T22:33:16.343961Z info Found {IP:10.138.0.17 Hostname: NodeName: TargetRef:nil} 247 | 2018-06-30T22:33:16.344135Z info Found matching ports list in existing subset [{http 8080 TCP}] 248 | 2018-06-30T22:33:16.347498Z info Successfully updated meshexpand, now with 1 endpoints 249 | 2018-06-30T22:33:16.347889Z info Details: &Endpoints{ObjectMeta:k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta{Name:meshexpand,GenerateName:, 250 | .... 251 | ``` 252 | Confirm the changes. 253 | ``` 254 | kubectl describe svc meshexpand 255 | ``` 256 | Expected output: 257 | ``` 258 | Name: meshexpand 259 | Namespace: default 260 | Labels: 261 | Annotations: alpha.istio.io/kubernetes-serviceaccounts=10570444441-compute@developer.gserviceaccount.com 262 | Selector: 263 | Type: ClusterIP 264 | IP: 10.35.254.116 265 | Port: http 8080/TCP 266 | TargetPort: 8080/TCP 267 | Endpoints: 10.138.0.17:8080 268 | Session Affinity: None 269 | Events: 270 | ``` 271 | if your `Annotations` look like `alpha.istio.io/kubernetes-serviceaccounts=default` then, 272 | 273 | ``` 274 | kubectl edit svc meshexpand 275 | ``` 276 | replace `default` with the service account and save the file. 277 | 278 | 279 | 9. Configure the sidecar 280 | Edit the file `/var/lib/istio/envoy/sidecar.env` 281 | Add the followling lines 282 | ``` 283 | ISTIO_INBOUND_PORTS=8080 284 | ISTIO_SERVICE=meshexpand 285 | ISTIO_NAMESPACE=default 286 | ``` 287 | 288 | 10. Restart istio-proxy and the node-agent 289 | ``` 290 | systemctl restart istio 291 | systemctl restart istio-auth-node-agent 292 | ``` 293 | 11. Check IP Table rules 294 | ``` 295 | iptables-save | grep -i istio 296 | ``` 297 | OUTPUT: 298 | ``` 299 | # Generated by iptables-save v1.6.0 on Sat Jun 30 22:38:45 2018 300 | .... 301 | -A PREROUTING -p tcp -j ISTIO_INBOUND 302 | -A OUTPUT -p tcp -j ISTIO_OUTPUT 303 | -A ISTIO_INBOUND -p tcp -m tcp --dport 8080 -j ISTIO_REDIRECT 304 | -A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -j ISTIO_REDIRECT 305 | ``` 306 | 307 | 12. Expose the service on the virtual host 308 | This step will expose the service outside the mesh by making it available in the ingress 309 | 310 | Obtain the original virtualservice 311 | 312 | ``` 313 | istioctl get virtualservices bookinfo -o yaml >> bookinfo.yaml 314 | ``` 315 | In the VirtualService, add the following lines: 316 | ``` 317 | spec: 318 | gateways: 319 | - bookinfo-gateway 320 | hosts: 321 | - '*' 322 | http: 323 | .... 324 | - match: 325 | - uri: 326 | prefix: /mesh 327 | route: 328 | - destination: 329 | host: meshexpand 330 | subset: v1 331 | port: 332 | number: 8080 333 | ``` 334 | Add a new DestinationRule 335 | ``` 336 | cat < GET / HTTP/1.1 370 | > Host: meshexpand.default.svc.cluster.local:8080 371 | > User-Agent: curl/7.58.0 372 | > Accept: */* 373 | > 374 | < HTTP/1.1 200 OK 375 | < x-powered-by: Express 376 | < content-type: text/html; charset=utf-8 377 | < content-length: 12 378 | < etag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE" 379 | < date: Sat, 07 Jul 2018 01:49:52 GMT 380 | < x-envoy-upstream-service-time: 7 381 | < server: envoy 382 | < 383 | * Connection #0 to host meshexpand.default.svc.cluster.local left intact 384 | Hello World! 385 | ``` 386 | 387 | 14. Access the service from outside the mesh 388 | 389 | ``` 390 | curl $GATEWAY/mesh -v 391 | ``` 392 | OUTPUT: 393 | ``` 394 | * Rebuilt URL to: meshexpand.default.svc.cluster.local:8080/ 395 | * Trying 10.35.254.116... 396 | * TCP_NODELAY set 397 | * Connected to meshexpand.default.svc.cluster.local (10.35.254.116) port 8080 (#0) 398 | > GET / HTTP/1.1 399 | > Host: meshexpand.default.svc.cluster.local:8080 400 | > User-Agent: curl/7.58.0 401 | > Accept: */* 402 | > 403 | < HTTP/1.1 200 OK 404 | < x-powered-by: Express 405 | < content-type: text/html; charset=utf-8 406 | < content-length: 12 407 | < etag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE" 408 | < date: Sat, 07 Jul 2018 01:49:52 GMT 409 | < x-envoy-upstream-service-time: 7 410 | < server: envoy 411 | < 412 | * Connection #0 to host meshexpand.default.svc.cluster.local left intact 413 | Hello World! 414 | ``` -------------------------------------------------------------------------------- /misc/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Summary 3 | In this lab, you will learn a few additional capabilities of Istio. 4 | 5 | # Table of Contents 6 | 1. [Setup and Requirements](#setup-and-requirements) 7 | 2. Web Sockets 8 | - [Install sample websocket app](#install) 9 | - [Test websocket application](#test) 10 | - [Protect a websockets endpoint](#protect) 11 | 3. [Rate Limiting](#quota) 12 | 4. [Expose external services](#expose) 13 | - [Within the service mesh](#within) 14 | - [Outside the mesh](#outside) 15 | 16 | ## Setup and Requirements 17 | This lab assumes you have bookinfo application from the main lab. 18 | 19 | ## Install sample websocket app 20 | In this part of the lab, you will install and configure a sample websocket application 21 | 22 | 1. Build a sample application 23 | ``` 24 | ./websocket/dockerbuild.sh 25 | ``` 26 | 27 | 2. Push the application to GCP 28 | ``` 29 | ./websocket/dockerpush.sh 30 | ``` 31 | 32 | 3. Deploy the application to Kubernetes 33 | ``` 34 | kubectl apply -f <(istioctl kube-inject -f ./websocket/websockets.yaml) 35 | ``` 36 | 37 | 4. Edit bookinfo virtual services to add new routes 38 | ``` 39 | kubectl edit virtualservice bookinfo 40 | ``` 41 | Add the following lines to the bookinfo virtual service 42 | ``` 43 | - match: 44 | - uri: 45 | exact: /v1/ws 46 | route: 47 | - destination: 48 | host: websockets 49 | port: 50 | number: 3000 51 | websocketUpgrade: true 52 | - match: 53 | - uri: 54 | exact: / 55 | route: 56 | - destination: 57 | host: websockets 58 | port: 59 | number: 3000 60 | ``` 61 | 62 | ## Test websocket application 63 | 1. Open a Chrome tab and go to the $GATEWAY endpoint. You should see this message 64 | 65 | 66 | 2. Open developer tools in Chrome 67 | 68 | 69 | 3. Open a websocket connection and test 70 | 71 | 72 | The first step opens a websocket connection to the server. The second step registers a listener for incoming messages and prints the message from the server. The last step send a message to the server. 73 | 74 | In this example, I'm sending `hi` to the server and the server responds with `helloworld`. 75 | 76 | ### Protect a websockets endpoint 77 | In this part of the lab, you will protect a websockets endpoints with apikeys and capture analytics using Apigee Edge. 78 | 79 | 1. Create an API specification for the websockets application 80 | 81 | ``` 82 | kubectl apply -f ./websockets/websockets-api.yaml 83 | ``` 84 | 85 | 2. Create rule to enable API key protection for the websockets application 86 | 87 | ``` 88 | kubectl apply -f ./websockets/websokets-rule.yaml 89 | ``` 90 | 91 | 3. Test the endpoint 92 | 93 | ``` 94 | curl http://35.227.164.14/ 95 | ``` 96 | 97 | OUTPUT: 98 | ``` 99 | PERMISSION_DENIED:apigee-handler.apigee.istio-system:missing authentication 100 | ``` 101 | This is an expected result. If you pass a valid apikey as a queryparam, then the call should succeed. 102 | 103 | NOTE: To create a valid API key, please follow the steps [here](../apimanagement/README.md). It involves creating an API Product and a Developer App in Apigee Edge. 104 | 105 | 4. Test the websocket connection 106 | 107 | 108 | The first connection does not provide an apikey. The second connection provides an invalid apikey. The last connection provides a valid apikey. 109 | 110 | NOTE: Istio does not call Mixer (istio-policy) once a connection is successfully established. Therefore Quota or Rate Limiting policies are not expected to work. 111 | 112 | 113 | ## Rate Limiting 114 | In this part of the lab, we will enable rate limiting on a service. 115 | 116 | ### Understanding Quota 117 | There are four parts to quota. 118 | * The `memquota` adapter uses a sliding window of sub second resolution to enforce rate limits. The `maxAmount` in the adapter configuration sets the default limit for all counters associated with a quota instance. This default limit applies if a quota override does not match the request. In the example, we will set a quota on the `details` service for 3 per minute. 119 | * The kind `quota` specifies the quota identifier. In this case it is the `destination.service`. 120 | * The `QuotaSpec` determines the message weight. In this case, we will increase the counter by 1. 121 | * The `QuotaSpecBinding` determines to which services the `QuotaSpec` must be applied to. In this case, the `details` service. 122 | * The `rule` which specifies when the quota adapter should be active. In this case, there is no match condition, because we are using `QuotaSpecBinding` to control which servies the quota applies to. 123 | 124 | If the number of requests exceeds the quota, Mixer returns a RESOURCE_EXHAUSTED message to the proxy. The proxy in turn returns status HTTP 429 to the caller. 125 | 126 | 1. Apply Quota Policy 127 | ``` 128 | cat < 206 | In this part of the lab, you'll see how to expose external services (services not managed by Istio) to consumers within and outside the service mesh. 207 | 208 | ### Within the service mesh 209 | In this section, we will expose a service outside the mesh for consumption within the mesh. For this example, we will expose the service `httpbin.org` to consumers within the mesh. 210 | 211 | #### Purpose 212 | * Allows the mesh operator to control which services/endpoints are exposed inside the mesh 213 | * Even if the endpoint changes the consumer is protected by these changes. Consumers access the external service using an internal name. 214 | * Allows the mesh operator to apply security (TLS) before the call is made externally in one centralized location. 215 | 216 | 1. Create a `ServiceEntry` 217 | A service entry describes the properties of a service (DNS name, VIPs ,ports, protocols, endpoints). 218 | 219 | ``` 220 | cat EOF << | kubectl apply -f - 221 | apiVersion: networking.istio.io/v1alpha3 222 | kind: ServiceEntry 223 | metadata: 224 | name: httpbin-ext 225 | namespace: default 226 | spec: 227 | hosts: 228 | - httpbin.org 229 | location: MESH_EXTERNAL 230 | ports: 231 | - name: http 232 | number: 80 233 | protocol: HTTP 234 | resolution: DNS 235 | EOF 236 | ``` 237 | 2. Create a `Service` 238 | 239 | ``` 240 | apiVersion: v1 241 | kind: Service 242 | metadata: 243 | labels: 244 | app: httpbinapi 245 | version: v1 246 | name: httpbinapi 247 | namespace: default 248 | spec: 249 | externalName: httpbin.org 250 | selector: 251 | app: httpbinapi 252 | sessionAffinity: None 253 | type: ExternalName 254 | ``` 255 | 3. Create a `VirtualService` 256 | 257 | ``` 258 | apiVersion: networking.istio.io/v1alpha3 259 | kind: VirtualService 260 | metadata: 261 | name: httpbin-internal 262 | namespace: default 263 | spec: 264 | gateways: 265 | - mesh 266 | hosts: 267 | - httpbinapi.default.svc.cluster.local 268 | http: 269 | match: 270 | - uri: 271 | exact: /ip 272 | rewrite: 273 | authority: httpbin.org 274 | uri: /ip 275 | route: 276 | - destination: 277 | host: httpbin.org 278 | ``` 279 | Note the gateway uses the name `mesh`. The reserved word mesh is used to imply all the sidecars in the mesh. 280 | 281 | 4. Access the service from inside the mesh 282 | 283 | ``` 284 | kubectl exec -it mtlstest-5f4d7d858-zhcnc /bin/bash 285 | ``` 286 | 287 | ``` 288 | curl httpbinapi.default.svc.cluster.local/ip -v 289 | ``` 290 | 291 | OUTPUT: 292 | ``` 293 | * Trying 34.238.48.57... 294 | * TCP_NODELAY set 295 | * Connected to httpbinapi.default.svc.cluster.local (34.238.48.57) port 80 (#0) 296 | > GET /ip HTTP/1.1 297 | > Host: httpbinapi.default.svc.cluster.local 298 | > User-Agent: curl/7.58.0 299 | > Accept: */* 300 | > 301 | < HTTP/1.1 200 OK 302 | < server: envoy 303 | < date: Mon, 23 Jul 2018 04:54:48 GMT 304 | < content-type: application/json 305 | < content-length: 28 306 | < access-control-allow-origin: * 307 | < access-control-allow-credentials: true 308 | < via: 1.1 vegur 309 | < x-envoy-upstream-service-time: 133 310 | < 311 | {"origin":"35.xxx.xxx.xxx"} 312 | * Connection #0 to host httpbinapi.default.svc.cluster.local left intact 313 | ``` 314 | 315 | ### Outside the service mesh 316 | In this section, we will expose a service outside the mesh for consumption at the ingress. For this example, we will expose the service `httpbin.org` at the ingress. 317 | 318 | 1. Edit the `VirtualService` 319 | 320 | Add the following lines 321 | ``` 322 | - match: 323 | - uri: 324 | exact: /ip 325 | rewrite: 326 | authority: httpbin.org 327 | uri: /ip 328 | route: 329 | - destination: 330 | host: httpbin.org 331 | ``` 332 | 333 | 2. Access the service 334 | 335 | ``` 336 | curl $GATEWAY/ip -v 337 | ``` 338 | 339 | OUTPUT: 340 | ``` 341 | * Trying xx.xxx.xxx.203... 342 | * TCP_NODELAY set 343 | * Connected to xx.xxx.xxx.203 (35.203.186.203) port 80 (#0) 344 | > GET /ip HTTP/1.1 345 | > Host: xx.xxx.xxx.203 346 | > User-Agent: curl/7.52.1 347 | > Accept: */* 348 | > 349 | < HTTP/1.1 200 OK 350 | < server: envoy 351 | < date: Mon, 23 Jul 2018 04:57:57 GMT 352 | < content-type: application/json 353 | < content-length: 40 354 | < access-control-allow-origin: * 355 | < access-control-allow-credentials: true 356 | < via: 1.1 vegur 357 | < x-envoy-upstream-service-time: 135 358 | < 359 | {"origin":"10.138.0.7, xx.xxx.xxx.181"} 360 | * Curl_http_done: called premature == 0 361 | * Connection #0 to host xx.xxx.xxx.203 left intact 362 | ``` 363 | #### Purpose 364 | * Even if the endpoint changes the consumer is protected by these changes. Consumers access the external service using the ingress name. 365 | * Allows the mesh operator to apply security (TLS) before the call is made externally in one centralized location. -------------------------------------------------------------------------------- /misc/media/devtools-cmds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/misc/media/devtools-cmds.png -------------------------------------------------------------------------------- /misc/media/hello-websocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/misc/media/hello-websocket.png -------------------------------------------------------------------------------- /misc/media/open-devtools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/misc/media/open-devtools.png -------------------------------------------------------------------------------- /misc/media/websockets-apikey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srinandan/istio-workshop/206c44abff30f1c3614b039a7605dc3977e5ac33/misc/media/websockets-apikey.png -------------------------------------------------------------------------------- /misc/websocket/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest as builder 2 | ADD . /go/src/websocket 3 | WORKDIR /go/src/websocket 4 | RUN go get github.com/gorilla/websocket 5 | COPY index.html . 6 | COPY src/main.go . 7 | RUN CGO_ENABLED=0 GOOS=linux go install 8 | EXPOSE 3000 9 | CMD ["/go/bin/websocket"] 10 | 11 | 12 | FROM alpine:latest 13 | RUN apk --no-cache add ca-certificates 14 | WORKDIR /root/ 15 | COPY --from=builder /go/bin/websocket . 16 | COPY index.html . 17 | EXPOSE 3000 18 | CMD ["./websocket"] -------------------------------------------------------------------------------- /misc/websocket/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "{}" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2016 Istio Authors 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /misc/websocket/README.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | This is a sample websocket based application. I'd like to thank [Michael Van Sickle](https://github.com/vansimke) for the Youtube videos and code. -------------------------------------------------------------------------------- /misc/websocket/dockerbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t websockets . -------------------------------------------------------------------------------- /misc/websocket/dockerpush.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker push gcr.io/$PROJECT_ID/websockets 3 | docker tag websockets gcr.io/$PROJECT_ID/websockets -------------------------------------------------------------------------------- /misc/websocket/dockerrun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker run -P -p 3000:3000 -d --name websocket websockets:latest -------------------------------------------------------------------------------- /misc/websocket/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Gorilla WebSocket 6 | 7 | 8 | 9 |

Hello WebSockets

10 | 11 | 12 | -------------------------------------------------------------------------------- /misc/websocket/src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gorilla/websocket" 6 | "net/http" 7 | ) 8 | 9 | var upgrader = websocket.Upgrader{} 10 | 11 | func main() { 12 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 13 | http.ServeFile(w, r, "index.html") 14 | }) 15 | 16 | http.HandleFunc("/v1/ws", func(w http.ResponseWriter, r *http.Request) { 17 | var conn, _ = upgrader.Upgrade(w, r, nil) 18 | go func(conn *websocket.Conn) { 19 | for { 20 | mType, msg, err := conn.ReadMessage() 21 | if err != nil { 22 | conn.Close() 23 | } else { 24 | fmt.Println(string(msg)) 25 | conn.WriteMessage(mType, []byte("helloworld")) 26 | } 27 | } 28 | }(conn) 29 | }) 30 | 31 | http.ListenAndServe(":3000", nil) 32 | } -------------------------------------------------------------------------------- /misc/websocket/websockets-api.yaml: -------------------------------------------------------------------------------- 1 | # Define an API 2 | apiVersion: config.istio.io/v1alpha2 3 | kind: HTTPAPISpec 4 | metadata: 5 | name: websocketsapi 6 | namespace: default 7 | spec: 8 | apiKeys: 9 | - query: apikey 10 | - header: x-api-key 11 | attributes: 12 | attributes: 13 | api.service: 14 | stringValue: websockets.default.svc.cluster.local 15 | api.version: 16 | stringValue: v1 17 | patterns: 18 | - attributes: 19 | attributes: 20 | api.operation: 21 | stringValue: /v1/ws 22 | httpMethod: GET 23 | uriTemplate: /v1/ws 24 | - attributes: 25 | attributes: 26 | api.service: 27 | stringValue: websockets.default.svc.cluster.local 28 | httpMethod: GET 29 | uriTemplate: / 30 | --- 31 | # Bind the API to a service 32 | apiVersion: config.istio.io/v1alpha2 33 | kind: HTTPAPISpecBinding 34 | metadata: 35 | creationTimestamp: null 36 | name: websocketsapi-binding 37 | namespace: default 38 | spec: 39 | api_specs: 40 | - name: websocketsapi 41 | namespace: default 42 | services: 43 | - name: websockets 44 | namespace: default -------------------------------------------------------------------------------- /misc/websocket/websockets-rule.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: config.istio.io/v1alpha2 2 | kind: rule 3 | metadata: 4 | name: websockets-rule 5 | namespace: istio-system 6 | spec: 7 | match: context.reporter.kind == "inbound" && destination.namespace == "default" && destination.service.name == "websockets" 8 | actions: 9 | - handler: apigee-handler.apigee.istio-system 10 | instances: 11 | - apigee.authorization -------------------------------------------------------------------------------- /misc/websocket/websockets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: websockets 5 | labels: 6 | app: websockets 7 | spec: 8 | ports: 9 | - port: 3000 10 | name: http 11 | selector: 12 | app: websockets 13 | --- 14 | apiVersion: extensions/v1beta1 15 | kind: Deployment 16 | metadata: 17 | creationTimestamp: null 18 | name: websockets-v1 19 | spec: 20 | replicas: 1 21 | template: 22 | metadata: 23 | labels: 24 | app: websockets 25 | version: v1 26 | spec: 27 | containers: 28 | - image: gcr.io/nandanks-151422/websockets 29 | imagePullPolicy: IfNotPresent 30 | name: websockets 31 | ports: 32 | - containerPort: 3000 33 | resources: 34 | requests: 35 | cpu: 100m 36 | --- 37 | apiVersion: networking.istio.io/v1alpha3 38 | kind: VirtualService 39 | metadata: 40 | name: helloworld 41 | namespace: default 42 | spec: 43 | gateways: 44 | - helloworld-gateway 45 | hosts: 46 | - '*' 47 | http: 48 | - match: 49 | - uri: 50 | exact: /hello 51 | route: 52 | - destination: 53 | host: helloworld 54 | port: 55 | number: 5000 56 | - match: 57 | - uri: 58 | exact: /v1/ws 59 | route: 60 | - destination: 61 | host: websockets 62 | port: 63 | number: 3000 64 | websocketUpgrade: true 65 | - match: 66 | - uri: 67 | exact: / 68 | route: 69 | - destination: 70 | host: websockets 71 | port: 72 | number: 3000 -------------------------------------------------------------------------------- /mtlstest/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | 3 | RUN apt-get update && apt-get install -y gnupg curl 4 | RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - 5 | RUN apt-get install -y nodejs 6 | 7 | # Upgrade npm 8 | RUN npm i npm@latest -g 9 | 10 | # Create a sample app 11 | RUN echo "var express = require('express');var app = express();app.get('/', function (req, res) {res.send('Hello World!');});app.listen(8080, function () {});" >> index.js 12 | RUN echo "{\"name\": \"mtlstest\",\"version\": \"1.0.0\",\"main\": \"index.js\",\"scripts\": {\"start\": \"node index.js\"},\"dependencies\": {\"express\": \"^4.16.1\"}}" >> package.json 13 | RUN npm install --save express 14 | EXPOSE 8080 15 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /mtlstest/bookinfo-add-serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: bookinfo-productpage 5 | --- 6 | apiVersion: extensions/v1beta1 7 | kind: Deployment 8 | metadata: 9 | name: productpage-v1 10 | spec: 11 | replicas: 1 12 | template: 13 | metadata: 14 | labels: 15 | app: productpage 16 | version: v1 17 | spec: 18 | serviceAccountName: bookinfo-productpage 19 | containers: 20 | - name: productpage 21 | image: istio/examples-bookinfo-productpage-v1:1.5.0 22 | imagePullPolicy: IfNotPresent 23 | ports: 24 | - containerPort: 9080 25 | -------------------------------------------------------------------------------- /mtlstest/dockerbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t mtlstest . 3 | docker tag mtlstest gcr.io/$PROJECT_ID/mtlstest:latest 4 | gcloud docker -- push gcr.io/$PROJECT_ID/mtlstest:latest 5 | -------------------------------------------------------------------------------- /mtlstest/k8ssetup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | kubectl create -f <(istioctl kube-inject -f mtlstest.yaml) --validate=true --dry-run=false 3 | -------------------------------------------------------------------------------- /mtlstest/mixer-rule-deny-others.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "config.istio.io/v1alpha2" 2 | kind: denier 3 | metadata: 4 | name: denyproductpagehandler 5 | spec: 6 | status: 7 | code: 7 8 | message: Not allowed 9 | --- 10 | apiVersion: "config.istio.io/v1alpha2" 11 | kind: checknothing 12 | metadata: 13 | name: denyproductpagerequest 14 | spec: 15 | --- 16 | apiVersion: "config.istio.io/v1alpha2" 17 | kind: rule 18 | metadata: 19 | name: denyproductpage 20 | spec: 21 | match: destination.labels["app"] == "details" && source.user != "cluster.local/ns/default/sa/bookinfo-productpage" 22 | actions: 23 | - handler: denyproductpagehandler.denier 24 | instances: [ denyproductpagerequest.checknothing ] 25 | -------------------------------------------------------------------------------- /mtlstest/mtlstest.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: mtlstest 5 | labels: 6 | app: mtlstest 7 | spec: 8 | ports: 9 | - port: 8080 10 | name: http 11 | selector: 12 | app: mtlstest 13 | --- 14 | apiVersion: extensions/v1beta1 15 | kind: Deployment 16 | metadata: 17 | name: mtlstest 18 | spec: 19 | replicas: 1 20 | template: 21 | metadata: 22 | labels: 23 | name: mtlstest 24 | spec: 25 | containers: 26 | - name: mtlstest 27 | image: gcr.io/PROJECT_ID/mtlstest:latest 28 | imagePullPolicy: Always 29 | ports: 30 | - containerPort: 8080 31 | -------------------------------------------------------------------------------- /multi/README.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | In this lab, you will learn how to install and configure a multi-cluster mesh 4 | 5 | # Table of Contents 6 | 7 | * [How does it work?](#how) 8 | * [Setup and Requirements](#setup-and-requirements) 9 | 10 | ## How does it work
11 | NOTE: I think this is an area of Istio that is rapidly changing (improving). The statements below are true for Istio 1.0. 12 | 13 | ### Prerequisites 14 | 15 | * Kubernetes v1.9 or higher; 1.10 is preferred. 16 | * Helm 2.7.2 or higher 17 | * Istio control plane installed on a Kubernetes cluster (which will be referred to as master) 18 | * All pod CIDRs in every cluster must be routable to each other 19 | 20 | ## Setup and Requirements 21 | 22 | *WORK IN PROGRESS* 23 | 24 | 1. Complete Istio installation on the master cluster as described in the previous labs. 25 | 26 | 2. Configing the remote cluster 27 | - Create a new GKE cluster 28 | - 29 | 30 | 3. Install a sample application in the remote cluster 31 | 32 | Create a file hello.yaml with the following contents 33 | 34 | ``` 35 | apiVersion: v1 36 | kind: Service 37 | metadata: 38 | name: helloworld 39 | labels: 40 | app: helloworld 41 | spec: 42 | ports: 43 | - port: 5000 44 | name: http 45 | selector: 46 | app: helloworld 47 | --- 48 | apiVersion: extensions/v1beta1 49 | kind: Deployment 50 | metadata: 51 | name: helloworld-v1 52 | spec: 53 | replicas: 1 54 | template: 55 | metadata: 56 | labels: 57 | app: helloworld 58 | version: v1 59 | spec: 60 | containers: 61 | - name: helloworld 62 | image: istio/examples-helloworld-v1 63 | resources: 64 | requests: 65 | cpu: "100m" 66 | imagePullPolicy: IfNotPresent #Always 67 | ports: 68 | - containerPort: 5000 69 | ``` 70 | 71 | ``` 72 | kubectl apply -f <(istioctl kube-inject -f hello.yaml)> 73 | ``` 74 | 75 | ## Testing the setup 76 | 77 | Get the Cluster IP of the details application (from the master cluster) 78 | 79 | ``` 80 | kubectl get svc 81 | ``` 82 | 83 | OUTPUT: 84 | ``` 85 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 86 | details ClusterIP 10.35.248.207 9080/TCP 18d 87 | ``` 88 | 89 | Access the bash shell in the helloworld application 90 | 91 | ``` 92 | kubectl exec -it helloworld-v1-c5c996c78-xw8d2 bash 93 | ``` 94 | 95 | Access the details IP with the cluster IP 96 | 97 | ``` 98 | curl 10.35.248.207:9080/details/0 99 | ``` 100 | OUTPUT: 101 | ``` 102 | {"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"} 103 | ``` 104 | 105 | ## Observations 106 | 107 | * At the moment, DNS is the responsibility of the user (Istio does not provide a solution) 108 | * There are a few options discussed in the community [here](https://groups.google.com/forum/#!topic/istio-users/MbG9DNT7Duk) -------------------------------------------------------------------------------- /rbac/istio-rbac-namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "config.istio.io/v1alpha2" 2 | kind: ServiceRole 3 | metadata: 4 | name: service-viewer 5 | namespace: default 6 | spec: 7 | rules: 8 | - services: ["*"] 9 | methods: ["GET"] 10 | constraints: 11 | - key: "app" 12 | values: ["productpage", "details", "reviews", "ratings","mtlstest"] 13 | --- 14 | apiVersion: "config.istio.io/v1alpha2" 15 | kind: ServiceRoleBinding 16 | metadata: 17 | name: bind-service-viewer 18 | namespace: default 19 | spec: 20 | subjects: 21 | - properties: 22 | namespace: "istio-system" 23 | - properties: 24 | namespace: "default" 25 | roleRef: 26 | kind: ServiceRole 27 | name: "service-viewer" --------------------------------------------------------------------------------