Integrate with Python¶
Preface¶
This guide will explain how to delegate authorization decisions to OPA from a Python application via the OPA REST API.
Note
This guide assumes you have deployed an OPA instance with a system package as described in the policy writing guide - see the Helm or docker-compose deployment guide for instructions on OPA deployment.
Dependencies¶
We will use the following dependencies:
Example
[project]
dependencies = [
"requests==2.31.0",
"pydantic==2.6.4"
]
Serializing Input Data¶
OPA expects a JSON object as it's input, with the exact fields depending on the policy being involked - we will assume our policy requires a subject
name, an action
which is either "read"
or "write"
and an item_id
. This can therefore be represented as a pydatnic
BaseModel
which consists of the required fields - where the action
is represented by the Action
Enum
.
from enum import Enum
from pydantic import BaseModel
class Action(Enum):
Read = "read"
Write = "write"
class Input(BaseModel):
subject: str
action: Action
item_id: int
We can now create an instance of this input as so:
opa_input = Input(subject="bob", action=Action.Read, item_id=42)
Making the Request¶
We will use requests
to POST
to the opa root path - shown henceforth as http://opa:8181/
. To do this we will simply call requests.post
with the OPA root query URL; we will serialize the input as json using the model_dump_json
method and pass it to the optional body
argument.
response = requests.post("http://opa:8181/", data=opa_input.model_dump_json())
Note
We are assuming the response will be OK
(200
). In a real application, you should check the response.code
and handle such cases appropriately.
Interpreting the Decision¶
OPA returns a decision as a JSON object, with the exact fields depending on the policy being involked - we will assume our policy returns only an allow
boolean. This can therefore be represented as the pydantic
BaseModel
Decision
, which contains the allow
field.
class Decision(BaseModel):
allow: bool
We can now deserialize the response of OPA using the model_validate_json
method on the Decision
class with the response
text
as the argument:
decision = Decision.model_validate_json(response.text)
Finally, we can access the allow
field of the decision
and print it to stdout:
print(f"Allowed: {decision.allow}")
Complete Code
import requests
from enum import Enum
from pydantic import BaseModel
class Action(Enum):
Read = "read"
Write = "write"
class Input(BaseModel):
subject: str
action: Action
item_id: int
class Decision(BaseModel):
allow: bool
if __name__ == "__main__":
opa_input = Input(subject="bob", action=Action.Read, item_id=42)
response = requests.post("http://opa:8181/", data=opa_input.model_dump_json())
decision = Decision.model_validate_json(response.text)
print(f"Allowed: {decision.allow}")