Manual Chapter : API Protection Concepts

Applies To:

Show Versions Show Versions

BIG-IP APM

  • 14.1.2, 14.1.0
Manual Chapter

API Protection Concepts

Introducing API protection

API calls originating from enterprise, partner, and consumer applications that access cloud and on-prem resources require strong authentication and identity mediation in the current federated identity environment. Access Policy Manager lets you configure an API protection proxy for securing API calls.

Here's how API protection works:

  • Access Policy Manager, set up as an API protection proxy, receives API calls from various applications.
  • API request introspection and classification is done based on API request URI, method, parameters, cookies, headers, and so on.
  • Access Policy Manager provides authentication, authorization, and federation services using OAuth, JWT, OpenID Connect, and SAML.
  • Access Policy Manager enables identity mediation by creating tokens for accessing API servers.
  • Integrated AAA and XACML PDP services retrieve user, device, and client information.
  • Access Policy Manager allows legitimate API requests to reach the application, and sends a response if the request is denied.

Together these features result in strong API authentication support and protection designed to make it simpler and more flexible to handle API calls.

About API protection profiles

An API protection profile is the primary tool that Access Policy Manager administrators use to safeguard API servers. Protection profiles define groups of related RESTful APIs used by applications. The protection profile contains a list of paths that may appear in a request. The system classifies requests and sends them to specific API servers.

The simplest way to create an API protection profile and establish API protection is using an OpenAPI Spec 2.0 file to import the details of the APIs. If you use an OpenAPI Spec 2.0 file, Access Policy Manager automatically creates the following (depending on what's included in the spec file):

  • API protection profile
  • Paths
  • API servers
  • Responses
  • Per-request policy with a Request Classification agent and a subroutine containing an OAuth scope check agent

If you have no spec file, you can manually develop the API protection profile by specifying the necessary information. The system automatically creates a per-request policy that can be edited further.

To enable API protection, the API protection profile must be associated with a virtual server. If using API protection, the virtual server can have only one API protection profile associated with it. You cannot select other access profiles or per-request policies in that virtual server.

About OpenAPI spec files

The OpenAPI Specification 2.0 defines the spec file format needed to describe RESTful APIs. The spec file can be written either in JSON or YAML. Using a spec file simplifies your work of implementing API protection. Refer to the OpenAPI Specification 2.0 (formerly called Swagger version 2.0) for details.

Following is an example spec file written in YAML:

  swagger: "2.0"  
  info:
    version: 1.0.0
    title: Sample API
    description: API description in Markdown.
  schemes:
    -https
  host: api.example.com
  basePath: /v1
  paths:
    /users:
      get:
        summary: Returns a list of users.
        description: Optional extended description in Markdown.
        produces:
          - application/json
        responses:
          200:
            description: OK

About API protection agents

Access Policy Manager (APM) provides the following agents for API protection.

  • Request Classification (RCA)
  • API Server Selection
  • API Authentication
  • Response Selection

The per-request policy that is created with the API protection profile may already include these agents. You can create, view, and edit them in the visual policy editor. Request Classification corresponds to the paths in the policy. API Server Selection picks the server to which to send the request, and uses only servers specified in the API protection profile.

API Authentication locates the authentication type (HTTP Basic or OAth 2.0) in the incoming request header and sets the appropriate subsession variables. Response Selection lets you assign a customized response in case a request is denied access by the Reject Ending agent.

About Request Classification

The Request Classification Agent classifies incoming API requests based on request path and method. When you create an API protection prfile, you specify the paths to which you expect to receive requests.

Each path has the following attributes: URI path, method, path ID, and Active. Path ID uniquely identifies the path. The agent matches the incoming request with one of the path objects, and sets a perflow variable perflow.request_classification.path_id to the path ID of the matching path object. You can use the path ID is in branch expressions.

If these paths are in the API protection profile:

This is shown in the visual policy editor:

About API Server Selection

The API Server Selection agent selects a specific API server to which to send an API request. The server selected must be one of the servers associated with the corresponding API protection profile.

API Server Selection sets a perflow variable with the corresponding API server. API Protection then uses the perflow variable to set the destination appropriately, and also modifies the outgoing request based on the server configuration. Request Classification can also set the perflow variable when one of the paths is selected. If the perflow variable is not set, API Protection uses the default server associated with the API protection profile.

If this is the server in the API protection profile:

This is shown in the visual policy editor:

You can click API Server Selection in the policy and edit its properties, or edit servers on the Paths tab of the API protection profile.

About API Authentication

The API Authentication agent looks for the authentication type (HTTP Basic or OAuth 2.0) in the incoming API request header.

If the authentication header contains the Bearer auth scheme using an OAuth JWT token, the system creates the subsession variable subsession.api_authentication.scheme with the value oauth.

If the header contains Basic, the system creates the subsession variable subsession.api_authentication.scheme with the value http. For basic authentication, it also creates appropriate subsession variables (such as subsession.logon.last.username and subsession.logon.last.password) that are needed by the Authentication agents (such as ldap, ad, and so on).

You can use the subsession variable subsession.api_authentication.scheme in branch expressions for policy decisions based on the authentication scheme.

Here is a subroutine in an API protection per-request policy that handles authentication:

You can click API Authentication in the visual policy editor and edit its properties.

About Response Selection

The Response Selection agent allows you to send different responses to the user depending on what happened. The agent creates a perflow variable, perflow.response_selection.response, which is read by the Reject Ending Agent.

You can create custom API responses and assign a default on the Responses tab of the API protection profile.

This API protection per-request policy uses Response Selection in two places to provide different responses for different situations. One is for authentication failure and the other is for an invalid status.

You can click Response Selection in the visual policy editor and edit its properties, or edit responses on the Responses tab of the API protection profile.

About wildcard matching in API protection paths

When specifying URI paths in the API protection profile, you can use the * wildcard to represent the segment of an API path it's configured in. For example, if the API path format is defined as /f5/util/openshift/{something}, the following path classifications would match:

 /*/*/*/*
 /f5/*/openshift/{something}
 /*/*/*/{something}
 /f5/util/*/*
 /f5/util/openshift/*
 /*5/util/openshift/{something}
 /f*/util/openshift/{something}
 and so on... 

Furthermore, the BIG-IP system parses API paths into per-flow request variables that you can use in the API protection per-request policy to expand matching rules. For example, if the API path format was defined as /f5/util/openshift/{something}?department={id}, and the processed API request was GET /f5/util/openshift/professor?department=001, you could use the following expression in the API protection per-request policy to match that request:

 expr { 
 [ mcget request.path.1} ] == "f5" && 
 [ mcget {request.path.4} ] == "professor" && 
 [ mcget {request.method} ] == "GET" && 
 [ mcget {request.query.department} ] == "001" }

