API Security: How to implement API Access Control with F5

Introduction 

Organizations use API as a de facto standard to connect services and transfer data. Gartner predicts that by 2022, API attacks will become the most-frequent attack vector, causing data breaches for enterprise web applications.

According to Gartner (table below), providing effective security for API falls into two broad aspects: API Threat Protection and API Access Control.

API Threat Protection means detecting and blocking attacks on API, while API Access Control means controlling which application and users can access API.

F5 has a couple of product offerings that can address either aspect of API security as defined by Gartner.

Specifically, the Web Application and API Protection (WAAP) service offered via the F5 Distributed Cloud (F5 XC) addresses API Threat Protection and is consumed as SaaS. Please take a high-level overview here.

For API Access Control, the good old and ever evolving F5 BIG-IP Access Policy Manager (APM) rises again to the occasion. In this article, I will focus at length on how we can leverage BIG-IP APM to provide API access control.

Pre-words

Before I get started, I would like to acknowledge the excellent work and coverage on this topic already done by James Lee, who has authored a three part article series titled ‘Advanced API Access Control with BIG-IP APM’. James has also provided tremendous assistance for my work effort while I was researching this very topic. THANK YOU, James!

The purpose of this article is to hit the topic really hard one more time, hoping to further uncover the intricacies associated with the realm of API access control.

Mechanism for API Access Control

The OAuth 2.0 protocol is broadly used as a mechanism to provide API access control. It provides functions such as authentication, as well as authorization, which are pivotal to implementing control on API access. 

The OAuth 2.0 specification defines four roles, and it is the four roles working together to get the job done.

I won’t bore you with the specs itself, in layman’s terms, I have described them as below.

Resource Owner: This is the end user. e.g., you and I

Resource Server: This is the API server that also understands OAuth. In many scenarios, API servers only know how to serve API requests, one way to add OAuth capability is via offloading that function to something else. Hint: BIG-IP APM 

Client: This is the application that makes API calls to your API server. The confusion part is Client here refers to OAuth Client. The application itself is an API client and for it to also act as an OAuth client, it needs to add OAuth Client function as well 

Authorization Server: This is who OAuth Client talks to to get an access token. The Authorization Server usually authenticates the OAuth Client prior to giving it the token.

A high-level traffic flow would be like this,  

  1. Client (Your application with OAuth component acting as OAuth Client) reaches out to the Authorization Server for an access token
  2. Authorization Server checks the incoming request from Client, usually authenticates the Client as well, if successful, gives Client an access token.
  3. Client sends the API request, with the access token included, to the Resource Server
  4. Resource Server verifies the access token and answers the API request

Note: There are several variations to the above flow, depending upon the type of the application and associated capabilities (e.g., browser, mobile or machine based). The above flow is most suited to non-interactive machine-to-machine API traffic.

API Access Control with BIG-IP APM

If you are looking at adding API Access Control to your API servers that do not understand OAuth, leveraging the BIG-IP APM is surely a great way to bring in that capability.

In addition, the Web Application and API Protection as a SaaS offering brings in API Threat Protection capability, which means you effectively kill two birds with one stone and can completely nail API security with a consolidated single vendor solution.

In the succeeding sections, I will walk through the BIG-IP APM configuration, allowing it to function as an Authorization Server, as well as offloading Resource Server capability for your API servers.

Authorization Server

The role of Authorization Server is to provide an access token to Client if things check out. The kind of things that must check out is dependent upon the OAuth grant type being implemented. The popular grant types include the ones listed below but are not limited to these four: 

  1. Authorization Code grant
  2. Implicit grant
  3. Resource Owner Password Credential (ROPC) grant
  4. Client Credentials grant 

The APM supports all four grant types, with the Client Credentials grant requiring a bit of iRule magic.

Step-wise, we first create a LB VIP, and then attach it with an access profile that turns it into an Authorization Server.

Prior to creating the access profile, we must create associated prerequisites.

