RBAC With API Gateway and Open Coverage Agent (OPA)

With numerous entry management fashions and implementation strategies out there, developing an authorization system for backend service APIs can nonetheless be difficult. Nevertheless, the final word aim is to make sure that the proper particular person has acceptable entry to the related useful resource. On this article, we’ll focus on the way to allow the Position-based entry management (RBAC) authorization mannequin on your API with open-source API Gateway Apache APISIX and Open Policy Agent (OPA).

What Is RBAC?

Role-based access control (RBAC)and attribute-based access control (ABAC) are two generally used entry management fashions used to handle permissions and management entry to assets in laptop methods. RBAC assigns permissions to customers based mostly on their position inside a corporation. In RBAC, roles are outlined based mostly on the capabilities or obligations of customers, and permissions are assigned to these roles. Customers are then assigned to a number of roles, they usually inherit the permissions related to these roles. Within the API context, for instance, a developer position might need permission to create and replace API assets, whereas an end-user position would possibly solely have permission to learn or execute API assets.

Mainly, RBAC assigns permissions based mostly on person roles, whereas ABAC assigns permissions based mostly on attributes related to customers and assets.

In RBAC, a coverage is outlined by the mixture of a person’s assigned position, the actions they’re licensed to carry out, and the assets on which they’ll carry out these actions.

What Is OPA?

OPA (Open Policy Agent) is a coverage engine and a set of instruments that present a unified strategy to coverage enforcement throughout a complete distributed system. It lets you outline, handle, and implement insurance policies centrally from a single level. By defining insurance policies as code, OPA permits simple evaluation, enhancing, and roll-back of insurance policies, facilitating environment friendly coverage administration.


OPA gives a declarative language known as Rego, which lets you create and implement insurance policies all through your stack. While you request a coverage choice from OPA, it makes use of the foundations and knowledge that you’ve supplied in a .rego file to guage the question and produce a response. The question result’s then despatched again to you because the coverage choice. OPA shops all of the insurance policies and the info it wants in its in-memory cache. Because of this, OPA returns outcomes rapidly. Right here is an instance of a easy OPA Rego file:

bundle instance

default enable = false
enable 
    enter.methodology == "GET"
    enter.path =="/api/useful resource"
    enter.person.position == "admin"

On this instance, we’ve a bundle known as “instance” that defines a rule known as “enable”. The “enable” rule specifies that the request is allowed if the enter methodology is “GET”, the requested path is /api/useful resource, and the person’s position is “admin”. If these situations are met, then the “enable” rule will consider as “true”, permitting the request to proceed.

Why Use OPA and API Gateway for RBAC?

API Gateway gives a centralized location to configure and handle API, and API shoppers. It may be used as a centralized authentication gateway by avoiding having every particular person service implement authentication logic contained in the service itself. Alternatively, OPA provides an authorization layer and decouples the coverage from the code by creating a definite profit for authorization. With this mixture, you may add permissions for an API useful resource to a task. Customers is perhaps related to a number of person roles. Every person position defines a set of permissions (GET, PUT, DELETE) on RBAC assets (outlined by URI paths). Within the subsequent part, let’s learn to obtain RBAC utilizing these two.

Learn how to Implement RBAC With OPA and Apache APISIX

In Apache APISIX, you may configure routes and plugins to outline the conduct of your API. You should use the APISIX opa plugin to implement RBAC insurance policies by forwarding requests to OPA for decision-making. Then OPA makes an authorization choice based mostly on customers’ roles and permissions in real-time.

Assume that we’ve Conference API the place you may retrieve/edit occasion periods, matters, and speaker data. A speaker can solely learn their very own periods and matters whereas the admin can add/edit extra periods and matters. Or attendees can depart their suggestions concerning the speaker’s session through a POST request to /speaker/speakerId/session/suggestions and the speaker can solely see by requesting the GET methodology of the identical URI. The under diagram illustrates the entire situation:


  1. API shopper requests a route on the API Gateway with its credential equivalent to a JWT token within the authorization header.
  2. API Gateway sends shopper knowledge with a JWT header to the OPA engine.
  3. OPA evaluates if the patron has a proper to entry the useful resource through the use of insurance policies (roles and permissions) we specify within the .rego file.
  4. If the OPA choice is allowed, then the request will likely be forwarded to the upstream Convention service.

