Manual Chapter : API Protection Concepts

Applies To:

Show Versions Show Versions

BIG-IP APM

  • 16.0.0
Manual Chapter

API Protection Concepts

Introducing API protection

API calls originating from enterprise, partner, and consumer applications that access cloud and on-premise 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.
  • Quotas, whitelists, and blacklists can be configured for rate limiting API requests.
  • 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.
You can also configure rate limiting, whitelist, and a blacklist in the API protection profile and enforce it by using an API Rate Limiting agent in the per-request policy.
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
  • API Rate Limiting
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 OAuth 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. You can configure rate limiting and add an API Rate Limiting agent to the per-request policy.

About Request Classification

The Request Classification Agent classifies incoming API requests based on request path and method. When you create an API protection profile, 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 API Rate Limiting

You can use the API Rate Limiting agent to enforce rate limiting, spike control, blacklists, and whitelists for each API request. The API Rate Limiting agent can appear one or more times in per-request policies and should not be used in subroutines. This agent is located under Traffic Management in the visual policy editor.
You can assign more than one rate limiting configuration to the Rate Limiting agent. (Each rate limiting configuration specifies a rate limiting key, quota, and spike control info.) All assigned rate limiting configurations apply to each request, and you can apply weights to the configurations to allow certain requests to have higher weight. The weights indicate how much to add to the quota for each request.
The API Rate Limiting agent enforces Blacklists or Whitelists that are configured in the API protection profile when Enforce Blacklist and Enforce Whitelist are set to Enabled. When the system finds a
key::key_value
specified in the Blacklist, the request is sent to the fallback branch. When the system finds a
key::key_value
specified in the Whitelist, the request is sent to the successful branch.
The API protection per-request policy enforces rate limiting in this order:
  • Blacklist
  • Whitelist
  • Rate Limiting quota and spike values

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 session.custom.temp.unique_key [ 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.
perflow.api_rate_limiting
.result
Specifies whether the request is within the rate limiting quotas or if it exceeded the limits. The API Rate Limiting agent sets this variable to indicate the results of rate limiting enforcement.