Under Access => Federation => OAuth Authorization Server, create a ‘Client Application’ and a ‘Resource Server’, followed by creating an ‘OAuth Profile’ that binds the ‘Client Application’ and ‘Resource Server’ together. The logic is that the authorization server needs to know its registered client application, as well as the participating resource server. This allows for Resource Server reaching out to Authorization Server for token validation as part of the flow.

For this specific article, we select ‘Resource Owner Password Credentials’ (ROPC) grant type. There are plenty of resources on the Internet that talk about these different grants in great details but for the purpose of non-interactive machine to machine API traffic, the most suited grant type is Client Credentials. 

The BIG-IP APM does not natively handle Client Credentials grant type. However, it is very similar to ROPC grant type, which is natively handled. The idea is that we let the client application use ‘Client Credentials’ grant when talking to the Authorization Server, and once traffic arrives at the APM, we use an iRule to convert it to ROPC so the APM can process that traffic. 

ROPC requires that the Client (API client application) to send in username, password, client_id and client_secret. Client Credentials only requires client_id and client_secret to be sent.

With Client Credentials grant, since no username or password is needed, the iRule simply adds them as dummies so the request looks like a ROPC grant request.

Below are a couple of screenshots for your reference, as well as the iRule that you can readily use.

 Figure 1 - Create a Client Application

Figure 2 - Create a Resource Server

This iRule below is based on an excellent solution shared by DevCentral user youssef1. This is all his work, and I am simply referencing it here for this article. 

when HTTP_REQUEST {

    set grant_type null

    if { ( [string tolower [HTTP::uri]] equals "/f5-oauth2/v1/token" ) and ( [HTTP::method] equals "POST" ) } {
        set grant_type "client_credentials"
        HTTP::collect [HTTP::header Content-Length]
    }

}

when HTTP_REQUEST_DATA {

    if {$grant_type contains "client_credentials" } {
        set payload [HTTP::payload]

        if { [HTTP::payload] contains "grant_type=client_credentials" } {
            # log local0. "Old Payload: [HTTP::payload]"
            HTTP::payload replace 0 [HTTP::header Content-Length] [string map {"grant_type=client_credentials" "grant_type=password&username=xxx&password=xxx"} $payload]
            # log local0. "New Payload: [HTTP::payload]"
            HTTP::release
        }
    }
}

 The above concludes the Authorization Server configuration.

Resource Server

If your API servers do not understand OAuth, you can offload OAuth function to the BIG-IP APM by putting them behind it. Specifically, create a LB VIP for your API servers and attach an access profile so that together they act as a Resource Server.

The Resource Server is responsible for checking the access token presented by the Client (application) as part of its API request, if the token checks out, API request is answered, otherwise denied.

Depending on the type of the access token, if it is in the form of an opaque token, meaning it carries no information on its own, the Resource Server will need to present this token to the Authorization Server and in return it gets the information.

If the access token is in the form of a JSON Web Token (JWT), the Resource Server verifies the signature of the token and then reads the embedded information off it. The Resource Server won’t need to reach out to the Authorization Server in this case.

The APM supports both opaque token and JWT token, and by default the opaque token is used. The opaque token provides certain benefits such as it is revokable, hides the actual information and is probably smaller in size when compared to a JWT token. The downside is the Resource Server will need to talk to the Authorization Server for token validation and introspection. The JWT token does not need the extra roundtrip of communication, and therefore cuts down on latency, due to information is already embedded inside the token. However, it may not be suitable if you are transmitting sensitive information or require revoking a token after one is issued.

Just as a side note, the BIG-IP APM can receive an opaque token, validates it against an external party, and then issue a JWT token downstream, as part of its SSO capability. This is not related to our use case here, but I will mention it for awareness.

To offload Resource Server function to the BIG-IP APM, go to Access => Federation => OAuth Client / Resource Server, create a ‘Provider’ and an ‘OAuth Server’ configuration.