Subsequent, we set up, configure APISIX, and outline insurance policies in OPA.

Stipulations

  • Docker is used to putting in the containerized etcd and APISIX.
  • curl is used to ship requests to APISIX Admin API. You may as well use instruments equivalent to Postman to work together with the API.

Step 1: Set up Apache APISIX

APISIX might be simply put in and began with the next quickstart script:

curl -sL https://run.api7.ai/apisix/quickstart | sh

Step 2: Configure the Backend Service (Upstream)

To route requests to the backend service for the Convention API, you’ll have to configure it by including an upstream server in Apache APISIX through the Admin API.

curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -X PUT -d '

   "title":"Conferences API upstream",
   "desc":"Register Conferences API because the upstream",
   "sort":"roundrobin",
   "scheme":"https",
   "nodes":
      "conferenceapi.azurewebsites.web:443":1
   
'

Step 3: Create an API Shopper

Subsequent, we create a shopper (a brand new speaker) with the username jack in Apache APISIX. It units up the jwt-auth plugin for the patron with the desired key and secret. This can enable the patron to authenticate utilizing a JSON Web Token (JWT).

curl http://127.0.0.1:9180/apisix/admin/shoppers -X PUT -d '

    "username": "jack",
    "plugins": 
        "jwt-auth": 
            "key": "user-key",
            "secret": "my-secret-key"
        
    
'

Step 4: Create a Public Endpoint to Generate a JWT Token

You additionally have to arrange a brand new Route that generates and indicators the token utilizing the public-api plugin. On this situation, API Gateway acts as an id supplier server to create and confirm the token with our shopper jack’s key. The id supplier might be additionally another third-party companies equivalent to Google, Okta, Keycloak, and Ory Hydra.

curl http://127.0.0.1:9180/apisix/admin/routes/jas -X PUT -d '

    "uri": "/apisix/plugin/jwt/signal",
    "plugins": 
        "public-api": 
    
'

Step 5: Declare a New JWT Token for the API Shopper

Now we are able to get a brand new token for our speaker Jack from the API Gateway utilizing the general public endpoint we created. The next curl command generates a brand new token with Jack’s credentials and assigns position, and permission within the payload.

curl -G --data-urlencode 'payload="position":"speaker","permission":"learn"' http://127.0.0.1:9080/apisix/plugin/jwt/signal?key=user-key -i

After you run the above command, you’ll obtain a token as a response. Save this token someplace — later we’re going to use this token to entry our new API Gateway endpoint.

Step 6: Create a New Plugin Config

This step includes configuring APISIX’s 3 plugins: proxy-rewrite, jwt-auth, and opa plugins.

curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PUT -d '

   "plugins":
      "jwt-auth":
      ,
      "proxy-rewrite":
         "host":"conferenceapi.azurewebsites.web"
      
   
'
  • The proxy-rewrite plugin is configured to proxy requests to the conferenceapi.azurewebsites.web host.
  • OPA authentication plugin is configured to make use of the OPA coverage engine working at http://localhost:8181/v1/data/rbacExample. Additionally, APISIX sends all consumer-related data to OPA. We’ll add this coverage .rego file within the Opa configuration part.

Step 7: Create a Route for Convention Periods

The ultimate step is to create a brand new route for Conferences API speaker periods:

curl "http://127.0.0.1:9180/apisix/admin/routes/1" -X PUT -d '

    "title":"Conferences API speaker periods route",
    "desc":"Create a brand new route in APISIX for the Conferences API speaker periods",
    "strategies": ["GET", "POST"],
    "uris": ["/speaker/*/topics","/speaker/*/sessions"],
    "upstream_id":"1",
    "plugin_config_id":1
'

The payload incorporates details about the route, equivalent to its title, description, strategies, URIs, upstream ID, and plugin configuration ID. On this case, the route is configured to deal with GET and POST requests for 2 totally different URIs, /speaker/matters and /speaker/periods. The “upstream_id” area specifies the ID of the upstream service that can deal with incoming requests for this route, whereas the “plugin_config_id” area specifies the ID of the plugin configuration for use for this route.

