open banking
5 TopicsUsing Shape IBD to protect OIDC IdP from Bot Attacks in Open Banking scenarios
Introduction Open Banking implementation standards reserve ample space for describing security controls that need to be in place to secure the access to APIs, with particular focus on end-user consent management. The mechanisms ensuring end-users can securely give banks their consent for third party fintechs to perform banking operations on their behalf, are the bedrock of Open Banking standards. The banks are required to put in place Strong Customer Authentication (SCA) methods allowing the end-user to login to the OIDC IdP/ OAuth Authorization Server to give their consent for the access token to be generated. This implies the existence of a login form, most often reinforced with multi-factor authentication methods. While these methods provide a good measure of defense against less sophisticated threats, bot networks are still capable of being platforms for launching application denial of service or advanced financial fraud attacks so warding off bots allows the defense to keep one step ahead of the attackers. Shape represents best-in-class bot defense available in the market today, relying on a managed service model backed by advanced AI/ML models and dedicated SOC teams. Integrated Bot Defense (IBD) is the first self-service offering from Shape, encapsulated in an easy-to-use form factor. Customers don't need to route their traffic to Shape cloud, IBD integration with Shape backend systems relying instead on API calls. Also, customers can manage the entire onboarding process through the self-service dashboard available on F5's Cloud Services portal, allowing quick addition of new applications to be protected. IBD supports BIG-IP as an insertion point in the customer environment, with more methods to be added. To assist with BIG-IP deployment of IBD, the onboarding process is making available for download a per-application customized iApp template that doesn't require deep BIG-IP expertise to install and provides a wizard-like way of configuring IBD. Setup The high-level diagram of the lab used to simulate an Open Banking deployment is shown below, along with the roles performed by each element: The Open Banking workflow for an authorized end-user is described below: The user logs into the Third Party Provider application ("client") and creates a new funds transfer The TPP application redirects the user to the OAuth Authorization Server / OIDC IdP - PingFederate The user provides its credentials to PingFederate and gets access to the consent management screen where the required "payments" scope will be listed If the user agrees to give consent to the TPP client to make payments out of his/her account, PingFederate will generate an authorization code (and an ID Token) and redirect the user to the TPP client The TPP client opens an MTLS connection to the IdP, authenticates itself with a client certificate, exchanges the authorization code for a user-constrained access token and attaches it as a bearer token to the /domestic-payments call sent to the API gateway over an MTLS session authenticated with the same client certificate The API Gateway terminates the MTLS session and obtains the client certificate authenticates the access token by downloading the JSON Web Keys from PingFederate, checks the hashed client certificate matches the value found in the token and grants conditional access to the backend application. The App Protect WAF and DoS modules perform advanced security checks before releasing the request to the backend server pod. OpenBullet2 launching credential stuffing attacks Integrated Bot Defense installation To install IBD, login to your F5 Cloud Services account, select Integrated Bot Defense and click on Add Application button. Select BIG-IP as the insertion point and click Next. Ensure Web App application type is selected (default) and input the name of the application. Click Save. Download the iApp template, import it into BIG-IP and create an Application. For step-by-step guidance and details on the iApp configuration options, consult the Integrated Bot Defense Configuration Guide for BIG-IP. Testing We used OpenBullet2 to simulate a malicious bot performing credential stuffing attacks against the OIDC IdP / OAuth Authorization Server, PingFederate. Although OpenBullet2 is configured to use valid credentials, no hit is registered after 3 attempts due to IBD blocking all login attempts generated by bots. Examining the F5 Cloud Services dashboard, we can see how IBD identifies and blocks bot sessions while allowing human sessions to pass through. The 3 malicious bots blocked correspond to the 3 attempts made by OpenBullet2 - the valid human traffic has been generated in the background. Conclusion Integrated Bot Defense brings the sophisticated AI/ML technologies used by Shape Defense in a package that is very easy to deploy and configure with minimal configuration changes to the infrastructure components, such as BIG-IP. The ability of IBD to detect advanced tools like OpenBullet2 makes it ideal for securing high-value targets such as Open Banking consent management infrastructure. In this article we demonstrated how IBD can be deployed inside customer's infrastructure, using a BIG-IP device as an insertion point, to protect a PingFederate server acting as OIDC IdP/ OAuth Authorization Server in Open Banking scenarios. Resources The UDF lab environment used to build this configuration can be found here.1.7KViews2likes0CommentsConfiguring NGINX API micro-gateway to support Open Banking's Advanced FAPI security profile
Introduction In my last article, Integrating NGINX Controller API Management with PingFederate to secure financial services API transactions, we have seen how to configure NGINX Controller to perform basic JWT authorization against PingFederate, configured as OIDC IdP / OAuth Autorization Server. One weakness of the basic JWT authentication mechanism is the lack of context: anyone presenting a valid JWT will be allowed to performed the actions granted by the token, even if the sender is not the original OAuth client that was issued the token. This opens an avenue for attackers to use JWTs stollen from their rightful owners. Ideally, a mechanism of restricting the usage of the JWT to their original requestor is needed and this type of protection is specifically required for API calls presenting the highest risk, such as financial API calls. For example, Financial-grade API (FAPI) Security Profile 1.0 - Part 2: Advanced (Read and Write API Security Profile) specifies that: Authorization server: shall only issue sender-constrained access tokens; shall support MTLS as mechanism for constraining the legitimate senders of access tokens; Uncertainty of resource server handling of access tokens The protected resources that conform to this document shall not accept a bearer access token. They shall only support sender-constrained access tokens via MTLS. It is therefore useful to examine the configuration of NGINX, in its micro-gateway deployment mode, needed to perform the function of a resource server in cases requiring the Advanced FAPI security profile. Setup A high-level diagram of the lab environment used to demonstrate this setup is found below: The roles performed by each network element are described below: Authentication and API flow The workflow is very similar with the one described in my last article, with the differences highlighted here in bold: The user logs into the Third Party Provider application ("client") and creates a new funds transfer The TPP application redirects the user to the OAuth Authorization Server / OIDC IdP - PingFederate The user provides its credentials to PingFederate and gets access to the consent management screen where the required "payments" scope will be listed If the user agrees to give consent to the TPP client to make payments out of his/her account, PingFederate will generate an authorization code (and an ID Token) and redirect the user to the TPP client The TPP client opens an MTLS connection to the IdP, authenticates itself with a client certificate, exchanges the authorization code for a user-constrained access token and attaches it as a bearer token to the /domestic-payments call sent to the API gateway over an MTLS session authenticated with the same client certificate The API Gateway terminates the MTLS session and obtains the client certificate, authenticates the access token by downloading the JSON Web Keys from PingFederate, checks the hashed client certificate matches the value found in the token and grants conditional access to the backend application The Kubernetes Ingress receives the API call and performs WAF security checks via NGINX App Protect The API call is forwarded to the backend server pod Examining the differences between the workflows, it becomes apparent the extra actions NGINX API micro-gateway has to perform to support this advanced security use case are MTLS termination and client certificate hash verification. NGINX API micro-gateway configuration The full configuration is available on DevCentral's Code Share: Configure NGINX microgateway for MTLS termination and client certificate hash verification I will highlight below the most relevant parts of the configuration. MTLS termination server { server_name api.bank.f5lab; listen 443 ssl; ssl_certificate /etc/nginx/f5lab.crt; ssl_certificate_key /etc/nginx/f5lab.key; ssl_session_cache off; ssl_prefer_server_ciphers off; ssl_client_certificate /etc/nginx/updated_ca.crt; ssl_verify_client on; ssl_verify_depth 10; A detailed explanation of each of these commands can be found in the ngx_http_ssl_module user guide. JWT client certificate hash verification To compute and validate the client certificate hash, we will use an njs script (more information on njs scripting language and installation process can be found here). The njs script used (named "x5t.js" in our case) is shown below: function validate(r) { var clientThumbprint = require("crypto") .createHash("sha256") .update(Buffer.from(r.variables.ssl_client_raw_cert.replace(/(\n|----|-BEGIN|-END| CERTIFICATE-)/gm, ''), 'base64')) .digest("base64url"); return clientThumbprint === r.variables.jwt_cnf_fingerprint ? '1' : '0'; } export default { validate } Importing the "x5t.js" script in the main nginx configuration is done by: js_import /etc/nginx/x5t.js; We are populating the value of variable $jwt_cnf_fingerprint (available to the njs script via "r.variables.jwt_cnf_fingerprint") by extracting the 'x5t#S256' value from JWT: auth_jwt_claim_set $jwt_cnf_fingerprint 'cnf' 'x5t#S256'; The "validate" function of "x5t.js" will the compare the value of $jwt_cnf_fingerprint variable extracted from JWT with the computed SHA256 hash of the client certificate and set the validation result in the $thumbprint_match variable. js_set $thumbprint_match x5t.validate; Lastly, we will make a decision to accept or block client's access based on the validation result: if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } Conclusion Supporting MTLS termination and client certificate hash validation against sender-constrained JWTs issued by Authorization Servers such as PingFederate, enables NGINX API micro-gateway to support Open Banking's Advanced FAPI security profile. Resources The UDF lab environment used to build this configuration can be found here.1.9KViews1like0CommentsConfigure NGINX microgateway for MTLS termination and client certificate hash verification
Problem this snippet solves: This configuration is used to support advanced Open Banking scenarios where NGINX performs MTLS termination and checks the validity of the JWT by comparing the computed client certificate hash with the hash found inside JWT. How to use this snippet: The code snipped shows the contents of nginx.conf and x5t.js, the njs function responsible for computing the client certificate hash. Code : ########## #nginx.conf: ########## user nginx; worker_processes auto; load_module modules/ngx_http_js_module.so; load_module modules/ngx_stream_js_module.so; error_log /var/log/nginx/error.log debug; events { worker_connections 10240; } http { include /etc/nginx/mime.types; default_type application/octet-stream; error_log /var/log/nginx/error.log; log_format jwt_log_format '$remote_addr - "$jwt_claim_sub" [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "$host" sn="$server_name" rt=$request_time ua="$upstream_addr" us="$upstream_status" ut="$upstream_response_time" ul="$upstream_response_length" cs="$upstream_cache_status" http_authorization="$http_authorization" ssl_client_verify="$ssl_client_verify" jwt_cnf_fingerprint="$jwt_cnf_fingerprint" client_cert=$ssl_client_raw_cert thumbprint_match=$thumbprint_match'; sendfile on; keyval_zone zone=one:1m type=ip state=one.keyval timeout=1h; keyval $remote_addr $target zone=one; keepalive_timeout 65; server_tokens off; map $request_uri $request_uri_path { '~^(?P [^?]*)(\?.*)?$' $path; } limit_req_zone $binary_remote_addr zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr:10m rate=5000r/m; proxy_cache_path /etc/nginx/jwk_bank_idp levels=1 keys_zone=jwk_bank_idp:1m max_size=10m; map $jwt_claim_scope $passes_conditional_policy_policy_1_761 { default 0; ~.*payments.* 1; } auth_jwt_claim_set $jwt_cnf_fingerprint 'cnf' 'x5t#S256'; js_import /etc/nginx/x5t.js; js_set $thumbprint_match x5t.validate; server { server_name api.bank.f5lab; listen 443 ssl; ssl_certificate /etc/nginx/f5lab.crt; ssl_certificate_key /etc/nginx/f5lab.key; ssl_session_cache off; ssl_prefer_server_ciphers off; ssl_client_certificate /etc/nginx/updated_ca.crt; ssl_verify_client on; ssl_verify_depth 10; access_log /var/log/nginx/access.log jwt_log_format; location = /_jwks_uri_bank_idp { internal; subrequest_output_buffer_size 64k; proxy_cache jwk_bank_idp; proxy_cache_valid 200 1h; proxy_cache_use_stale error timeout updating; proxy_ignore_headers Cache-Control Expires Set-Cookie; proxy_method GET; proxy_pass https://idp.bank.f5lab/ext/open_banking; } location = /open-banking/v3.1/pisp/domestic-payments { if ($request_method !~ '^GET|POST$') { return 405; } error_log /dev/null; proxy_set_header Host ''; proxy_set_header Host bank.f5lab; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ''; proxy_http_version 1.1; limit_req zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr nodelay; limit_req_status 429; auth_jwt bank_idp; auth_jwt_key_request /_jwks_uri_bank_idp; if ($passes_conditional_policy_policy_1_761 = 0) { return 403 'Access denied because payments scope is missing'; } if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } if ($ssl_client_verify != "SUCCESS") { return 403 'Client SSL cert verification failed'; } proxy_pass http://wl_openbanking; } location ~* /open-banking/v3.1/pisp/domestic-payments/* { if ($request_method !~ '^GET|POST$') { return 405; } error_log /dev/null; proxy_set_header Host ''; proxy_set_header Host bank.f5lab; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ''; proxy_http_version 1.1; limit_req zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr nodelay; limit_req_status 429; auth_jwt bank_idp; auth_jwt_key_request /_jwks_uri_bank_idp; if ($passes_conditional_policy_policy_1_761 = 0) { return 403 'Access denied because payments scope is missing'; } if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } if ($ssl_client_verify != "SUCCESS") { return 403 'Client SSL cert verification failed'; } proxy_pass http://wl_openbanking; } location = /open-banking/v3.1/pisp/domestic-payment-consents { if ($request_method !~ '^GET|POST$') { return 405; } error_log /dev/null; proxy_set_header Host ''; proxy_set_header Host bank.f5lab; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ''; proxy_http_version 1.1; limit_req zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr nodelay; limit_req_status 429; auth_jwt bank_idp; auth_jwt_key_request /_jwks_uri_bank_idp; if ($passes_conditional_policy_policy_1_761 = 0) { return 403 'Access denied because payments scope is missing'; } if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } if ($ssl_client_verify != "SUCCESS") { return 403 'Client SSL cert verification failed'; } proxy_pass http://wl_openbanking; } location ~* /open-banking/v3.1/pisp/domestic-payment-consents/* { if ($request_method !~ '^GET|POST$') { return 405; } error_log /dev/null; proxy_set_header Host ''; proxy_set_header Host bank.f5lab; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ''; proxy_http_version 1.1; limit_req zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr nodelay; limit_req_status 429; auth_jwt bank_idp; auth_jwt_key_request /_jwks_uri_bank_idp; if ($passes_conditional_policy_policy_1_761 = 0) { return 403 'Access denied because payments scope is missing'; } if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } if ($ssl_client_verify != "SUCCESS") { return 403 'Client SSL cert verification failed'; } proxy_pass http://wl_openbanking; } location ~* /open-banking/v3.1/pisp/domestic-payments/*/payment-details { if ($request_method !~ '^GET|POST$') { return 405; } error_log /dev/null; proxy_set_header Host ''; proxy_set_header Host bank.f5lab; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ''; proxy_http_version 1.1; limit_req zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr nodelay; limit_req_status 429; auth_jwt bank_idp; auth_jwt_key_request /_jwks_uri_bank_idp; if ($passes_conditional_policy_policy_1_761 = 0) { return 403 'Access denied because payments scope is missing'; } if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } if ($ssl_client_verify != "SUCCESS") { return 403 'Client SSL cert verification failed'; } proxy_pass http://wl_openbanking; } location ~* /open-banking/v3.1/pisp/domestic-payment-consents/*/funds-confirmation { if ($request_method !~ '^GET|POST$') { return 405; } error_log /dev/null; proxy_set_header Host ''; proxy_set_header Host bank.f5lab; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection ''; proxy_http_version 1.1; limit_req zone=policy_1_99c0d81f-d277-4cd3-a97b-e94dde53453f_binary_remote_addr nodelay; limit_req_status 429; auth_jwt bank_idp; auth_jwt_key_request /_jwks_uri_bank_idp; if ($passes_conditional_policy_policy_1_761 = 0) { return 403 'Access denied because payments scope is missing'; } if ($thumbprint_match != 1) { return 403 'Access denied because client SSL certificate thumbprint does not match jwt_cnf_fingerprint'; } if ($ssl_client_verify != "SUCCESS") { return 403 'Client SSL cert verification failed'; } proxy_pass http://wl_openbanking; } if ($target) { return 403; } } upstream wl_openbanking { zone wl_openbanking 512k; server 10.0.0.1:30511; keepalive 64; keepalive_requests 100; keepalive_timeout 60s; } } ################################################################################### ########## #x5t.js ########## function validate(r) { var clientThumbprint = require("crypto") .createHash("sha256") .update(Buffer.from(r.variables.ssl_client_raw_cert.replace(/(\n|----|-BEGIN|-END| CERTIFICATE-)/gm, ''), 'base64')) .digest("base64url"); return clientThumbprint === r.variables.jwt_cnf_fingerprint ? '1' : '0'; } export default { validate } Tested this on version: 16.01.3KViews1like0CommentsIntegrating NGINX Controller API Management with PingFederate to secure financial services API transactions
Introduction The previous article in the "Securing financial services APIs" series, "Using NGINX Controller API Management Module and NGINX App Protect to secure financial services API transactions", described a setup where NGINX Controller APIm, acting as an OAuth Resource Server, was using F5's APM as an OIDC IdP / OAuth Autorization Server in an OAuth/OIDC authentication flow. The current article explores the integration of NGINX Controller APIm with PingFederate, one of the market leading identity management solutions, in a similar setup. Ping Identity has partnered with OBIE (Open Banking Implementation Entity) the body responsible for UK Open Banking implementation as a response to EU's PSD2 directive and, as such, it acquired a front seat in the development of Open Banking initiative, one of the most mature examples of financial service API. Ping Identity technology is also Financial-Grade API (FAPI) compliant, supporting the features critical in ensuring higher security for financial API transactions, while maintaining seamless user experience and ease of configuration. Ping Identity's PDS2 & Open Banking technical solution guide can be found here, while this article focusses primarily on the ease of configuration of NGINX Controller APIm to interact with PingFederate solution in a basic financial services API scenario. Setup For demo purposes, as a backend banking application we used a server stub generated from UK Open Banking's OpenAPI spec deployed in a Kubernetes environment, having NGINX App Protect deployed on Kubernetes Ingress controller as an API WAF. The API Gateway and API Management function is implemented by NGINX API Gateway and NGINX Controller APIm, placed in front of the Kubernetes environment. The configuration of all the above (backend server, NAP/KIC and NGINX APIm) is managed through a CI/CD pipeline configured in Gitlab, simulating a modern application development environment. Authentication and API flow This demo is implementing the Authorization Code flow to enable a "domestic payment" transaction. Summarising the steps of the authentication and API flow (refer to the setup diagram above): 1. The user logs into the Third Party Provider application ("client") and creates a new funds transfer 2. The TPP application redirects the user to the OAuth Authorization Server / OIDC IdP - PingFederate 3. The user provides its credentials to PingFederate and gets access to the consent management screen where the required "payments" scope will be listed 4. If the user agrees to give consent to the TPP client to make payments out of his/her account, PingFederate will generate an authorization code (and an ID Token) and redirect the user to the TPP client 5. The TPP client exchanges the authorization code for an access token and attaches it as a bearer token to the /domestic-payments call sent to the API gateway 6. The API Gateway authenticates the access token by downloading the JSON Web Keys from PingFederate and grants conditional access to the backend application 7. The Kubernetes Ingress receives the API call and performs WAF security checks via NGINX App Protect 8. The API call is forwarded to the backend server pod NGINX APIm configuration In this scenario, NGINX APIm is performing the Resource Server OAuth role, where it downloads the JWKs from the OAuth Authorization Server / OIDC IdP (PingFederate) and checks the authenticity of the access token presented in the API call. Additionally, it may apply further checks to conditionally grant access to the application - in this demo it will check for the presence of the "payments" scope. The NGINX APIm configuration is straightforward and consists of two steps: 1. Configuring the IdP Go to Services => Identity Providers and click on Create identity Providers. Fill in the mandatory parameters Name, Environment and Type (JWT). Enter the JWKs URL location and the caching duration. 2. Configuring the OAuth authorization and conditional access criteria Go to Services =>APIs , select an API Definition and edit the associated Published API. Navigate to Routing and edit the Component to be protected, navigating to Security/Authentication. Select the previously created Identity Provider and optionally enable conditional access. As an example, access is granted if "payments" is one of the scopes found in the access token. Conclusion NGINX APIm offers a very simple yet granular way of configuring NGINX API Gateway as an OAuth Resource Server and allows the integration with an industry-leading IAM solution, PingFederate, to protect financial services API transactions. Links UDF lab environment link.788Views1like0CommentsUsing NGINX Controller API Management Module and NGINX App Protect to secure financial services API transactions
As financial services APIs (such as Open Banking) are concerned primarily with managing access to exposed banking APIs, the security aspect has always been of paramount importance. Securing financial services APIs is a vast topic, as security controls are distributed among different functions, such as user authentication at the Identity Provider level, user authorization and basic API security at the API Gateway level and advanced API security at the WAF level. In this article we will explore how two NGINX products, Controller API Management Module and App Protect, can be deployed to secure the OAuth Authorization Code flow which is a building block of the access controls used to secure many financial services APIs.. Physical setup The setup used to support this article comprises of NGINX Controller API Management Module, providing API Management functions through an instance of NGINX API Gateway and NGINX App Protect deployed on a Kubernetes Ingress Controller providing advanced security for the Kubernetes-deployed demo application, Arcadia Finance. These elements are being deployed and configured in an automated fashion using a Gitlab CI/CD pipeline. The visualization for NGINX App Protect is provided by NAP dashboards deployed in ELK. Note: For the purpose of supporting this lab, APM was configured as an OAuth Authorization Server supporting OpenID Connect. Its configuration, along with the implementation details of the third party banking application (AISP/PISP), acting as an OAuth Client, is beyond the scope of this article. In an OAuth Authorization Code flow, the PSU (End User) is initiating an API request through the Account or Payment Information Services Provider (AISP/PISP Application) which first redirects the end user to the Authorization Server. Strong Customer Authentication is being performed between the end user and Authorization Server which, if successful, will issue an authorization code and redirect the user back to theAISP/PISP Application. The AISP/PISP Application will exchange the authorization code for an ID Token and a JWT Access Token, the latter will be attached as a bearer token to the initial end-user API request which will then be forwarded to the API Gateway. The API Gateway will authenticate the signature of the JWT Access Token by downloading the JSON Web Key (JWK) from the Authorization Server and may apply further security controls by authorising the API call based on JWT claims and/or apply rate limits. Worth noting here is the security function of the API Gateway, which provides positive security by allowing only calls conforming to published APIs, in addition to authentication and authorization functions. The Web Application Firewall function, represented here by the NGINX App Protect deployed on the Kubernetes Ingress Controller (KIC), will add negative security protection, by checking the request against a database of attack signatures, and advanced API security, by validating the API request against the OpenAPI manifest and providing Bot detection capabilities. Configuration To configure the NGINX Controller API Management Module, first create an Application by sending a POST request to 'https://{{ my_controller }}/api/v1/services/environments/env_prod/apps' having the following body: { "metadata": { "name": "app_api", "displayName": "API Application Arcadia", "description": "", "tags": [] }, "desiredState": {} } Then create an Identity Provider, pointed at the Authorization Server's JWK endpoint, by sending a PUT request to 'https://{{ my_controller }}/api/v1/security/identity-providers/bank_idp' having the following body: { "metadata": { "name": "bank_idp", "tags": [] }, "desiredState": { "environmentRefs": [ { "ref": "/services/environments/env_prod" } ], "identityProvider": { "type": "JWT", "jwkFile": { "type": "REMOTE_FILE", "uri": "https://bank.f5lab/f5-oauth2/v1/jwks", "cacheExpire": "12h" } } } } Create an API definition by sending a PUT request to 'https://{{ my_controller }}/api/v1/services/api-definitions/arcadia-api-def/versions/v1' with the following body: { "metadata": { "name": "v1", "displayName": "arcadia-api-def" }, "desiredState": { "specs": { "REST": { "openapi": "3.0.0", "info": { "version": "v1", "title": "arcadia-api-def" }, "paths": {} } } } } Then import the OpenAPI definition by sending a PUT request to 'https://{{ my_controller }}/api/v1/services/api-definitions/arcadia-api-def/versions/v1/import' with the OpenAPI JSON as a request body. Publish the API definition by sending a PUT request to 'https://{{ my_controller }}/api/v1/services/environments/env_prod/apps/app_api/published-apis/prod-api', with the following body: { "metadata": { "name": "prod-api", "displayName": "prod-api", "tags": [] }, "desiredState": { "apiDefinitionVersionRef": { "ref": "/services/api-definitions/arcadia-api-def/versions/v1" }, "gatewayRefs": [ { "ref": "/services/environments/env_prod/gateways/gw_api" } ] } } Declare the necessary back-end components (in this example webapi-kic.nginx-udf.internal Kubernetes workload) by sending a PUT to 'https://{{ my_controller }}/api/v1/services/environments/env_prod/apps/app_api/components/cp_moneytransfer_api' with the following body: { "metadata": { "name": "cp_moneytransfer_api", "displayName": "cp_moneytransfer_api", "tags": [] }, "desiredState": { "ingress": { "uris": { "/api/rest/execute_money_transfer.php": { "php": { "get": { "description": "Send money to a friend", "parameters": [ { "in": "body", "name": "body", "required": true, "schema": { "type": "object" } } ], "responses": { "200": { "description": "200 response" } } }, "matchMethod": "EXACT" } } }, "gatewayRefs": [ { "ref": "/services/environments/env_prod/gateways/gw_api" } ] }, "backend": { "ntlmAuthentication": "DISABLED", "preserveHostHeader": "DISABLED", "workloadGroups": { "wl_mainapp_api": { "loadBalancingMethod": { "type": "ROUND_ROBIN" }, "uris": { "http://webapi-kic.nginx-udf.internal:30276": { "isBackup": false, "isDown": false, "isDrain": false } } } } }, "programmability": { "requestHeaderModifications": [ { "action": "DELETE", "applicableURIs": [], "headerName": "Host" }, { "action": "ADD", "applicableURIs": [], "headerName": "Host", "headerValue": "k8s.arcadia-finance.io" } ] }, "logging": { "errorLog": "DISABLED", "accessLog": { "state": "DISABLED" } }, "security": { "rateLimits": { "policy_1": { "rate": "5000r/m", "burstBeforeReject": 0, "statusCode": 429, "key": "$binary_remote_addr" } }, "conditionalAuthPolicies": { "policy_1": { "action": "ALLOW", "comparisonType": "CONTAINS", "comparisonValues": [ "Payment" ], "sourceType": "JWT_CLAIM", "sourceKey": "scope", "denyStatusCode": 403 } }, "identityProviderRefs": [ { "ref": "/security/identity-providers/bank_idp" } ], "jwtClientAuth": { "keyLocation": "BEARER" } }, "publishedApiRefs": [ { "ref": "/services/environments/env_prod/apps/app_api/published-apis/prod-api" } ] } } Note the 'security' block, specifying the JWT authentication, the Identity Provider from where to download the JWK, the authorization check applied on each request and the rate limit policy. The configuration used to deploy NGINX App Protect on the Kubernetes Ingress Controller can be consulted here. Summary In this article we showed how NGINX Controller API Management Module and NGINX App Protect can be deployed to protect API calls as part of the OAuth Authorization Code flow which is a basic flow used to control the access to many financial services APIs. Links UDF lab environment link.1.7KViews1like0Comments