The idea is that with a provider, it has all the information on Authorization Server, so Resource Server knows how to communicate with it. E.g., what URL to hit when validating a token

Figure 4 - Create a Provider

https://as.abbagmbh.de points to the LB VIP we created earlier on for the Authorization Server.

When creating the ‘OAuth Server’ configuration, fill in the ‘Resource Server ID’ and ‘Resource Server Secret’ values by copying them from the previous step when we configured under the ‘OAuth Authorization Server’ menu.

 Figure 5 - Create an OAuth Server (Resource Server)

The above concludes the Resource Server configuration.

Access Profiles

We need to create two access profiles, one for Authorization Server and the other for Resource Server.

For Authorization Server, select ‘LTM-APM’ type, associate an OAuth Profile created earlier and leave the rest as default.

The Access policy shown below is simple, the result is that an access token will be issued if client_id and client_secret in the request check out.

 

 Figure 6 – Access policy for Authorization Server

For Resource Server, select ‘LTM-APM’ type and leave the rest as default.

For the access policy, use ‘OAuth Scope’ type (I renamed it as OAuth Token Check), set token validation mode as ‘external’, select the Resource Server we created earlier on.

Figure 7 - Resource Server access policy 

 Figure 8 - Token validation

 The above concludes a very basic setup of Resource Server.

Scope

In OAuth 2.0, scope is used to limit the level of access granted to an access token. For instance, you can use a ‘READ’ scope that allows API calls via HTTP GET, and a ‘WRITE’ scope that allows HTTP POST API calls.

The full list of supported scopes should be communicated to the Client as defined on the Authorization Server.

When Client is asking for an access token, it will include scope as part of the request parameter. If scope is not included, the Authorization Server either process the request using a pre-defined default value or fail the request indicating an invalid scope.

Once access token is issued with the requested scope, it is sent to the Resource Server and it is incumbent upon the Resource Server to do something about it.

Take the prior ‘READ’ and ‘WRITE’ scopes as an example, the Resource Server will need to block POST API calls if the scope is ‘READ’.

Scope in essense is a literal string of key value pair, the string itself is defined per implementation. Once it is defined on the Authorization Server, it needs to be communicated to the Client, so the Client will know what scopes are available to use; it also needs to be communicated to the Resource Server as well, as it will implement enforcement per design.

In this article, I am only introducing scope at a conceptual level to keep it short.

The BIG-IP APM does however provide a full set of functions to support scope management.

Testing

So far, we have created two LB VIP’s, one as an Authorization Server, and the other as a Resource Server.

 Figure 9 - LB VIP

We created two access profiles, with each attached to the associated LB VIP. 

 

Figure 10 - ROPC profile attach

  

Figure 11 - Resource Server profile attach

On Postman, we use the following to get an access token from the Authorization Server’s token URL (https://ropcas.abbagnbh.de/f5-oauth2/v1/token) See Figure 4.

 Figure 12 - Postman get Access Token 

Below shows the access token is obtained.

Figure 13 - Postman token obtained 

 Let’s use this token with our API request.

 Figure 14 - Postman send API request with access token

 The API server is programmed to print out the API request itself.

 Figure 15 - API server response 

On the APM, if you go to Access => Overview => OAuth Reports => Tokens, you will see the token as ‘ACTIVE’.

 Figure 16 - APM OAuth Token report

Conclusion

In this article, we started at high level on what comprises API security defined by Gartner, which comes down to API Threat Protection and API Access Control.

F5 has WAAP as a SaaS offering to address API Threat Protection and the BIG-IP APM provides a highly capable solution for API Access Control.

I have explained the concept around API Access Control using OAuth 2.0, as well as a specific use case on non-interactive machine to machine API access control.

I hope you will find this article of value and please reach out with comments or your sales team if you have a need around implementing API Security.

Published Jan 11, 2023
Version 1.0

Was this article helpful?

No CommentsBe the first to comment