# Open Policy Agent

{{ define "main" }}
{{ partial "google-analytics.html" . }} {{ partial "meta.html" . }}
Policy-based control for cloud native environments
Flexible, fine-grained control for administrators across the stack

Stop using a different policy language, policy model, and policy API for every product and service you use. Use OPA for a unified toolset and framework for policy across the cloud native stack.

Whether for one service or for all your services, use OPA to decouple policy from the service's code so you can release, analyze, and review policies (which security and compliance teams love) without sacrificing availability or performance.

Created By

## Declarative Policy

Context-aware, Expressive, Fast, Portable

    {
        "apiVersion": "admission.k8s.io/v1beta1",
        "kind": "AdmissionReview",
        "request": {
            "kind": {
                "group": "",
                "kind": "Pod",
                "version": "v1"
            },
            "object": {
                "metadata": {
                    "name": "myapp"
                },
                "spec": {
                    "containers": [
                        {
                            "image": "nginx",
                            "name": "nginx-frontend"
                        },
                        {
                            "image": "mysql",
                            "name": "mysql-backend"
                        }
                    ]
                }
            }
        }
    }

                                              package kubernetes.admission

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

    {
        "apiVersion": "admission.k8s.io/v1beta1",
        "kind": "AdmissionReview",
        "request": {
            "kind": {
                "group": "extensions",
                "kind": "Ingress",
                "version": "v1beta1"
            },
            "object": {
                "metadata": {
                    "name": "prod",
                    "namespace": "bar"
                },
                "spec": {
                    "rules": [
                        {
                            "host": "initech.com",
                            "http": {
                                "paths": [
                                    {
                                        "backend": {
                                            "serviceName": "banking",
                                            "servicePort": 443
                                        },
                                        "path": "/finance"
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        }
    }

                                          package kubernetes.admission
    # Reject any ingress with the same host as an existing ingress
    deny[msg] {
        input.request.kind.kind == "Ingress"
        # iterate over all hosts in input Ingress
        some i
        newhost := input.request.object.spec.rules[i].host
        # iterate over all existing ingresses and all hosts for each ingress
        some namespace, name, j
        oldhost := data.kubernetes.ingresses[namespace][name].spec.rules[j].host
        # reject if the oldhost and the newhost are the same
        newhost == oldhost
        msg := sprintf("ingress host conflicts with ingress %v/%v", [namespace, name])
    }

    {
        "attributes": {
            "destination": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 8000
                            },
                            "address": "172.17.0.8"
                        }
                    }
                }
            },
            "request": {
                "http": {
                    "headers": {
                        ":authority": "example-app",
                        ":method": "GET",
                        ":path": "/pets",
                        "user-agent": "Wget",
                        "x-forwarded-proto": "http",
                        "x-request-id": "4d75f8d5-983f-4ec5-92bb-d27e620b4921"
                    },
                    "host": "example-app",
                    "id": "8910035251488566126",
                    "method": "GET",
                    "path": "/pets",
                    "protocol": "HTTP/1.1"
                }
            },
            "source": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 54292
                            },
                            "address": "172.17.0.6"
                        }
                    }
                }
            }
        },
        "parsed_path": [
            "pets"
        ]
    }

                                        package envoy.authz

    # allow all GET requests to /pets
    default allow = false
    allow {
        input.attributes.request.http.method == "GET"
        input.attributes.request.http.path == "/pets"
    }

    {
        "attributes": {
            "destination": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 8000
                            },
                            "address": "172.17.0.8"
                        }
                    }
                }
            },
            "request": {
                "http": {
                    "headers": {
                        ":authority": "example-app",
                        ":method": "GET",
                        ":path": "/pets/owners",
                        "user-agent": "Wget",
                        "x-forwarded-client-cert": "By=spiffe://domain.test/db-server;Hash=331f2f4eb2a1729fa4e0f46c8c663786098151ae571fed7b66680e970f6a0f94;URI=spiffe://domain.test/frontend",
                        "x-forwarded-proto": "http",
                        "x-request-id": "4d75f8d5-983f-4ec5-92bb-d27e620b4921"
                    },
                    "host": "example-app",
                    "id": "8910035251488566126",
                    "method": "GET",
                    "path": "/pets/owners",
                    "protocol": "HTTP/1.1"
                }
            },
            "source": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 54292
                            },
                            "address": "172.17.0.6"
                        }
                    }
                }
            }
        },
        "parsed_path": [
            "pets",
            "owners"
        ]
    }

                                            package envoy.authz
    import input.attributes.request.http as http_request

    # allow only the frontend service to GET /pets/owners
    default allow = false
    allow {
        http_request.path == "/pets/owners"
        http_request.method == "GET"
        source_spiffe_id == "spiffe://domain.test/frontend"
    }

    source_spiffe_id = client_id {
        [_, _, uri_type_san] := split(http_request.headers["x-forwarded-client-cert"], ";")
        [_, client_id] := split(uri_type_san, "=")
    }

    {
        "method": "PUT",
        "owner": "bob@hooli.com",
        "path": [
            "pets",
            "pet113-987"
        ],
        "user": "alice@hooli.com"
    }

                                        package application.authz

    # Only owner can update the pet's information
    # Ownership information is provided as part of OPA's input
    default allow = false
    allow {
        input.method == "PUT"
        some petid
        input.path = ["pets", petid]
        input.user == input.owner
    }

    {
        "pet_list": [
            {
                "breed": "St. Bernard",
                "name": "Cujo",
                "up_for_adoption": false
            },
            {
                "breed": "Collie",
                "name": "Lassie",
                "up_for_adoption": true
            }
        ],
        "token": "eyJ1IjoiSFMyNTYiLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpY2UiLCJlbXBsb3llZSI6dHJ1ZSwibmFtZSI6IkFsaWNlIFNtaXRoIn0.vMBYEW8VK9XM7yPkKTu1C3Gy1tOq1A0d4-xYMkkRpEc"
    }

    package application.authz

    # Everyone can see adopted pets
    allowed_pets[pet] {
        some i
        pet := input.pet_list[i]
        pet.up_for_adoption == true
    }

    # Employees can see all pets.
    allowed_pets[pet] {
        [header, payload, signature] := io.jwt.decode(input.token)
        payload.employee == true
        some i
        pet := input.pet_list[i]
    }

