About

Gloo Mesh Gateway can deploy an Open Policy Agent (OPA) server to run as a sidecar to its external auth service. After, you are responsible for administering the server per OPA best practices. You might choose this approach for larger scale environments and extended use cases such as bundling and caching.

With bundling, your Rego rules can live as a signed bundle in an external, central location, such as an AWS S3 bucket to meet your internal security requirements. This sidecar approach increases the resources needed in the external auth server pod, but works better at scale and provides more OPA-native support for teams familiar with administering an OPA server. You also get the OPA-Envoy plugin API as part of the Gloo external auth service.

For different setup options such as the default OPA or bring your own OPA, see OPA implementation optionsOPA implementation options.

Architecture

The following diagram and the steps in the rest of this guide show how you can set up an OPA server sidecar.

Figure: Architecture for deploying an OPA server sidecar.
Figure: Architecture for deploying an OPA server sidecar.
Figure: Architecture for deploying an OPA server sidecar.
Figure: Architecture for deploying an OPA server sidecar.

  1. A user sends a request that the ingress gateway receives. The request matches a route that is protected by an ExtAuthPolicy that uses OPA.
  2. The ingress gateway sends the request to the external auth service for an authorization decision.
  3. The external auth service passes the request through to the OPA server sidecar to make an authorization decision.
  4. The OPA server sidecar loads the OPA config of Rego rules from a bundle in a cloud provider. The OPA server uses these Rego rules to make an authorization decision on the request. You can provide the OPA config via a YAML file during the Helm installation, or subsequently in a Kubernetes config map. Note that the request does not trigger loading the rules. You must restart the OPA server each time that you update the OPA config.
  5. The OPA server returns the authorization decision to the external auth service, which returns the authorization decision to the ingress gateway.
  6. The ingress gateway handles the request per the authorization decision.
    • If unauthorized, the ingress gateway denies the request.
    • If authorized, the ingress gateway forwards the request to the destination workload.

Clear route cache

The Envoy proxy in your sidecar instance keeps a route cache in memory of precomputed routing decisions to help speed up performance. When the sidecar gets a request, it can check the route cache to decide where to send the request. When the route cache is cleared, Gloo recomputes the routing rules. This way, any old and potentially conflicting data from the initial request is cleared.

Before you begin

  1. Set up Gloo Mesh Gateway in a single cluster.

  2. Install Bookinfo and other sample apps.

  3. Configure an HTTP listener on your gateway and set up basic routing for the sample apps.

  4. Make sure that the external auth service is installed and running. If not, install the external auth service in your Gloo environment.

      kubectl get pods -A -l app=ext-auth-service
      
  5. Download the opa CLI tool.

  6. Get the external address of your ingress gateway. The steps vary depending on the type of load balancer that backs the ingress gateway.

  export INGRESS_GW_ADDRESS=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
echo $INGRESS_GW_ADDRESS
  

Note: Depending on your environment, you might see <pending> instead of an external IP address. For example, if you are testing locally in kind or minikube, or if you have insufficient permissions in your cloud platform, you can instead port-forward the service port of the ingress gateway:

  kubectl -n gloo-mesh-gateways port-forward deploy/istio-ingressgateway-1-24 8081
  

Bundle Rego rules

Prepare OPA configuration for the OPA server by creating, bundling, and referring to a Rego policy with the rules you want to enforce.

  1. Create a Rego policy file in a rego directory with the rules you want to enforce with OPA. The following policy allows GET and POST HTTP requests and denies requests to the /status endpoint.

      mkdir rego
    cat <<EOF > rego/policy.rego
    package httpbin
    
    import input.http_request
    
    # deny requests by default
    default allowed = false
    
    # set allowed to true if no error message
    allowed {
        not body
    }
    
    # return result and error message
    allow["allowed"] = allowed
    allow["body"] = body
    
    # main policy logic, with error message per rule
    body = "HTTP verb is not allowed" { not http_verb_allowed }
    else = "Path is not allowed" { not path_allowed }
    
    # allow only GET and POST requests
    http_verb_allowed {
       {"GET", "POST"}[_] == http_request.method
    }
    
    # deny requests to /status endpoint
    path_allowed {
       not startswith(http_request.path, "/status")
    }
    EOF
      
  2. Create another Rego policy. The following policy uses metadata that is enabled by the OPA-Envoy plugin API. This example shows how you can use OPA to evaluate and transform responses based on request metadata.

  • Check requests for an api-key header, with valid API keys either set to the test value of test-apikey or located in data.apikeys. The API keys in data.apikeys are loaded as part of the data bundle.
  • If the request is authorized, the api-key header is removed.
  • If the request is not authorized, the body is set to Unauthorized Request and returned to the client with a 403 status code, along with a reject-reason response header.
  • In both cases, the x-response-header is added.
  cat <<EOF > rego/apikey_policies.rego
package apikey_policies

import future.keywords.if

default allow := false

allow { api_key_allowed }

api_key_allowed { api_key == "test-apikey" } api_key_allowed { has_key(data.apikeys, api_key) }

api_key := input.http_request.headers["api-key"]

http_status := 200 { allow }

http_status := 403 { not allow }

body := "Unauthorized Request" { http_status == 403 }

headers["x-ext-auth-allow"] := "yes" if api_key_allowed headers["x-validated-by"] := "security-checkpoint" if api_key_allowed

request_headers_to_remove := ["api-key"]

response_headers_to_add["x-response-header"] := "for-client-only" response_headers_to_add["reject-reason"] := "unauthorized" if not allow

Helper function to check if a dictionary has a key

has_key(dict, k) { dict[k] } EOF

Use the `opa` CLI to bundle your Rego rules. The output of the command is a `bundle.tar.gz` compressed file in your current directory. For more information, see the [OPA docs](https://www.openpolicyagent.org/docs/latest/management-bundles/).