Manual Chapter :
API Protection Concepts
Applies To:
Show VersionsBIG-IP APM
- 14.1.5, 14.1.4, 14.1.3, 14.1.2, 14.1.0
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. |