Apache APISIX Authorization Policy: Protect Your APIs

Qi Guo

Qi Guo

April 21, 2023

Technology

Introduction

Nowadays, APIs have become the bridge connecting various systems and applications in terms of data and functionality. While enjoying the convenience of APIs, ensuring data security and avoiding data leakage and other security issues have become users' primary concerns. At this point, access control plays a crucial role. By formulating appropriate access control policies for APIs, not only can you protect APIs from enormous cyber attacks and ensure data security, but you can also help companies meet compliance requirements and enhance customer trust.

Apache APISIX is a dynamic, real-time, high-performance cloud-native API gateway that offers a rich set of traffic management features such as load balancing, dynamic upstream, canary release, service circuit breaker, authentication, and observability. In this article, we will introduce the access control policies of Apache APISIX and discuss which common strategies can be used to protect your API security and ensure the stable operation of your system.

What Is an Access Control Policy?

Access control policies are security mechanisms designed to protect sensitive data or resources in computer systems, networks, or applications, ensuring that only authorized users or applications can access them. This helps reduce the risk of data leakage and security vulnerabilities. In an API gateway, access control policies are an essential component. As the entry point for all traffic, the API gateway is responsible for receiving and forwarding all API requests. Therefore, the access control policies of the API gateway directly determine the security and stability of upstream services.

Common Access Control Policies in Apache APISIX

Apache APISIX offers a rich set of access control policies, supporting the OAuth 2.0 authentication protocol and integrating with various external authentication services such as Keycloak, Ory Hydra, Okta, Auth0, and more. In addition to supporting external authentication services, APISIX also provides powerful internal authentication methods. Combined with APISIX's Consumer object, you can freely mix and match authentication, authorization, rate limiting, IP blacklisting, and whitelisting plugins to protect your APIs and effectively prevent malicious requests from damaging your API services.

schematic

1. IP-based Access Control

IP-based access control is the simplest and most direct method, which can restrict access to your API only to requests from specific addresses.

You can use APISIX's ip-restriction plugin to enable this feature, which offers various configuration options, such as allowed or denied IP address lists, IP address ranges, and error messages returned when denying requests. You can configure these options according to your needs to achieve finer-grained access control. It's worth noting that IP-based access control may have some limitations, as IP addresses can be spoofed or shared. Therefore, when using the ip-restriction plugin, it's best to combine it with other access control plugins to improve the security and flexibility of your system.

2. API Key-based Access Control

This access control is a very common API access control strategy. Its basic principle is to authenticate and authorize requests through a pre-generated API Key, which can quickly add authentication mechanisms to APIs. However, it's important to protect the API Key to prevent it from leaking and suffering malicious attacks.

APISIX's key-auth plugin can easily add authentication mechanisms to your APIs, by adding the key to the query string or header for authentication when sending requests. In APISIX version 3.1 and later, it also supports encrypting and storing API Keys in etcd using the encrypted storage fields data_encryption configuration, further enhancing the security of your API.

3. Token-based Access Control

This method is implemented by adding an authentication field containing a token in the request header. A token is a key, usually, a string or number, used to verify whether the sender of an API request has permission to access the API. Typically, a token contains the user's identity and permissions, allowing the server to determine whether the user has access permission when they initiate an API request and make appropriate authorization or denial decisions.

APISIX provides the jwt-auth plugin to use this access control strategy, supporting configuration options like token storage location, token validity period, JWT signature algorithm, and keys. You can configure these options according to your needs to meet different authentication requirements.

4. Request Path-based Access Control

Request path-based access control is achieved by filtering and matching request paths to control access to specific APIs, services, or resources. This strategy is commonly used in scenarios requiring fine-grained access control over resources, such as protecting sensitive data or controlling specific users' access to specific resources within the system.

APISIX's uri-blocker plugin supports configuring regex rule lists to intercept user request URIs, and configuring rejected_code and rejected_msg to specify the HTTP status code and response body returned after the successful interception. This allows administrators to finely control user permissions and improve API security and controllability.

5. ACL-based Access Control Policy

ACL (Access Control List) is a list-based access control policy used to control user or user group access permissions to resources. Its basic principle is to define an ACL list for each resource, listing the users or user groups allowed to access the resource. When a user requests access to the resource, their access is determined based on the corresponding ACL list.

In APISIX, we can use the consumer-restriction to enable this feature. Administrators can easily control which users or user groups can access specific resources and prevent unauthorized users from sending requests to sensitive areas, avoiding sensitive data leaks.

