opa

    The JSON below shows the data sent to the OPA service by APISIX:

    Each of these keys are explained below:

    • type indicates the request type (http or stream).
    • request is used when the type is http and contains the basic request information (URL, headers etc).
    • var contains the basic information about the requested connection (IP, port, request timestamp etc).
    • route, service and consumer contains the same data as stored in APISIX and are only sent if the opa Plugin is configured on these objects.

    The JSON below shows the response from the OPA service to APISIX:

    1. {
    2. "result": {
    3. "allow": true,
    4. "reason": "test",
    5. "headers": {
    6. "an": "header"
    7. },
    8. "status_code": 401
    9. }
    10. }

    The keys in the response are explained below:

    • allow is indispensable and indicates whether the request is allowed to be forwarded through APISIX.
    • reason, headers, and status_code are optional and are only returned when you configure a custom response. See the next section use cases for this.

    First, you need to launch the Open Policy Agent environment:

    1. docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s
    1. curl -X PUT '127.0.0.1:8181/v1/policies/example1' \
    2. -H 'Content-Type: text/plain' \
    3. -d 'package example1
    4. import input.request
    5. default allow = false
    6. allow {
    7. # HTTP method must GET
    8. request.method == "GET"
    9. }'

    Then, you can configure the opa Plugin on a specific Route:

    1. curl -X PUT 'http://127.0.0.1:9080/apisix/admin/routes/r1' \
    2. -H 'X-API-KEY: <api-key>' \
    3. -H 'Content-Type: application/json' \
    4. -d '{
    5. "uri": "/*",
    6. "plugins": {
    7. "host": "http://127.0.0.1:8181",
    8. }
    9. },
    10. "upstream": {
    11. "nodes": {
    12. "httpbin.org:80": 1
    13. },
    14. "type": "roundrobin"
    15. }
    16. }'

    Now, to test it out:

    1. curl -i -X GET 127.0.0.1:9080/get

    Now if we try to make a request to a different endpoint the request will fail:

    1. curl -i -X POST 127.0.0.1:9080/post
    1. HTTP/1.1 403 FORBIDDEN

    You can also configure custom responses for more complex scenarios:

    1. curl -X PUT '127.0.0.1:8181/v1/policies/example2' \
    2. -H 'Content-Type: text/plain' \
    3. -d 'package example2
    4. import input.request
    5. default allow = false
    6. allow {
    7. request.method == "GET"
    8. }
    9. # custom response body (Accepts a string or an object, the object will respond as JSON format)
    10. reason = "test" {
    11. not allow
    12. }
    13. # custom response header (The data of the object can be written in this way)
    14. headers = {
    15. "Location": "http://example.com/auth"
    16. } {
    17. not allow
    18. }
    19. # custom response status code
    20. status_code = 302 {
    21. not allow
    22. }'

    Now you can test it out by changing the opa Plugin’s policy parameter to example2 and then making a request:

    1. curl -i -X GET 127.0.0.1:9080/get
    1. HTTP/1.1 200 OK
    1. HTTP/1.1 302 FOUND
    2. Location: http://example.com/auth
    3. test

    Let’s think about another scenario, when your decision needs to use some APISIX data, such as route, , etc., how should we do it?

    If your OPA service needs to make decisions based on APISIX data like Route and Consumer details, you can configure the Plugin to do so.

    The example below shows a simple echo policy which will return the data sent by APISIX as it is:

    1. curl -X PUT '127.0.0.1:8181/v1/policies/echo' \
    2. -d 'package echo
    3. allow = false
    4. reason = input'

    Now we can configure the Plugin on the Route to send APISIX data:

    1. curl -X PUT 'http://127.0.0.1:9080/apisix/admin/routes/r1' \
    2. -H 'X-API-KEY: <api-key>' \
    3. -H 'Content-Type: application/json' \
    4. -d '{
    5. "uri": "/*",
    6. "plugins": {
    7. "opa": {
    8. "host": "http://127.0.0.1:8181",
    9. "policy": "echo",
    10. "with_route": true
    11. }
    12. },
    13. "upstream": {
    14. "nodes": {
    15. "httpbin.org:80": 1
    16. },
    17. "type": "roundrobin"
    18. }
    19. }'

    Now if you make a request, you can see the data from the Route through the custom response:

    1. curl -X GET 127.0.0.1:9080/get
    2. {
    3. "type": "http",
    4. "request": {
    5. xxx
    6. },
    7. "var": {
    8. xxx
    9. },
    10. "route": {
    11. xxx
    12. }
    13. }
    1. curl http://127.0.0.1:2379/apisix/admin/routes/1 -X PUT -d value='
    2. {
    3. "methods": ["GET"],
    4. "uri": "/hello",
    5. "plugins": {},
    6. "upstream": {
    7. "type": "roundrobin",
    8. "nodes": {
    9. "127.0.0.1:1980": 1
    10. }
    11. }