OPA authorization

This feature is available with a Gloo Mesh Gateway license only.

The Open Policy Agent (OPA) is an open source, general-purpose policy engine that can be used to define and enforce versatile policies in a uniform way across your organization. Compared to an RBAC authorization system, OPA allows you to create more fine-grained policies. For more information, see the official docs.

Table of Contents

Setup

First, we need to install Gloo Mesh Enterprise (minimum version 1.1) with extauth enabled. Please refer to the corresponding installation guide for details.

This guide makes use of the Bookinfo sample application. You can install the application by following the steps in the Bookinfo deployment section.

OPA policy overview

Open Policy Agent policies are written in Rego. The Rego language is inspired from Datalog, which in turn is a subset of Prolog. Rego is more suited to work with modern JSON documents.

Gloo Mesh's OPA integration will populate an input document which can be used in your OPA policies. The structure of the input document depends on the context of the incoming request. See the following section for details.

OPA input structure

Validate requests attributes with Open Policy Agent

Creating a Virtual Gateway

Now let's configure Gloo Mesh Gateway to route requests to the destination we just created. To do that, we define a simple Virtual Gateway to match all requests that:

apiVersion: networking.enterprise.mesh.gloo.solo.io/v1beta1
kind: VirtualGateway
metadata:
  labels:
    app: bookinfo-policies
    app.kubernetes.io/name: bookinfo-policies
  name: test-inlined-gateway
  namespace: bookinfo
spec:
  connectionHandlers:
    - http:
        routeConfig:
          - virtualHost:
              domains:
                - www.example.com
              routes:
                - matchers:
                    - uri:
                        prefix: /ratings
                  name: ratings
                  options: {}
                  routeAction:
                    destinations:
                      - kubeService:
                          clusterName: mgmt.cluster
                          name: ratings
                          namespace: bookinfo
  ingressGatewaySelectors:
    - destinationSelectors:
        - kubeServiceMatcher:
            clusters:
              - mgmt.cluster
            labels:
              istio: ingressgateway-ns
            namespaces:
              - istio-system
      portName: http2

Let's send a request that matches the above route to the Gloo Mesh gateway and make sure it works:

curl -v $(BOOKINFO_INGRESS_GATEWAY_URL)/ratings/1 -H "Host: www.example.com"

The above command should return:

{"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}

Securing the Virtual Gateway

As we just saw, we were able to reach the destination without having to provide any credentials. This is because by default Gloo Mesh allows any request on routes that do not specify authentication configuration. Let's change this behavior. We will update the Virtual Gateway so that only requests that comply with a given OPA policy are allowed.

Define an OPA policy

Let's create a Policy to control which actions are allowed on our service:

cat <<EOF > policy.rego
package test

default allow = false
allow {
    startswith(input.http_request.path, "/ratings/2")
    input.http_request.method == "GET"
}
allow {
    input.http_request.path == "/ratings/3"
    any({input.http_request.method == "GET",
        input.http_request.method == "DELETE"
    })
}
EOF

This policy:

Create an OPA AuthConfig CRD

Gloo Mesh expects OPA policies to be stored in a Kubernetes ConfigMap, so let's go ahead and create a ConfigMap with the contents of the above policy file:

kubectl -n bookinfo create configmap allow-get-users --from-file=policy.rego

Now we can create an AuthConfig CRD with our OPA authorization configuration:

apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
  name: opa
  namespace: bookinfo
spec:
  configs:
  - opaAuth:
      modules:
      - name: allow-get-users
        namespace: bookinfo
      query: "data.test.allow == true"

The above AuthConfig references the ConfigMap (modules) we created earlier and adds a query that allows access only if the allow variable is true.

Updating the Virtual Gateway

Once the AuthConfig has been created, we can use it to secure our Virtual Gateway:

apiVersion: networking.enterprise.mesh.gloo.solo.io/v1beta1
kind: VirtualGateway
metadata:
  labels:
    app: bookinfo-policies
    app.kubernetes.io/name: bookinfo-policies
  name: test-inlined-gateway
  namespace: bookinfo
spec:
  connectionHandlers:
    - http:
        routeConfig:
          - virtualHost:
              domains:
                - www.example.com
              routes:
                - matchers:
                    - uri:
                        prefix: /ratings
                  name: ratings
                  options:
                    extauth:
                      configRef:
                        name: opa
                        namespace: bookinfo
                  routeAction:
                    destinations:
                      - kubeService:
                          clusterName: mgmt.cluster
                          name: ratings
                          namespace: bookinfo
  ingressGatewaySelectors:
    - destinationSelectors:
        - kubeServiceMatcher:
            clusters:
              - mgmt.cluster
            labels:
              istio: ingressgateway-ns
            namespaces:
              - istio-system
      portName: http2

Testing the configuration

Paths that start with /ratings/1 are not authorized (should return 403):

curl -v $(BOOKINFO_INGRESS_GATEWAY_URL)/ratings/1 -H "Host: www.example.com"

Allowed to get ratings/2:

curl -v $(BOOKINFO_INGRESS_GATEWAY_URL)/ratings/2 -H "Host: www.example.com"

Cleanup

You can clean up the resources created in this guide by running:

kubectl delete vg -n bookinfo test-inlined-gateway
kubectl delete ac -n bookinfo opa
kubectl delete cm -n bookinfo allow-get-users
rm policy.rego