Project: Open Policy Agent (OPA) (Provisioning / Security & Compliance)
File: envoy-tutorial-gloo-edge.md

title: "Tutorial: Gloo Edge" kind: envoy weight: 11 is an Envoy based API Gateway that provides a Kubernetes CRD to manage Envoy configuration for performing traffic management and routing. Gloo Edge allows creation of a that implements the Envoy spec for an . The purpose of this tutorial is to show how OPA could be used with Gloo Edge to apply security policies for upstream services. This tutorial requires Kubernetes 1.14 or later. To run the tutorial locally, we recommend using in version v1.0+ with Kubernetes 1.14+. The tutorial also requires to install Gloo Edge on a Kubernetes cluster. ```bash minikube start ``` ```bash helm repo add gloo https://storage.googleapis.com/solo-public-helm helm upgrade --install --namespace gloo-system --create-namespace gloo gloo/gloo kubectl config set-context $(kubectl config current-context) --namespace=gloo-system ``` Ensure all the pods are running using `kubectl get pod` command. define a set of route rules, security configuration, rate limiting, transformations, and other core routing capabilities supported by Gloo Edge. define destinations for routes. Save the configuration as vs.yaml. ```yaml apiVersion: gloo.solo.io/v1 kind: Upstream metadata: name: httpbin spec: static: hosts: addr: httpbin.org port: 80 apiVersion: gateway.solo.io/v1 kind: VirtualService metadata: name: httpbin spec: virtualHost: domains: '*' routes: matchers: prefix: / routeAction: single: upstream: name: httpbin namespace: gloo-system options: autoHostRewrite: true ``` ```bash kubectl apply -f vs.yaml ``` For simplification port-forwarding will be used. Open another terminal and execute. ```bash kubectl port-forward deployment/gateway-proxy 8080:8080 ``` The `VirtualService` created in the previous step forwards requests to http://httpbin.org Let's test that Gloo works properly by running the below command in the first terminal. ```bash curl -XGET -Is localhost:8080/get | head -n 1 HTTP/1.1 200 OK curl http -XPOST -Is localhost:8080/post | head -n1 HTTP/1.1 200 OK ``` The following OPA policy will work as follows: Alice is granted a guest* role and can perform `GET` requests. Bob is granted an admin* role and can perform `GET` and `POST` requests. policy.rego ```live:example:module:openable package envoy.authz import rego.v1 import input.attributes.request.http as http_request default allow := false allow if { istokenvalid action_allowed } istokenvalid if { token.valid now := time.now_ns() / 1000000000 token.payload.nbf <= now now < token.payload.exp } action_allowed if { http_request.method == "GET" token.payload.role == "guest" } action_allowed if { http_request.method == "GET" token.payload.role == "admin" } action_allowed if { http_request.method == "POST" token.payload.role == "admin" } token := {"valid": valid, "payload": payload} if { [, encoded] := split(httprequest.headers.authorization, " ") [valid, , payload] := io.jwt.decodeverify(encoded, {"secret": "secret"}) } ``` A sample input can be seen below using Alice's token, Alice should be able to `GET` but not `POST` ```live:example:input { "attributes": { "request": { "http": { "method": "GET", "headers": { "authorization": "Bearer

} } } } } ``` With the input value above, the answer is: ```live:example:output ``` Next we build an OPA bundle. ```bash opa build policy.rego ``` And now we serve the OPA bundle created above using Nginx. ```bash docker run --rm --name bundle-server -d -p 8888:80 -v ${PWD}:/usr/share/nginx/html:ro nginx:latest ``` Create a deployment as shown below and save it in deployments.yaml ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: opa labels: app: opa spec: replicas: 1 selector: matchLabels: app: opa template: metadata: labels: app: opa spec: containers: name: opa image: openpolicyagent/opa:{{< currentopaenvoydockerversion >}} volumeMounts: readOnly: true mountPath: /policy name: opa-policy args: "run" "--server" "--addr=0.0.0.0:8181" "--set=services.default.url=http://host.minikube.internal:8888" "--set=bundles.default.resource=bundle.tar.gz" "--set=plugins.envoyextauthz_grpc.addr=0.0.0.0:9191" "--set=plugins.envoyextauthz_grpc.path=envoy/authz/allow" "--set=decision_logs.console=true" "--set=status.console=true" "--ignore=.*" volumes: name: opa-policy ``` ```bash kubectl apply -f deployments.yaml ``` Ensure all pods are running using `kubectl get pod` command. Next, define a Kubernetes `service` for OPA-Envoy. This is required to create a DNS record and thereby create a Gloo `Upstream` object. service.yaml ```yaml apiVersion: v1 kind: Service metadata: name: opa spec: selector: app: opa ports: name: grpc protocol: TCP port: 9191 targetPort: 9191 ``` Note: Since the name of the service port is `grpc`, `Gloo` will understand that traffic should be routed using HTTP2 protocol. `kubectl apply -f service.yaml` To use OPA as a custom auth server, we need to add the `extauth` attribute as described below: gloo.yaml ```yaml global: extensions: extAuth: extauthzServerRef: name: gloo-system-opa-9191 namespace: gloo-system ``` To apply it, run the following command: ```bash helm upgrade --install --namespace gloo-system --create-namespace -f gloo.yaml gloo gloo/gloo ``` Configure Gloo Edge routes to perform authorization via configured extauth before regular processing. vs-patch.yaml ```yaml spec: virtualHost: options: extauth: customAuth: {} ``` Then apply the patch to our `VirtualService` as shown below: ```bash kubectl patch vs httpbin --type=merge --patch "$(cat vs-patch.yaml)" ``` Before we exercise the policy, for convenience sake, we will want to store Alice and Bob's tokens in environment variables as such: ```bash export ALICETOKEN="eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJleHAiOiAyMjQxMDgxNTM5LCAibmJmIjogMTUxNDg1MTEzOSwgInJvbGUiOiAiZ3Vlc3QiLCAic3ViIjogIllXeHBZMlU9In0.Uk5hgUqMuUfDLvBLnlXMD0-X53aMHlziqg3vhOsCc8" export BOBTOKEN="eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJleHAiOiAyMjQxMDgxNTM5LCAibmJmIjogMTUxNDg1MTEzOSwgInJvbGUiOiAiYWRtaW4iLCAic3ViIjogIlltOWkifQ.5qsm7rRTvqFHAgiB6evX0ahWnGbWquZC0HImVQPQo8" ``` Now let's verify that OPA only allows Alice to perform `GET` requests. ```bash curl -XGET -Is -H "Authorization: Bearer $ALICE_TOKEN" localhost:8080/get HTTP/1.1 200 OK ``` And with a `POST` request, we get: ```bash curl http -XPOST -Is -H "Authorization: Bearer $ALICE_TOKEN" localhost:8080/post HTTP/1.1 403 Forbidden ``` And for Bob, we should be able to `GET` and `POST`: ```bash curl -XGET -Is -H "Authorization: Bearer $BOB_TOKEN" localhost:8080/get HTTP/1.1 200 OK ``` And the `POST`: ```bash curl http -XPOST -Is -H "Authorization: Bearer $BOB_TOKEN" localhost:8080/post HTTP/1.1 200 OK ``` Check OPA's decision logs to view the inputs received by OPA from Gloo Edge and the results generated by OPA. ```bash kubectl logs deployment/opa -n gloo-system ``` Congratulations for finishing the tutorial! This tutorial showed how you can use OPA with to apply security policies for upstream services and how to create and test a policy that would allow `GET` or `POST` requests based on your user role.