PageSourceSearch

https://www.openpolicyagent.org/assets/js/8a41d9ee.5c3d9225.js

js openpolicyagent.org collected 2026-09-24 08:31:18 UTC 15,943 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkopa_website=self.webpackChunkopa_website||[]).push([[28792],{28453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var i=n(96540);const s={},o=i.createContext(s);function a(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(o.Provider,{value:t},e.children)}},68996:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"envoy/tutorial-istio","title":"Tutorial: Istio","description":"Istio is an open source service mesh for managing the different microservices that make","source":"@site/docs/envoy/tutorial-istio.md","sourceDirName":"envoy","slug":"/envoy/tutorial-istio","permalink":"/docs/envoy/tutorial-istio","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":3,"frontMatter":{"title":"Tutorial: Istio","sidebar_position":3},"sidebar":"docsSidebar","previous":{"title":"Tutorial: Standalone Envoy","permalink":"/docs/envoy/tutorial-standalone-envoy"},"next":{"title":"Tutorial: Gloo Edge","permalink":"/docs/envoy/tutorial-gloo-edge"}}');var s=n(74848),o=n(28453);const a={title:"Tutorial: Istio",sidebar_position:3},r=void 0,l={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Steps",id:"steps",level:2},{value:"1. Install OPA-Envoy",id:"1-install-opa-envoy",level:3},{value:"2. Configure the mesh to define the external authorizer",id:"2-configure-the-mesh-to-define-the-external-authorizer",level:3},{value:"3. Enable automatic injection of the Istio Proxy and OPA-Envoy sidecars in the namespace where the app will be deployed, e.g., <code>default</code>",id:"3-enable-automatic-injection-of-the-istio-proxy-and-opa-envoy-sidecars-in-the-namespace-where-the-app-will-be-deployed-eg-default",level:3},{value:"4. Deploy the BookInfo application and make it accessible outside the cluster",id:"4-deploy-the-bookinfo-application-and-make-it-accessible-outside-the-cluster",level:3},{value:"5. Set the <code>SERVICE_HOST</code> environment variable in your shell to the public IP/port of the Istio Ingress gateway",id:"5-set-the-service_host-environment-variable-in-your-shell-to-the-public-ipport-of-the-istio-ingress-gateway",level:3},{value:"6. Exercise the OPA policy",id:"6-exercise-the-opa-policy",level:3},{value:"Summary",id:"summary",level:2}];function d(e){const t={a:"a",blockquote:"blockquote",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components},{RunSnippet:n}=t;return n||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("RunSnippet",!0),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.a,{href:"https://istio.io/latest/",children:"Istio"})," is an open source service mesh for managing the different microservices that make\nup a cloud-native application. Istio provides a mechanism to use a service as an external authorizer with the\n",(0,s.jsx)(t.a,{href:"https://istio.io/latest/docs/tasks/security/authorization/authz-custom/",children:"AuthorizationPolicy API"}),"."]}),"\n",(0,s.jsx)(t.p,{children:"This tutorial shows how Istio's AuthorizationPolicy can be configured to delegate authorization decisions to OPA."}),"\n",(0,s.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsxs)(t.p,{children:["This tutorial requires Kubernetes 1.20 or later. To run the tutorial locally ensure you start a cluster with Kubernetes\nversion 1.20+, for example ",(0,s.jsx)(t.a,{href:"https://kubernetes.io/docs/setup/",children:"minikube"})," or\n",(0,s.jsx)(t.a,{href:"https://kind.sigs.k8s.io/",children:"KIND"}),"."]}),"\n",(0,s.jsxs)(t.p,{children:["The tutorial also requires Istio v1.19.0 or later. It assumes you have Istio deployed on top of Kubernetes.\nSee Istio's ",(0,s.jsx)(t.a,{href:"https://istio.io/latest/docs/setup/install/helm/",children:"Helm Install"})," page to get started."]}),"\n",(0,s.jsxs)(t.p,{children:["If you are using an earlier version of Istio (1.9+), you will have to customize the ",(0,s.jsx)(t.code,{children:"AuthorizationPolicy"})," in the\n",(0,s.jsx)(t.code,{children:"quick_start.yaml"})," file to use the ",(0,s.jsx)(t.code,{children:"security.istio.io/v1beta1"})," API version instead of ",(0,s.jsx)(t.code,{children:"security.istio.io/v1"}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"steps",children:"Steps"}),"\n",(0,s.jsx)(t.h3,{id:"1-install-opa-envoy",children:"1. Install OPA-Envoy"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/opa-envoy-plugin/main/examples/istio/quick_start.yaml\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"quick_start.yaml"})," manifest defines the following resources:"]}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsxs)(t.p,{children:["AuthorizationPolicy to direct authorization checks to the OPA-Envoy sidecar. See ",(0,s.jsx)(t.code,{children:"kubectl -n {$NAMESPACE} get authorizationpolicy ext-authz"})," for details."]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsxs)(t.p,{children:["ServiceEntry to allow Istio to find the OPA-Envoy sidecars. See ",(0,s.jsx)(t.code,{children:"kubectl -n {$NAMESPACE} get serviceentry opa-ext-authz-grpc-local"})," for details."]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsxs)(t.p,{children:["Kubernetes namespace (",(0,s.jsx)(t.code,{children:"opa-istio"}),") for OPA-Envoy control plane components."]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsxs)(t.p,{children:["Kubernetes admission controller in the ",(0,s.jsx)(t.code,{children:"opa-istio"})," namespace that automatically injects the OPA-Envoy sidecar into pods in namespaces labelled with ",(0,s.jsx)(t.code,{children:"opa-istio-injection=enabled"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsxs)(t.p,{children:["OPA configuration file and an OPA policy into ConfigMaps in the namespace where the app will be deployed, e.g., ",(0,s.jsx)(t.code,{children:"default"}),".\nThe following is the example OPA policy:"]}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["alice is granted a ",(0,s.jsx)(t.strong,{children:"guest"})," role and can perform a ",(0,s.jsx)(t.code,{children:"GET"})," request to ",(0,s.jsx)(t.code,{children:"/productpage"}),"."]}),"\n",(0,s.jsxs)(t.li,{children:["bob is granted an ",(0,s.jsx)(t.strong,{children:"admin"})," role and can perform a ",(0,s.jsx)(t.code,{children:"GET"})," to ",(0,s.jsx)(t.code,{children:"/productpage"})," and ",(0,s.jsx)(t.code,{children:"/api/v1/products"}),"."]}),"\n"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-rego",metastring:'title="authz.rego"',children:'package istio.authz\n\ndefault allow := false\n\nallow if {\n    input.parsed_path[0] == "health"\n    input.attributes.request.method == "GET"\n}\n\nallow if {\n    some user_role in _user_roles[_user_name]\n    some permission in _role_permissions[user_role]\n\n    permission.method == input.attributes.request.http.method\n    permission.path == input.attributes.request.http.path\n}\n\n# Underscore prefix used only to signal that rules and functions are\n# intended to be referenced only within the same policy, i.e. "private".\n# It has no special meaning to OPA.\n\n_user_name := parsed if {\n    [_, encoded] := split(input.attributes.request.http.headers.authorization, " ")\n    [parsed, _] := split(base64url.decode(encoded), ":")\n}
1\n\n_user_roles := {\n    "alice": ["guest"],\n    "bob": ["admin"],\n}\n\n_role_permissions := {\n    "guest": [{"method": "GET", "path": "/productpage"}],\n    "admin": [\n        {"method": "GET", "path": "/productpage"},\n        {"method": "GET", "path": "/api/v1/products"},\n    ],\n}\n'})}),"\n",(0,s.jsx)(n,{id:"authz.rego"}),"\n",(0,s.jsxs)(t.p,{children:["OPA is configured to query for the ",(0,s.jsx)(t.code,{children:"data.istio.authz.allow"}),"\ndecision. If the response is ",(0,s.jsx)(t.code,{children:"true"})," the operation is allowed, otherwise the\noperation is denied. Sample input received by OPA is shown below:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-json",metastring:'title="input.json"',children:'{\n  "attributes": {\n    "request": {\n      "http": {\n        "method": "GET",\n        "path": "/productpage",\n        "headers": {\n          "authorization": "Basic YWxpY2U6cGFzc3dvcmQ="\n        }\n      }\n    }\n  }\n}\n'})}),"\n",(0,s.jsx)(n,{id:"input.json"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-rego",children:"package example\n\nresult := data.istio.authz.allow\n"})}),"\n",(0,s.jsx)(n,{files:"#input.json #authz.rego",command:"data.example.result"}),"\n",(0,s.jsxs)(t.p,{children:["An example of the complete input received by OPA can be seen ",(0,s.jsx)(t.a,{href:"https://github.com/open-policy-agent/opa-envoy-plugin/tree/main/examples/istio#example-input",children:"in the Istio examples"}),"."]}),"\n",(0,s.jsxs)(t.blockquote,{children:["\n",(0,s.jsxs)(t.p,{children:["In typical deployments the policy would either be built into the OPA container\nimage or it would be fetched dynamically via the ",(0,s.jsx)(t.a,{href:"../management-bundles/",children:"Bundle API"}),". ConfigMaps are\nused in this tutorial for test purposes."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"2-configure-the-mesh-to-define-the-external-authorizer",children:"2. Configure the mesh to define the external authorizer"}),"\n",(0,s.jsxs)(t.p,{children:["Edit the mesh configmap with ",(0,s.jsx)(t.code,{children:"kubectl edit configmap -n istio-system istio"})," and define the external provider:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"data:\n  mesh: |-\n    # Add the following lines to define the ServiceEntry previously created as an external authorizer:\n    extensionProviders:\n    - name: opa-ext-authz-grpc\n      envoyExtAuthzGrpc:\n        service: opa-ext-authz-grpc.local\n        port: 9191\n"})}),"\n",(0,s.jsxs)(t.p,{children:["See ",(0,s.jsx)(t.a,{href:"https://istio.io/latest/docs/tasks/security/authorization/authz-custom/#define-the-external-authorizer",children:"the Istio Docs for AuthorizationPolicy"})," for\nmore details."]}),"\n",(0,s.jsxs)(t.p,{children:["The format of the service value is ",(0,s.jsx)(t.code,{children:"[<Namespace>/]<Hostname>"}),". The specification\nof ",(0,s.jsx)(t.code,{children:"<Namespace>"})," is required only when it is insufficient to unambiguously resolve\na service in the service registry. See also the ",(0,s.jsx)(t.a,{href:"https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig-ExtensionProvider-EnvoyExternalAuthorizationGrpcProvider",children:"configuration documentation"}),".\nExample: ",(0,s.jsx)(t.code,{children:"opa-ext-authz-grpc.foo.svc.cluster.local"})," or\n",(0,s.jsx)(t.code,{children:"bar/opa-ext-authz-grpc.local"}),"."]}),"\n",(0,s.jsxs)(t.h3,{id:"3-enable-automatic-injection-of-the-istio-proxy-and-opa-envoy-sidecars-in-the-namespace-where-the-app-will-be-deployed-eg-default",children:["3. Enable automatic injection of the Istio Proxy and OPA-Envoy sidecars in the namespace where the app will be deployed, e.g., ",(0,s.jsx)(t.code,{children:"default"})]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:'kubectl label namespace default opa-istio-injection="enabled"\nkubectl label namespace default istio-injection="enabled"\n'})}),"\n",(0,s.jsx)(t.h3,{id:"4-deploy-the-bookinfo-application-and-make-it-accessible-outside-the-cluster",children:"4. Deploy the BookInfo application and make it accessible outside the cluster"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl apply -f https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/platform/kube/bookinfo.yaml\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl apply -f https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/networking/bookinfo-gateway.yaml\n"})}),"\n",(0,s.jsxs)(t.h3,{id:"5-set-the-service_host-environment-variable-in-your-shell-to-the-public-ipport-of-the-istio-ingress-gateway",children:["5. Set the ",(0,s.jsx)(t.code,{children:"SERVICE_HOST"})," environment variable in your shell to the public IP/port of the Istio Ingress gateway"]}),"\n",(0,s.jsx)(t.p,{children:"Run this command in a new terminal window to start a Minikube tunnel that sends traffic to your Istio Ingress Gateway:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{children:"minikube tunnel\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Check that the Service shows an ",(0,s.jsx)(t.code,{children:"EXTERNAL-IP"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl -n istio-system get service istio-ingressgateway\n\nNAME                   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                      AGE\nistio-ingressgateway   LoadBalancer   10.98.42.178   127.0.0.1     15021:32290/TCP,80:30283/TCP,443:32497/TCP,31400:30216/TCP,15443:30690/TCP   5s\n"})}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"minikube:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"export SERVICE_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\n"})}),"\n",(0,s.jsxs)(t.p,{children:["For other platforms see the ",(0,s.jsx)(t.a,{href:"https://istio.io/docs/tasks/traffic-management/ingress/#determining-the-ingress-ip-and-ports",children:"Istio documentation on determining ingress IP and ports."})]}),"\n",(0,s.jsx)(t.h3,{id:"6-exercise-the-opa-policy",children:"6. Exercise the OPA policy"}),"\n",(0,s.jsxs)(t.p,{children:["Check that ",(0,s.jsx)(t.strong,{children:"alice"})," can access ",(0,s.jsx)(t.code,{children:"/productpage"})," ",(0,s.jsx)(t.strong,{children:"BUT NOT"})," ",(0,s.jsx)(t.code,{children:"/api/v1/products"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"curl --user alice:password -i http://$SERVICE_HOST/productpage\
1ncurl --user alice:password -i http://$SERVICE_HOST/api/v1/products\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Check that ",(0,s.jsx)(t.strong,{children:"bob"})," can access ",(0,s.jsx)(t.code,{children:"/productpage"})," ",(0,s.jsx)(t.strong,{children:"AND"})," ",(0,s.jsx)(t.code,{children:"/api/v1/products"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"curl --user bob:password -i http://$SERVICE_HOST/productpage\ncurl --user bob:password -i http://$SERVICE_HOST/api/v1/products\n"})}),"\n",(0,s.jsx)(t.h2,{id:"summary",children:"Summary"}),"\n",(0,s.jsxs)(t.p,{children:["This tutorial showed how Istio's ",(0,s.jsx)(t.a,{href:"https://istio.io/latest/docs/tasks/security/authorization/authz-custom/",children:"AuthorizationPolicy API"}),"\ncan be configured to use OPA as an External authorization service."]}),"\n",(0,s.jsxs)(t.p,{children:["This tutorial also showed a sample OPA policy that returns a ",(0,s.jsx)(t.code,{children:"boolean"})," decision\nto indicate whether a request should be allowed or not."]}),"\n",(0,s.jsxs)(t.p,{children:["More details about the tutorial can be seen\n",(0,s.jsx)(t.a,{href:"https://github.com/open-policy-agent/opa-envoy-plugin/tree/main/examples/istio",children:"in the opa-envoy-plugin Istio examples"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.