## Declarative Policy

Context-aware, Expressive, Fast, Portable

Kubernetes

Envoy

Application

Kubernetes

    {
        "apiVersion": "admission.k8s.io/v1beta1",
        "kind": "AdmissionReview",
        "request": {
            "kind": {
                "group": "",
                "kind": "Pod",
                "version": "v1"
            },
            "object": {
                "metadata": {
                    "name": "myapp"
                },
                "spec": {
                    "containers": [
                        {
                            "image": "nginx",
                            "name": "nginx-frontend"
                        },
                        {
                            "image": "mysql",
                            "name": "mysql-backend"
                        }
                    ]
                }
            }
        }
    }

                                  package kubernetes.admission

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

    {
        "apiVersion": "admission.k8s.io/v1beta1",
        "kind": "AdmissionReview",
        "request": {
            "kind": {
                "group": "extensions",
                "kind": "Ingress",
                "version": "v1beta1"
            },
            "object": {
                "metadata": {
                    "name": "prod",
                    "namespace": "bar"
                },
                "spec": {
                    "rules": [
                        {
                            "host": "initech.com",
                            "http": {
                                "paths": [
                                    {
                                        "backend": {
                                            "serviceName": "banking",
                                            "servicePort": 443
                                        },
                                        "path": "/finance"
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        }
    }

                                  package kubernetes.admission

    # Reject any ingress with the same host as an existing ingress
    deny[msg] {
        input.request.kind.kind == "Ingress"
        # iterate over all hosts in input Ingress
        some i
        newhost := input.request.object.spec.rules[i].host
        # iterate over all existing ingresses and all hosts for each ingress
        some namespace, name, j
        oldhost := data.kubernetes.ingresses[namespace][name].spec.rules[j].host
        # reject if the oldhost and the newhost are the same
        newhost == oldhost
        msg := sprintf("ingress host conflicts with ingress %v/%v", [namespace, name])
    }

Envoy

    {
        "attributes": {
            "destination": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 8000
                            },
                            "address": "172.17.0.8"
                        }
                    }
                }
            },
            "request": {
                "http": {
                    "headers": {
                        ":authority": "example-app",
                        ":method": "GET",
                        ":path": "/pets",
                        "user-agent": "Wget",
                        "x-forwarded-proto": "http",
                        "x-request-id": "4d75f8d5-983f-4ec5-92bb-d27e620b4921"
                    },
                    "host": "example-app",
                    "id": "8910035251488566126",
                    "method": "GET",
                    "path": "/pets",
                    "protocol": "HTTP/1.1"
                }
            },
            "source": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 54292
                            },
                            "address": "172.17.0.6"
                        }
                    }
                }
            }
        },
        "parsed_path": [
            "pets"
        ]
    }

                                  package envoy.authz

    # allow all GET requests to /pets
    default allow = false
    allow {
        input.attributes.request.http.method == "GET"
        input.attributes.request.http.path == "/pets"
    }

    {
        "attributes": {
            "destination": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 8000
                            },
                            "address": "172.17.0.8"
                        }
                    }
                }
            },
            "request": {
                "http": {
                    "headers": {
                        ":authority": "example-app",
                        ":method": "GET",
                        ":path": "/pets/owners",
                        "user-agent": "Wget",
                        "x-forwarded-client-cert": "By=spiffe://domain.test/db-server;Hash=331f2f4eb2a1729fa4e0f46c8c663786098151ae571fed7b66680e970f6a0f94;URI=spiffe://domain.test/frontend",
                        "x-forwarded-proto": "http",
                        "x-request-id": "4d75f8d5-983f-4ec5-92bb-d27e620b4921"
                    },
                    "host": "example-app",
                    "id": "8910035251488566126",
                    "method": "GET",
                    "path": "/pets/owners",
                    "protocol": "HTTP/1.1"
                }
            },
            "source": {
                "address": {
                    "Address": {
                        "SocketAddress": {
                            "PortSpecifier": {
                                "PortValue": 54292
                            },
                            "address": "172.17.0.6"
                        }
                    }
                }
            }
        },
        "parsed_path": [
            "pets",
            "owners"
        ]
    }

                                  package envoy.authz
    import input.attributes.request.http as http_request

    # allow only the frontend service to GET /pets/owners
    default allow = false
    allow {
        http_request.path == "/pets/owners"
        http_request.method == "GET"
        source_spiffe_id == "spiffe://domain.test/frontend"
    }

    source_spiffe_id = client_id {
        [_, _, uri_type_san] := split(http_request.headers["x-forwarded-client-cert"], ";")
        [_, client_id] := split(uri_type_san, "=")
    }

