Advanced API Access Control with BIG-IP APM – Part II

Configuring BIG-IP APM to support API access control using OAuth scopes

Let’s take a look at how we can configure BIG-IP APM to provide an advanced API access control using OAuth scopes. I will not cover the basic OAuth configuration part in this article, and please refer to my previous article if you need a guide for basic OAuth configuration.

 

1) Create OAuth scopes in the OAuth Authorization Server

You first need to create all required OAuth scopes based on how you design your access control policy. In this demo, I followed what I used in the example of the Part I article, so I need a total of 8 OAuth scopes in the OAuth AS. 

BIG-IP UI >> Access >> Federation >> OAuth Authorization Server >> Scope >> Create

2) Assign scopes to the OAuth clients in the OAuth Authorization Server

I created two OAuth clients here, ‘Client_External_Postman’ and ‘Postman_Windows’. The first client(‘Client_External_Postman’) app represents an online payment app in the above example, and the ‘Postman_Windows’ app represents an analytic app. As for different access requirements, I assigned all scopes to the first app and assigned only three scopes to the second app.

3) Create an iRule to set the HTTP method as a session variable

Since we will use CRUD-based access control in our policy, we need to identify the HTTP method from the clients’ request and assign it to a custom session variable. Below is the simple iRule to collect the HTTP method and assign it to the ‘session.custom.httpmethod’ variable. We will use this custom variable in our per-request policy later. For now, we create the below iRule and store it with the name of ‘HTTP_Method’. 

when ACCESS_PER_REQUEST_AGENT_EVENT {
    ACCESS::session data set session.custom.httpmethod [HTTP::method] 
}

4) Modify the existing per-request policy in the OAuth RS

If you already completed the demo in my previous article(“Implementing basic OAuth with F5 BIG-IP APM”), you have an existing per-request policy in your OAuth RS like the below.

a. Click the (+) icon next to the ‘Start’ item in the main PRP and select the ‘iRule Event’ under the ‘General Purpose’ tab.

b. Write the iRule name you created above; in this case, the iRule name is ‘HTTP_Method’.

c. Click the (+) icon next to the ‘RS Scope Check’ item in the main PRP and select the ‘URL Branching’ under the ‘Classification’ tab.

d. Go to the ‘Branch Rules’ tab and delete an existing rule by clicking the ‘x’ button. Then click the ‘Add Branch Rule’ and name it to ‘/account’.

e. Click the ‘change’ button under the newly created rule and click the ‘Add Expression’. Then select the ‘URL Branching’ as a context and the ‘Suffix Match’ as a ‘Condition’ with the value of ‘/account’. Click the ‘Add Expression’.

f. Add one more branch rule with a name of ‘/transfer’ like the below. Then click the ‘Save’.

Then our current per-request policy should be similar to the below.

g. Click the (+) icon next to ‘/account’ branch rule of the ‘URL Branching’ item and add the ‘Empty’ item under the ‘General Purpose’ tab.

Change the name to ‘HTTP Method – account’

h. Add four branch rules under the ‘Branch Rules’ tab and name each rule like the below.

 

i. Click the ‘change’ menu on each item and go to the ‘Advanced’ tab. Then configure the below command.

expr {[mcget {session.custom.httpmethod}] equals "GET"}
expr {[mcget {session.custom.httpmethod}] equals "POST"}
expr {[mcget {session.custom.httpmethod}] equals "PATCH"}
expr {[mcget {session.custom.httpmethod}] equals "DELETE"}

We’re going to allow 4 HTTP methods here, ‘GET’, ‘POST’, ‘PATCH’, and ‘DELETE’. Any other HTTP methods that are not configured here will be rejected.

Add the same item next to the ‘/transfer’ branch rule of the ‘URL Branching’ item. Then, our configuration should be similar to the below.

j. Click the (+) icon next to the ‘GET’ branch rule of the ‘HTTP Method - account’ item and add the ‘Empty’ item under the ‘General Purpose’ tab.

Change the name to ‘account_read scope’

Go to the ‘Branch Rules’ tab and click the ‘Add Branch Rule’. Then change the name to ‘Successful’.

Click the ‘change’ menu and configure the below command under the ‘Advanced’ tab.

expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "account.read"}

k. Repeat the steps above for other HTTP methods of the ‘HTTP Method – account’ item with different scope variable checking commands like the below.

‘GET’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "account.read"}
‘POST’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "account.create"}
‘PATCH’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "account.update"}
‘DELETE’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "account.delete"}

l. Repeat the same steps above for the ‘GET’, ‘POST’, ‘PATCH’ and ‘DELETE’ branch rules of the ‘HTTP Method – transfer’ item.

‘GET’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "transfer.read"}
‘POST’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "transfer.create"}
‘PATCH’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "transfer.update"}
‘DELETE’ branch rule -> expr {[mcget {subsession.oauth.scope.last.introspect.scope}] contains "transfer.delete"}