Scenario Introduction: Finer-Grained Access Control

In real-world application scenarios, we often implement finer-grained access control for resources containing sensitive data. For example, we now have two users, A and B, who use the same internal authentication methods, such as key-auth or basic-auth. We also want to apply finer-grained access control to user B, prohibiting them from accessing certain APIs.

schematic_2

We can use APISIX's consumer-restriction plugin for some finer-grained control. This plugin allows you to set access restrictions based on Route, Service, or Consumer, and it supports configuring four type attribute values:

  • consumer_name: Restrict Consumer access to Route or Service by listing the Consumer's username in a whitelist or blacklist.
  • consumer_group_id: Restrict Consumer access to Route or Service by listing the Consumer Group's id in a whitelist or blacklist.
  • service_id: Restrict Consumer access to Service by listing the Service's id in a whitelist or blacklist. This has to be used in conjunction with an authorization plugin.
  • route_id: Restrict Consumer access to Route by listing the Route's id in a whitelist or blacklist.

In this scenario, we can use two configuration methods to prevent user B from accessing a specific API resource.

Setting Access Control Policy in Route

  1. First, we need to create two Consumer objects on APISIX and enable the basic-auth plugin, with names userA and userB.
curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: {YOUR_API_KEY}' -X PUT -i -d '
{
  "username": "userA",
  "plugins": {
    "basic-auth": {
      "username":"userA",
      "password": "123456"
    }
  }
}'
curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: {YOUR_API_KEY}' -X PUT -i -d '
{
  "username": "userB",
  "plugins": {
    "basic-auth": {
      "username":"userB",
      "password": "123456"
    }
  }
}'
  1. Then we enable and configure the whitelist property of consumer-restriction on the route where we need to apply the restriction and add the username of the previously created consumer userA. This way, the route will only accept requests from userA.
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: {YOUR_API_KEY}' -X PUT -d '
{
  "uri": "/get",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "httpbin.org:80": 1
    }
  },
  "plugins": {
    "basic-auth": {},
    "consumer-restriction": {
      "whitelist": [
        "userA"
      ]
    }
  }
}'
  1. Send access requests separately using userA and userB.
curl -u userA:123456 http://127.0.0.1:9080/get -i
HTTP/1.1 200 OK
curl -u userB:123456 http://127.0.0.1:9080/get -i
HTTP/1.1 403 Forbidden
...
{"message":"The consumer_name is forbidden."}

The result indicates that userB has been restricted from accessing the API resource.

Set up Permission Control Policies in Consumer

  1. First, we will set up a route whose ID is called forbidden-userB, and enable basic-auth plugin.
curl http://127.0.0.1:9180/apisix/admin/routes -H 'X-API-KEY: {YOUR_API_KEY}' -X PUT -d '
{
  "id": "forbidden-userB",
  "uri": "/get",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "httpbin.org:80": 1
    }
  },
  "plugins": {
    "basic-auth": {}
  }
}'
  1. Create two Consumer objects and enable the basic-auth plugin. Note that we need to configure the consumer-restriction plugin to refine the permission control policies for userB.
curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: {YOUR_API_KEY}' -X PUT -i -d '
{
  "username": "userA",
  "plugins": {
    "basic-auth": {
      "username":"userA",
      "password": "123456"
    }
  }
}'
curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: {YOUR_API_KEY}' -X PUT -i -d '
{
  "username": "userB",
  "plugins": {
    "basic-auth": {
      "username":"userB",
      "password": "123456"
    },
    "consumer-restriction": {
      "type": "route_id",
      "blacklist": [
        "forbidden-userB"
      ],
      "rejected_code": 403
    }
  }
}'
  1. Send requests using userA and userB separately.
curl -u userA:123456 http://127.0.0.1:9080/get -i
HTTP/1.1 200 OK
curl -u userB:123456 http://127.0.0.1:9080/get -i
HTTP/1.1 403 Forbidden
...
{"message":"The route_id is forbidden."}

By examining the test results, we can verify that userB's requests have been effectively limited.

Conclusion

This article introduces the commonly-used permission control policies in APISIX and illustrates how to enable and configure them in APISIX using a classic scenario. Permission control is a prevalent strategy in API gateways. APISIX not only offers a comprehensive suite of ready-to-use plugins for authentication, but also provides extensive support in areas such as security, traffic management, and observability. By selecting and configuring your permission control policy rules, you can easily strengthen the security of your APIs.

Tags:
APISIX BasicsAuthentication & AuthorizationAPI Gateway PolicyPlugin