OPA takes care of Authorization, not Authentication but is also often used as a back end service for Admissions Controllers.

The exam won’t have us write policy files but we should know how to work with them and what they do.

Install OPA:

curl -L -o opa https://github.com/open-policy-agent/opa/releases/download/v0.11.0/opa_linux_amd64
chmod 755 ./opa
./opa run -s

Output:

{"addrs":[":8181"],"insecure_addr":"","level":"info","msg":"First line of log 
stream.","time":"2021-03-18T20:25:38+08:00"}

Note: By default authentication and authorization are disabled.

An example OPA rule in the Rego policy language: example.rego

# example.rego
package httpapi.authz

# HTTP API request
import input

default allow = false

allow {
  input.path == "home"
  input.user == "john"
}

Install the rule. Default port is 8181

curl -X PUT --data-binary @example.rego http://localhost:8181/v1/policies/example1
curl http://localhost:8181/v1/policies

Simple example of using the above rule in Python:

@app.route('/home')
def hello_world():

  user = request.args.get("user")
  # Create a dict to send to OPA
  input_dict = {
    "input": {
    "user": user,
    "path": "home",  
    }
  }

  # This is our OPA endpoint
  rsp = requests.post("http://127.0.0.1:8181/..authz", json=input_dict)
   
  if not rsp.json()["result"]["allow"]:
    return 'Unauthorized!', 401
  
  return 'Welcome Home!', 200

Videos to Watch to Learn More about OPA

How Netflix Is Solving Authorization Across Their Cloud - Manish Mehta & Torin Sandall, Netflix
https://www.youtube.com/watch?v=R6tUNpRpdnY

OPA Deep Dive
https://www.youtube.com/watch?v=4mBJSIhs2xQ

OPA in Kubernetes

With OPA in Kubernetes we can point our Validating and Mutating Webhooks at OPA instead of creating our own server and hosting the API

An example of a Validating Webhook Configuration pointing to the k8s service for an OPA install

apiVersion: admissionregistration.k8s.io/v1beta1 
kind: ValidatingWebhookConfiguration
metadata:
  name: opa-validating-webhook
webhooks:
  - name: validating-webhook.openpolicyagent.org
    rules:
    - operations: ["CREATE", "UPDATE"]
      apiGroups: ["*"]
      apiVersions: ["*"]
      resources: ["*"]

    clientConfig:
      caBundle: $(cat ca.crt | base64 | tr -d '\n')
      service:
        namespace: opa
        name: opa

Example data coming in for a pod creation

{
  "kind": "AdmissionReview",
  "request": {
    "kind": {
      "kind": "Pod",
      "version": "v1"
    },
    "object": {
      "metadata": {
        "name": "myapp"
      },
      "spec": {
        "containers": [
          {
          "image": "nginx",
          "name": "nginx-frontend"
          },
          {
          "image": "mysql",
          "name": "mysql-backend"
          }
        ]
      }
    }
  }
}

Validating against this policy

// kubernetes.rego
package kubernetes.admission

deny[msg] {
  input.request.kind.kind == "Pod" 
  image := input.request.object.spec.containers[_].image
  startswith(image, "hooli.com/") 
  msg := sprintf("image '%v' from untrusted registry", [image])
}

https://www.openpolicyagent.org/docs/latest/kubernetes-primer/

When installed in k8s we insert the .rego via a ConfigMap

kind: ConfigMap
apiVersion: v1
metadata:
  name: policy-unique-podname
  namespace: opa
  labels:
    openpolicyagent.org/policy: rego
data:
  main: |
    package kubernetes.admission

    import data.kubernetes.pods

    deny[msg]{
      input.request.kind.kind == "Pod"
      input_pod_name := input.request.object.metadata.name
      other_pod_names := pods[other_ns][other_name].metadata.name
      input_pod_name == other_pod_names
      msg := sprintf("Podname '%v' already exists")
    }

When we install OPA into Kubernetes a sidecar called kube-mgmt is created in the OPA pod
This side car loads Kubernetes objects so OPA knows what resources are deployed, it also loads ConfigMap policies into OPA that have labels of openpolicyagent.org/policy: rego as shown in the above example

References