Request variables

A request variable is a type of perflow variable that allows a per-request policy to inspect the properties of requests such as URI, method, parameters, cookies, header, and so on. You can use request variables in Access control checks and make policy decisions based on properties of the request. For example, request variables are commonly used in OAuth scope checks.

The following request type variable lexical tree shows how you can use request variables.

Request variable API call example

Here is an example API call that could be used to access an application.

 GET api/api-1/project/project_1?part=snippet&order=asc&type=personel
   &group=administrator&group=developer&group=manager HTTP/1.1
 Host: api.corp.com
 Accept: application/json
 Cookie: token=Rg3vHJZnehYLjVg7qi3bZjzg; tscounter=1295214458; reg_fb_gate=true; gv=123.4;
   gv=234.2; gv=-2.43; gv=-78.2;
 Authorization: SWSS wNFYCj2wMrnuLIWmXJ4FuKQghDvVqZFUcDBWUg6BMrEAsuE7us
 SearchCriteria: ByGroup
 SearchCriteria: ByProject
 api_key: bNMP7di191ZehuKbggJtx3TXClGHNp3wG2KCNyF7

Based on the API code, using the request variables listed below in the per-request policy results in the values shown.

Request Variable Value
request.method GET
request.path /api/api-1/project/project_1
request.path.1 api
request.path.4 project_1
request.query part=snippet&order=asc&type=personnel&group =administrator&group=developer&group=manager
request.query.order asc
request.query.group administrator
request.query.group.values list of { administrator developer manager }
request.query.color <empty value> (query parameter "color" is not available in the request)
request.query.color.values <empty value> (query parameter "color" is not available in the request)
request.queries.count 6
request.queries.at.1 part
request.queries.at.1.value snippet
request.queries.at.3 type
request.queries.at.3.value personnel
request.header.Host api.corp.com
request.header.host api.corp.com
request.header.Cookie token=Rg3vHJZnehYLjVg7qi3bZjzg; tscounter=1295214458; reg_fb_gate=true;
request.cookie same as request.header.Cookie
request.cookie.token Rg3vHJZnehYLjVg7qi3bZjzg
request.cookie.reg_fb_gate true
request.cookie.gv 123.4
request.cookie.gv.values { 123.4 234.2 -2.43 -78.2 }
request.cookies.at.1 token
request.cookies.at.1.value Rg3vHJZnehYLjVg7qi3bZjzg
request.cookies.count 7
request.header.Authorization SWSS wNFYCj2wMrnuLIWmXJ4FuKQghDvVqZFUcDBWUg6B
request.header.authorization same as request.header.Authorization
request.header.authorization .SWSS wNFYCj2wMrnuLIWmXJ4FuKQghDvVqZFUcDBWUg6B
request.header.authorization .basic <empty value> for this example
request.header.authorization .basic.username ><empty value> for this example; however, if Basic scheme data is available, it provides decoded username
request.header.authorization .basic.password <empty value> for this example; however, if Basic scheme data is available, it provides decoded password
request.header.SearchCriteria ByGroup
request.header.SearchCriteria .values list of { ByGroup ByProject }
request.header.fakeheader <empty value> (HTTP header "fakeheader" is unavailable in the request)
request.header.fakeheader .values <empty value> (HTTP header "fakeheader" is unavailable in the request)
request.headers.count 7
request.headers.at.1 Host
request.headers.at.1.value api.corp.com
request.headers.at.7 api_key
request.headers.at.7.value bNMP7di191ZehuKbggJtx3TXClGHNp3wG2KCNyF7