Application

    {
        "method": "PUT",
        "owner": "bob@hooli.com",
        "path": [
            "pets",
            "pet113-987"
        ],
        "user": "alice@hooli.com"
    }

                                  package application.authz

    # Only owner can update the pet's information
    # Ownership information is provided as part of OPA's input
    default allow = false
    allow {
        input.method == "PUT"
        some petid
        input.path = ["pets", petid]
        input.user == input.owner
    }

    {
        "pet_list": [
            {
                "breed": "St. Bernard",
                "name": "Cujo",
                "up_for_adoption": false
            },
            {
                "breed": "Collie",
                "name": "Lassie",
                "up_for_adoption": true
            }
        ],
        "token": "eyJ1IjoiSFMyNTYiLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWxpY2UiLCJlbXBsb3llZSI6dHJ1ZSwibmFtZSI6IkFsaWNlIFNtaXRoIn0.vMBYEW8VK9XM7yPkKTu1C3Gy1tOq1A0d4-xYMkkRpEc"
    }

    package application.authz

    # Everyone can see adopted pets
    allowed_pets[pet] {
        some i
        pet := input.pet_list[i]
        pet.up_for_adoption == true
    }

    # Employees can see all pets.
    allowed_pets[pet] {
        [header, payload, signature] := io.jwt.decode(input.token)
        payload.employee == true
        some i
        pet := input.pet_list[i]
    }

Declarative. Express policy in a high-level, declarative language that promotes safe, performant, fine-grained controls. Use a language purpose-built for policy in a world where JSON is pervasive. Iterate, traverse hierarchies, and apply 50+ built-ins like string manipulation and JWT decoding to declare the policies you want enforced.

Context-aware. Leverage external information to write the policies you really care about. Stop inventing roles that represent complex relationships that years down the road no one will understand. Instead, write logic that adapts to the world around it and attach that logic to the systems that need it.

Learn More
Kubernetes Envoy Terraform Kafka SQL Linux

## Architectural Flexibility

Balance integration, availability, consistency

### Daemon

### Service

Policy
(Rego)
Data
(JSON)

Deploy OPA as a separate process on the same host as your service. Integrate OPA by changing your service’s code, importing an OPA-enabled library, or using a network proxy integrated with OPA.

### Library

### Service

Policy
(Rego)
Data
(JSON)

Embed OPA policies into your service. Integrate OPA as a Go library that evaluates policy, or integrate a WebAssembly runtime and use OPA to compile policy to WebAssembly instructions.

Learn More
Daemon Library

## Tools for Policy Authoring

IDEs, Sharing, Profiling, Testing, Coverage

#### Rego Playground for Policy Sharing

#### VS Code for Policy Authoring

#### CLI and REPL for complete control

OPA embraces policy-as-code, complete with tools that help people use and understand the policies they put in place. Integrated development environments, testing, profiling, coverage, automated performance tuning, and hot reloading aren’t just things you need for programming--you need them for policy too, and OPA delivers.

Learn More
VScode Rego Playground General Tooling
{{ end }}