apisix/docs/en/latest/plugins/opa.md
Navendu Pottekkat b2f3273b6a
docs: update "Authentication" Plugins (#6824)
Co-authored-by: homeward <97138894+hf400159@users.noreply.github.com>
2022-04-15 09:05:25 +08:00

9.9 KiB

title keywords description
opa
APISIX
Plugin
Open Policy Agent
opa
This document contains information about the Apache APISIX opa Plugin.

Description

The opa Plugin can be used to integrate with Open Policy Agent. This can help you decouple functions such as authentication and access to services and reduce the complexity of your system.

Attributes

Name Type Required Default Valid values Description
host string True Host address of the OPA service. For example, https://localhost:8181.
ssl_verify boolean False true When set to true verifies the SSL certificates.
policy string True OPA policy path. A combination of package and decision. While using advanced features like custom response, you can omit decision.
timeout integer False 3000ms [1, 60000]ms Timeout for the HTTP call.
keepalive boolean False true When set to true, keeps the connection alive for multiple requests.
keepalive_timeout integer False 60000ms [1000, ...]ms Idle time after which the connection is closed.
keepalive_pool integer False 5 [1, ...]ms Connection pool limit.
with_route boolean False false When set to true, sends information about the current Route.
with_service boolean False false When set to true, sends information about the current Service.
with_consumer boolean False false When set to true, sends information about the current Consumer. Note that this may send sensitive information like the API key. Make sure to turn it on only when you are sure it is safe.

Data definition

APISIX to OPA service

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

{
    "type": "http",
    "request": {
        "scheme": "http",
        "path": "\/get",
        "headers": {
            "user-agent": "curl\/7.68.0",
            "accept": "*\/*",
            "host": "127.0.0.1:9080"
        },
        "query": {},
        "port": 9080,
        "method": "GET",
        "host": "127.0.0.1"
    },
    "var": {
        "timestamp": 1701234567,
        "server_addr": "127.0.0.1",
        "server_port": "9080",
        "remote_port": "port",
        "remote_addr": "ip address"
    },
    "route": {},
    "service": {},
    "consumer": {}
}

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.

OPA service to APISIX

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

{
    "result": {
        "allow": true,
        "reason": "test",
        "headers": {
            "an": "header"
        },
        "status_code": 401
    }
}

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.

Example usage

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

docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s

Basic usage

Once you have the OPA service running, you can create a basic policy:

curl -X PUT '127.0.0.1:8181/v1/policies/example1' \
    -H 'Content-Type: text/plain' \
    -d 'package example1

import input.request

default allow = false

allow {
    # HTTP method must GET
    request.method == "GET"
}'

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

curl -X PUT 'http://127.0.0.1:9080/apisix/admin/routes/r1' \
    -H 'X-API-KEY: <api-key>' \
    -H 'Content-Type: application/json' \
    -d '{
    "uri": "/*",
    "plugins": {
        "opa": {
            "host": "http://127.0.0.1:8181",
            "policy": "example1"
        }
    },
    "upstream": {
        "nodes": {
            "httpbin.org:80": 1
        },
        "type": "roundrobin"
    }
}'

Now, to test it out:

curl -i -X GET 127.0.0.1:9080/get
HTTP/1.1 200 OK

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

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

Using custom response

You can also configure custom responses for more complex scenarios:

curl -X PUT '127.0.0.1:8181/v1/policies/example2' \
    -H 'Content-Type: text/plain' \
    -d 'package example2

import input.request

default allow = false

allow {
    request.method == "GET"
}

# custom response body (Accepts a string or an object, the object will respond as JSON format)
reason = "test" {
    not allow
}

# custom response header (The data of the object can be written in this way)
headers = {
    "Location": "http://example.com/auth"
} {
    not allow
}

# custom response status code
status_code = 302 {
    not allow
}'

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

curl -i -X GET 127.0.0.1:9080/get
HTTP/1.1 200 OK

Now if you make a failing request, you will see the custom response from the OPA service:

curl -i -X POST 127.0.0.1:9080/post
HTTP/1.1 302 FOUND
Location: http://example.com/auth

test

Sending APISIX data

Let's think about another scenario, when your decision needs to use some APISIX data, such as route, consumer, 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:

curl -X PUT '127.0.0.1:8181/v1/policies/echo' \
    -H 'Content-Type: text/plain' \
    -d 'package echo

allow = false
reason = input'

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

curl -X PUT 'http://127.0.0.1:9080/apisix/admin/routes/r1' \
    -H 'X-API-KEY: <api-key>' \
    -H 'Content-Type: application/json' \
    -d '{
    "uri": "/*",
    "plugins": {
        "opa": {
            "host": "http://127.0.0.1:8181",
            "policy": "echo",
            "with_route": true
        }
    },
    "upstream": {
        "nodes": {
            "httpbin.org:80": 1
        },
        "type": "roundrobin"
    }
}'

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

curl -X GET 127.0.0.1:9080/get
{
    "type": "http",
    "request": {
        xxx
    },
    "var": {
        xxx
    },
    "route": {
        xxx
    }
}

Disable Plugin

To disable the opa Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect.

curl http://127.0.0.1:2379/apisix/admin/routes/1 -X PUT -d value='
{
    "methods": ["GET"],
    "uri": "/hello",
    "plugins": {},
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:1980": 1
        }
    }
}'