{{ define "title" }}Open Policy Agent{{ end }} {{ define "content" }}
{{ partial "nav.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

OPA is now maintained by Styra and a large community of contributors

## Declarative Policy

Context-aware, Expressive, Fast, Portable

    {
        "apiVersion": "admission.k8s.io/v1",
        "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

    import rego.v1

    deny contains sprintf("image '%s' comes from untrusted registry", [container.image]) if {
    	input.request.kind.kind == "Pod"
    	some container in input.request.object.spec.containers
    	not startswith(container.image, "hooli.com/")
    }

    {
        "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

    import rego.v1

    # Reject any ingress with the same host as an existing ingress
    deny contains msg if {
    	input.request.kind.kind == "Ingress"

    	# iterate over all hosts in input Ingress
    	some rule in input.request.object.spec.rules
    	newhost := rule.host

    	# iterate over all existing ingresses and all hosts for each ingress
    	some namespace, name
    	some oldrule in data.kubernetes.ingresses[namespace][name].spec.rules
    	oldhost := oldrule.host

    	# reject if the oldhost and the newhost are the same
    	newhost == oldhost
    	msg := sprintf("ingress host conflicts with ingress %s/%s", [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

    import rego.v1

    # allow all GET requests to /pets
    default allow := false

    allow if {
    	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 rego.v1

    # allow only the frontend service to GET /pets/owners
    default allow := false

    allow if {
    	http_request.path == "/pets/owners"
    	http_request.method == "GET"
    	source_spiffe_id == "spiffe://domain.test/frontend"
    }

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

    http_request := input.attributes.request.http

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

                                        package application.authz

    import rego.v1

    # Only owner can update the pet's information
    # Ownership information is provided as part of OPA's input
    default allow := false

    allow if {
    	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

    import rego.v1

    # Everyone can see pets up for adoption
    allowed_pets contains pet if {
    	some pet in input.pet_list
    	pet.up_for_adoption
    }

    # Employees can see all pets.
    allowed_pets contains pet if {
    	[_, payload, _] := io.jwt.decode(input.token)
    	payload.employee
    	some pet in input.pet_list
    }

## 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

    import rego.v1

    deny contains sprintf("image '%s' comes from untrusted registry", [container.image]) if {
    	input.request.kind.kind == "Pod"
    	some container in input.request.object.spec.containers
    	not startswith(container.image, "hooli.com/")
    }

    {
        "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

    import rego.v1

    # Reject any ingress with the same host as an existing ingress
    deny contains msg if {
    	input.request.kind.kind == "Ingress"

    	# iterate over all hosts in input Ingress
    	some rule in input.request.object.spec.rules
    	newhost := rule.host

    	# iterate over all existing ingresses and all hosts for each ingress
    	some namespace, name
    	some oldrule in data.kubernetes.ingresses[namespace][name].spec.rules
    	oldhost := oldrule.host

    	# reject if the oldhost and the newhost are the same
    	newhost == oldhost
    	msg := sprintf("ingress host conflicts with ingress %s/%s", [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

    import future.keywords

    # allow all GET requests to /pets
    default allow := false

    allow if {
    	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 future.keywords
    import input.attributes.request.http as http_request

    # allow only the frontend service to GET /pets/owners
    default allow := false

    allow if {
    	http_request.path == "/pets/owners"
    	http_request.method == "GET"
    	source_spiffe_id == "spiffe://domain.test/frontend"
    }

    source_spiffe_id = client_id if {
    	[_, _, 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

    import rego.v1

    # Only owner can update the pet's information
    # Ownership information is provided as part of OPA's input
    default allow := false

    allow if {
    	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

    import rego.v1

    # Everyone can see pets up for adoption
    allowed_pets contains pet if {
    	some pet in input.pet_list
    	pet.up_for_adoption
    }

    # Employees can see all pets.
    allowed_pets contains pet if {
    	[_, payload, _] := io.jwt.decode(input.token)
    	payload.employee
    	some pet in input.pet_list
    }

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 150+ 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
VS Code Rego Playground General Tooling OPA GitHub
{{ end }}