Request variable API branch examples

Here is an API that includes a branch expression that checks the JWT token to be sure that the user is authorized to perform the operation.

 API format:
 GET /user/{last_name}/{first_name}?search={info}

 Example:
 GET /user/doe/john?search=title
 Authorization: Bearer 
 eyJhbGciOiJIUzI1NiIsImtpZCI6IjEyMyJ9.eyJhdWQiOiJodHRwczovL2FwaS5jb21
 wYW55LmNvbSIsImlzcyI6Imh0dHBzOi8vaWRwLmNvbXBhbnkuY29tIiwiaWF0IjoxNDkz
 NDIzMTUyLCJleHAiOjE0OTM0NjY2NTIsImxhc3RfbmFtZSI6IlRlc3QiLCJmaXJzdF9uY
 W1lIjoiTmF2eWEifQ.gXuJVZdeE743AepzsBUmBb2RyZP2XuSWW9xYqGWC50s

 Example branch expression to make sure the operation is authorized 
 within the user context available from JWT token.
 expr {
 [ mcget {request.path.1} ] == "user" && 
 [ mcget {request.path.2} ] == [ mcget 
    {last.subsession.oauth.client.last.jwt.last_name} ] &&
 [ mcget {request.path.3} ] == [ mcget 
    {last.subsession.oauth.client.last.jwt.first_name} ] &&
 [ mcget {request.method} ] == "GET" &&
 [ mcget {request.query.search} ] == "title" }

Here's another example branch expression:

 API format:
 DELETE /user/{last_name}/{first_name}
 Example:
 DELETE /user/doe/john
 Authorization: Bearer 
 eyJhbGciOiJIUzI1NiIsImtpZCI6IjEyMyJ9.eyJhdWQiOiJodHRwczovL2FwaS5jb21
 wYW55LmNvbSIsImlzcyI6Imh0dHBzOi8vaWRwLmNvbXBhbnkuY29tIiwiaWF0IjoxND
 kzNDIzMTUyLCJleHAiOjE0OTM0NjY2NTIsImxhc3RfbmFtZSI6IlRlc3QiLCJmaXJzd
 F9uYW1lIjoiTmF2eWEifQ.gXuJVZdeE743AepzsBUmBb2RyZP2XuSWW9xYqGWC50s

 Example branch expression to make sure the operation is authorized  
 within the user context available from JWT token.
 expr { 
 [ mcget {request.path.1}] == "user" && 
 [ mcget request.method ] == "DELETE" &&
 [ mcget last.subsession.oauth.client.last.jwt.memberGroup ] 
    == "administrators" }
	

Variable assignment expression example

Here is an API call with a variable assignment expression that you can use for Gating Criteria.

 API format:
 GET /user/{last_name}/{first_name}?search={info}

 Example:
 GET /user/doe/john?search=title 
 Authorization: Bearer 
 eyJhbGciOiJIUzI1NiIsImtpZCI6IjEyMyJ9.eyJhdWQiOiJodHRwczovL2FwaS5jb21
 wYW55LmNvbSIsImlzcyI6Imh0dHBzOi8vaWRwLmNvbXBhbnkuY29tIiwiaWF0IjoxND
 kzNDIzMTUyLCJleHAiOjE0OTM0NjY2NTIsImxhc3RfbmFtZSI6IlRlc3QiLCJmaXJzd
 F9uYW1lIjoiTmF2eWEifQ.gXuJVZdeE743AepzsBUmBb2RyZP2XuSWW9xYqGWC50s

 Example Variable assignment expression that can be used 
    for Gating Criteria.
 1. Use OAuth Bearer token as a unique key.
    expr { [ mcget request.header.Authorization.Bearer ] }

 2. Use OAuth Bearer token AND request path as unique keys.
    expr { [ append [ mcget request.header.Authorization.Bearer ] 
      [ mcget request.path ] ] }

Subsession variables for API protection

A subsession variable contains a numeric or string value that an action in a subroutine returns in a per-request policy. You use them to customize access rules or specify different outcomes based on their values. You can use subsession variables within subroutines or outside subroutines in a per-request policy. For example, subsession variables can access the results of recently completed subroutines.

The following subsession variable applies only to API protection: subsession.api_authentication.scheme. The API authentication agent sets the value of this variable to either basic or bearer based on the authentication header in the request.

You can also use common session variables as subsession variables. For example, subsession.logon.last.username or subsession.logon.last.password.

Perflow variables for API protection

Perflow variables exist only while a per-request policy runs. Perflow variables for a per-request policy subroutine exist while the subsession exists. Multiple subsessions can run simultaneously.

The following perflow variables can be used in an API protection per-request policy:

Perflow Variable Description
perflow.api.api_server Specifies the name of the API server associated with the request. The variable is set by the Request Classification agent when the matching path is associated with a server, or by the API Server Selection agent.
perflow.request_classification .path_id Specifies the path ID of the path. The Request Classification agent matches the request with a path and sets the variable to its path ID.
perflow.response_selection .response Specifies the appropriate response to be used by the Reject Ending agent. The Response Selection agent sets this perflow variable.