m. Click the ‘Successful’ branch of each scope checking the item and change the ‘Reject’ value to the ‘Allow’. Then our per-request policy would be like the below.

 

5) Review the access control flow

We have configured advanced API access control using OAuth scopes in the BIG-IP APM. In this demo, one BIG-IP APM is running as an OAuth Authorization Server and the other BIG-IP APM is running as an OAuth Resource Server. The above ‘Per-Request Policy’ should be applied to the BIG-IP APM which runs as an OAuth Resource Server. The below flow chart shows how access control is working at OAuth Resource Server.

 

6) Apply the policies

We need to apply both ‘per-session access policy’ and ‘per-request access policy’ to the VS of the OAuth Resource Server. To extract the HTTP method from the API request, we will attach the iRule we created in the above step.

 

Verifying the result

We’re going to test 5 different scenarios to verify our access control policy in the BIG-IP APM as an OAuth Resource Server. We created two different OAuth clients in the above, ‘Client_External_Postman’ and ‘Postman_Windows’. Please note that we assigned all scopes to the first app and assigned only 3 scopes(‘account.read’, ‘transfer.read’, ‘transfer.update’) to the second app.

1) Test1: Checking both OAuth client apps can access the required API endpoints with different actions.

a. We need to get an OAuth access_token first before making an API request from the OAuth client app(Client_External_Postman). Since the first app is allowed to ask for any scopes for both ‘/account’ and ‘/transfer’ API endpoints, we can put any scopes in space-separated format. For now, we will configure 4 scopes here – ‘account.read’ / account.create’ / ‘transfer.read’ / ‘transfer.create’.

b. Once the user authentication is completed, you will see the below window provided by OAuth Authorization Server. With this information window, the user can understand what access privileges are assigned to the access token.   

c. Perform an API request to the ‘/account’ endpoint with the ‘GET’ method. This should work fine because the token includes the ‘account.read’ scope.

d. Perform an API request to the ‘/account’ endpoint with the ‘POST’ method. This should work fine because the token includes the ‘account.create’ scope.

e. Perform an API request to the ‘/account’ endpoint with the ‘PATCH’ method. This should be blocked by OAuth Resource Server(BIG-IP APM) because the token doesn’t include the ‘account.update’ scope. Please note that the app ‘Client_External_Postman’ is allowed to get the ‘account.update’ scope, but we didn’t add the ‘account.update’ scope when we obtained the OAuth access_token. Thus, the request is blocked by OAuth Resource Server.

 

2) Test2: Prevent unauthorized access from the ‘Postman_Windows’ app with disallowed actions.

a. In the 2nd Postman app console, obtain the OAuth access token from the OAuth Authorization Server with allowed scopes – ‘account.read’, ‘transfer.read’, ‘transfer.update’. Please note that you must configure the correct ‘Client ID’ and the ‘Client Secret’ values that are assigned to the 2nd app.

b. Perform an API request to the ‘/account’ endpoint with the ‘GET’ method. This should work fine because the token includes the ‘account.read’ scope.

c. Perform an API request to the ‘/account’ endpoint with the ‘POST’ method. This should be blocked by OAuth Resource Server(BIG-IP APM) because the token doesn’t include the ‘account.create’ scope. Please note that the 2nd app (Postman_Windows) is allowed for using 3 OAuth scopes only.

 

3) Test3: Try to access the API endpoints with unassigned OAuth scopes

The 2nd app (Postman_Windows) doesn’t allow to use of the writing and deleting-related OAuth scopes such as ‘account.create’ or ‘transfer.delete’. What happens if the app asks to obtain scopes that are not allowed?

a. In the 2nd app Postman console, add the ‘account.create’ scope and try to get an access token.

b. Even though we added ‘account.create’ scope in our token request, OAuth Authorization Server returns only allowed OAuth scopes to the client, in this case, ‘account.read’, ‘transfer.read’, ‘transfer.update’.

 

c. Perform an API request to the ‘/account’ endpoint with the ‘POST’ method. This should be blocked by OAuth Resource Server(BIG-IP APM) because the token doesn’t include the ‘account.create’ scope.

 

4) Test4: Try to access the undefined API endpoints

In our current ‘per-request policy’ of the BIG-IP APM, we only allow two URLs end with the ‘/account’ and the ‘/transfer’. If clients try to access an undefined URL other than two, BIG-IP APM blocks the request like the below, even if the request includes the valid access token.

 

5) Test5: Try to access the API endpoints with the undefined HTTP methods

In our current ‘per-request policy’ of the BIG-IP APM, we only allow 4 HTTP methods(GET, POST, PATCH, DELETE) to support CRUD(Create, Read, Update, Delete) actions. Any HTTP methods other than four methods will be blocked by BIG-IP APM even if the request includes the valid OAuth access token.

 

Updated Aug 23, 2022
Version 2.0
  • Thank you, great serie of articles James_Jinwon_Lee . Looking at the configuration of the VPE, which can get massively complex: how to perform and maintain the configuration in an automated (imperative/declarative) way?

    That would be worth a part IV article 🙂