Step 8: Check the Setup With out OPA

Thus far, we’ve arrange all the mandatory configurations for APISIX to direct incoming requests to Convention API endpoints, solely permitting licensed API shoppers. Now, every time an API shopper desires to entry an endpoint, they have to present a JWT token to retrieve knowledge from the Convention backend service. You’ll be able to confirm this by hitting the endpoint and the area tackle we’re requesting now’s our customized API Gateway however not an precise Convention service:

curl -i http://127.0.0.1:9080/speaker/1/matters -H 'Authorization: API_CONSUMER_TOKEN'

Step 9: Run OPA Service

The opposite two steps are we run the OPA service utilizing Docker and add our coverage definition utilizing its API which can be utilized to guage authorization insurance policies for incoming requests.

docker run -d --network=apisix-quickstart-net --name opa -p 8181:8181 openpolicyagent/opa:newest run -s

This Docker command runs a container of the OPA picture with the newest model. It creates a brand new container on the present APISIX community apisix-quickstart-netwith the title opaand exposes port 8181. So, APISIX can ship coverage verify requests to OPA instantly utilizing the tackle [http://opa:8181](http://opa:8181) Observe that OPA and APISIX ought to run in the identical docker community.

Step 10: Outline and Register the Coverage

The second step on the OPA facet is that you must outline the insurance policies that will likely be used to manage entry to API assets. These insurance policies ought to outline the attributes required for entry (which customers have which roles) and the permission (which roles have which permissions) which are allowed or denied based mostly on these attributes. For instance, within the under configuration, we’re saying to OPA, verify the user_roles desk to seek out the position for jack. This data is shipped by APISIX inside enter.shopper.username. Additionally, we’re verifying the patron’s permission by studying the JWT payload and extracting token.payload.permission from there. The feedback describe the steps clearly.

curl -X PUT '127.0.0.1:8181/v1/insurance policies/rbacExample' 
    -H 'Content material-Kind: textual content/plain' 
    -d 'bundle rbacExample

# Assigning person rolesuser_roles := 
    "jack": ["speaker"],
    "bobur":["admin"]


# Position permission assignments
role_permissions := 
    "speaker": ["permission": "read"],
    "admin":   ["permission": "read", "permission": "write"]


# Helper JWT Features
bearer_token := t 
 t := enter.request.headers.authorization


# Decode the authorization token to get a task and permission
token = "payload": payload 
 [_, payload, _] := io.jwt.decode(bearer_token)


# Logic that implements RBAC
default enable = falseenable 
    # Lookup the checklist of roles for the person
    roles := user_roles[input.consumer.username]    # For every position in that checklist
    r := roles[_]    # Lookup the permissions checklist for position r
    permissions := role_permissions[r]    # For every permission
    p := permissions[_]    # Verify if the permission granted to r matches the customers request
    p == "permission": token.payload.permission
'

Step 11: Replace the Present Plugin Config With the OPA Plugin

As soon as we outlined insurance policies on the OPA service, we have to replace the present plugin config for the route to make use of the OPA plugin. We specify within the coverage attribute of the OPA plugin.

curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PATCH -d '

   "plugins":
      "opa":
         "host":"http://opa:8181",
         "coverage":"rbacExample",
         "with_consumer":true
      
   
'

Step 12: Check the Setup With OPA

Now we are able to check all setups we did with OPA insurance policies. When you attempt to run the identical curl command to entry the API Gateway endpoint, it first checks the JWT token because the authentication course of and sends shopper and JWT token knowledge to OPA to confirm the position and permission because the authorization course of. Any request and not using a JWT token in place or allowed roles will likely be denied.

curl -i http://127.0.0.1:9080/speaker/1/matters -H 'Authorization: API_CONSUMER_TOKEN'

Conclusion

On this article, we realized the way to implement RBAC with OPA and Apache APISIX. We outlined a easy customized coverage logic to permit/disallow API useful resource entry based mostly on our API shopper’s position and permissions. Additionally, this tutorial demonstrated how we are able to extract API consumer-related data within the coverage file from the JWT token payload or shopper object despatched by APISIX.