Welcome to NGINX Controller 3.x with BIG-IP Lab

Publish and protect modern applications

Warning

For any remark or mistake in this lab, please reach out Matthieu DIERICK or fork this repo and fix it with a merge request.

_images/index.png

Class 1 - Understand the infrastructure and the workflow

Welcome into the NGINX Controller 3.x with BIG-IP Lab

Warning

For any remark or mistake in this lab, please reach out Matthieu DIERICK or fork this repo and fix it with a merge request.

Note

The video below will explain you how Arcadia Finance application works and is structured. It is important to understand this part before configuring the lab. In the next section, we present the same if you don’t want to watch the video.

Architecture of Arcadia Application

Note

We will use the famous Arcadia Finance application in this lab. This application is based on 4 microservices. You can find below the different IP addresses and Ports used by NGINX and BIG-IP.

Note

This application is available in GitLab in case you want to build your own lab : https://gitlab.com/arcadia-application

First of all, it is important to understand how Arcadia app is split between microservices

This is how Arcadia App looks like when the 4 microservices are up and running, and you can notice how traffic is routed based on URI

_images/arcadia-api.png

But you can deploy Arcadia Step by Step

If you deploy only Main App and Back End services.

_images/MainApp.png

Note

You can see App2 (Money Transfer) and App3 (Refer Friend) are not available. There is dynamic content showing a WARNING instead of a 404 or blank frame.


If you deploy Main App, Back End and Money Tranfer services.

_images/app2.png

If you deploy Main App, Back End, Money Tranfer and Refer Friend services.

_images/app3.png

The diagram belows show the IP addresses and the ports used for all the routes

Note

For a lab standpoints, these IP addresses and ports does not change. But in a real life, they are dynamic.

_images/arcadia-routes.png

Workflow of the demo

The demo is split in 3 classes
  • Deploy, publish and protect Arcadia Web application
    • Deploy and publish Arcadia Main App

    • Deploy and publish Money Transfer App

    • Deploy and publish Refer Friends App

    • Apply WAF policy

  • Publish and protect Arcadia API
    • Publish the API using an OpenAPI 3.0 spec file

    • Protect the API with Advanced WAF and APM using OpenAPI 3.0 spec file

    • Discover the new Developer Portal


Step 1 - DevOps deploy Arcadia application

Note

Goal is to use the GUI in the NGINX Controller for our traditional customers. NetOps will configure the services (MainApp and BackEnd) manually.

Tasks:

  1. DevOps commit a new code in GitLab in order to publish a brand new application “Arcadia Bank”

  2. GitLab webhooks this commit and asks Jenkins to run a pipeline. This pipeline:
    1. Deploy Arcadia application in Kubernetes (Terraform).

    2. Deploy nodeports in Kubernetes (but it could be KIC) (Terraform).

    3. Deploy NGINX+ instances (ADC) in Docker, in front of this K8S cluster (Terraform)

    4. Create Gateways in NGINX Controller for each NGINX+ instance (Ansible)

    5. Deploy AS3 template into front BIGIP to publish publically the application - without WAF (Ansible)

  3. NetOps create ADC configuration in NGINX controller in order to “route” traffic to the right K8S service

    1. MainApp /* to service MainApp

    2. BackEnd /file* to service BackEnd

_images/MainApp1.png

Warning

At this stage, the first part of the application is published and can be accessed and demonstrated. We can see Money Transfert application is not yet there, same for Refer Friends.


Step 2 - DevOps deploy Money Transfer application

Note

Goal is to demonstrate NGINX Controller has a REST API to configure objects. NetOps will configure the service (Money Transfer) via REST API.

Tasks:

  1. DevOps commit a new code in GitLab in order to publish the second part of the Arcadia Bank website. This new application allows money transfer between friends.

  2. GitLab webhooks this commit and ask Jenkins to run a pipeline. This pipeline:
    1. Deploy Money Transfer application in Kubernetes (Terraform)

    2. Deploy nodeports in Kubernetes (Terraform)

  3. NetOps use REST API to publish this new app on NGINX+ instances

_images/app21.png

Warning

At this stage, the Money Transfer application is published and can be accessed and demonstrated


Step 3 - DevOps deploy Refer Friends application

Note

Goal is to demonstrate NGINX Controller can be part of the application lifecycle and CICD. NetOps don’t configure anything.

Tasks:

  1. DevOps commit a new code in GitLab in order to publish the third and last part of the Arcadia Bank website. This new application allow a customer to refer friends with their email address.

  2. GitLab webhooks this commit and ask Jenkins to run a Pipeline. This pipeline:
    1. Deploy Refer Friends application in Kubernetes (Terraform)

    2. Deploy nodeports in Kubernetes (Terraform)

    3. Configure all components in NGINX Controller (Ansible)

_images/app31.png

Warning

At this stage, the Refer Friends application is published and can be accessed and demonstrated. The Arcadia Bank website is finished, but not yet secured.


Step 4 - NetOps/SecOps publish WAF policy to protect Arcadia application

Note

Goal is to demonstrate BIG-IP Advanced WAF has a Declarative API interface to push WAF policies.

Task:

  1. NetOps run a Jenkins pipeline that will push a new AS3 declaration with a WAF policy built by Secops

Warning

At this stage, the Arcadia Bank website is published and secured.


Step 5 - Publish Arcadia API

Note

Goal is to demonstrate the new Controller capabilties with API management and gateway

Task:

  1. DevOps provide with an API specification file (OpenAPI 3.0 - OAS3)

  2. NetOps import this file into the Controller APIm and publish the API

  3. SecOps import his file into the BIG-IP and protect the API (WAF + Access)

  4. Developpers can access the new Developper Portal



Class 2 - Deploy, Publish and Protect Arcadia Web Application

In this section, we will deploy, publish and protect Arcadia application

DevOps deploy Arcadia Application - Main app

In this module, we will deploy the 2 main containers for Arcadia Bank application and we will publish them.

Note

At the end of this module, Arcadia Bank application will look like this.

_images/MainApp2.png

Note

As a DevOps, you will deploy Arcadia Application (main and back end pods) with an automation tool set

Step 1 - Deploy Arcadia Main app with a CI/CD pipeline like a DevOps

Connect to Jumhost RDP and Login as user / user

  1. Open Chrome, you can notice Chrome opens all the tabs for you

  2. Login to all tools

    1. Controller : admin@nginx-udf.internal / admin123!

    2. Jenkins : admin / admin

    3. GitLab : root / F5twister$

      Warning

      If GitLab does not start, restart the docker in the GitLab VM (WebSSH > docker restart gitlab). Wait 5 minutes.

    4. Kubernetes : click on skip

    5. BIG-IP : admin / admin

  3. In Gitlab, click on Administrator / Arcadia-MainApp

    1. Click on file deploy

    2. Click edit and make a modification, like YES !!!!!

    3. Click Commit changes

Note

At this moment, you simulate a commit like a DevOps. This commit will trigger a webhook to Jenkins, so that Jenkins executes a pipeline.

  1. In Jenkins, click on DeployMainApp pipeline

  2. A pipeline is running, click on it

  3. You can follow the steps

_images/pipeline_mainapp.png

Note

At this stage, Arcadia Main app and Back End app are deployed un K8S. But you need to publish them with NGINX+ via the controller.


Step 2 - Publish Arcadia application with NGINX+ and Controller

The Jenkins pipeline did several things

  1. Deployed Arcadia application (main and back end pods) in Kubernetes

    1. Connect to Kubernetes and check that.

    2. You can see 2 deployments (main and back) with nodeports services

  2. Started 3 NGINX+ instances in a docker

    1. WebSSH to CICD and DOCKER (NGINX API gw, Dev Portal)

    2. Run a docker ps

    ubuntu@ip-10-1-1-9:~$ docker ps
    CONTAINER ID        IMAGE                            COMMAND                  CREATED             STATUS              PORTS                                                              NAMES
    bf86e23a9807        nginx-plus:36v1                  "sh /entrypoint.sh"      33 seconds ago      Up 31 seconds       10.1.20.9:8080->80/tcp, 10.1.20.9:8443->443/tcp                    NginxPlusAPI
    74d679bdf5fb        nginx-plus:36v1                  "sh /entrypoint.sh"      33 seconds ago      Up 31 seconds       80/tcp, 10.1.20.12:8090->8090/tcp                                  NginxPlusDevPortal
    ac12c0f3148a        nginx-plus:36v1                  "sh /entrypoint.sh"      33 seconds ago      Up 32 seconds       10.1.20.10:8080->80/tcp, 10.1.20.10:8443->443/tcp                  NginxPlusWebApp
    ab75d7bd60bb        nginx                            "nginx -g 'daemon of…"   7 months ago        Up 13 hours         0.0.0.0:80->80/tcp                                                 lab-nginx
    35ddc5adc34d        sameersbn/bind:9.11.3-20190706   "/sbin/entrypoint.sh…"   9 months ago        Up 13 hours         0.0.0.0:53->53/tcp, 0.0.0.0:10000->10000/tcp, 0.0.0.0:53->53/udp   bind
    
  3. Check if NGINX+ instances appears in the controller

    1. In the controller GUI, click top left corner icon, and infrastructure

    2. You can see 3 instances running

    _images/instances.png
  4. Deployed an AS3 declaration into the BIG-IP in order to publish the NGINX+ instance externally

Note

It is time to configure the NGINX+ instances in order to publish Arcadia application (main and back services)


Configure the Controller

Warning

For all the commands below, there are CASE SENSITIVE

  1. Connect to the controller (admin@nginx-udf.internal / admin123!)

  2. Click on top left corner icon and Services

  3. Click on Apps and create app

    1. Application name : app_webapp

    2. Display name : Web Application Arcadia

    3. Environment : Production Environment

  4. Click submit

    _images/create_app_main.png
  5. Click on Create Component

    1. Configure the component as below

    _images/cp_main_1.png

_images/cp_main_2.png

_images/cp_main_3.png

Warning

Don’t forget to click on done


_images/cp_main_4.png

_images/cp_main_5.png

Warning

Don’t forget to click on done twice

Note

Click submit


  1. Get back to Web App and add a new Component

  2. Do the same, but for the back end service

    _images/cp_back_1.png

_images/cp_back_2.png

_images/cp_back_3.png

Warning

Don’t forget to click on done


_images/cp_back_4.png

_images/cp_back_5.png

Warning

Don’t forget to click on done twice

Note

Click submit


Step 3 - Test your Controller deployment
  1. Open Chrome and click on the bookmark Arcadia Finance

  2. Click on Login

  3. Login as matt / ilovef5

  4. You should see the main app wihtout App2 nor App3

Warning

Congratulations, you have deployed your first modern app with NGINX+ and the NGINX Controller

DevOps deploy Money Transfer application

In this module, we will deploy the Money Tranfer container for Arcadia Bank application and we will publish it.

Note

At the end of this module, Arcadia Bank application will look like this.

_images/app22.png

Note

In this lab, we will automate some tasks in the controller. As you noticed in the previous lab, it is long to create and you can make mistakes. We will deploy a new component using the NGINX Controller API.


Step 1 - Deploy Arcadia App2 with a CI/CD pipeline like a DevOps
  1. In Gitlab, click on Administrator / Arcadia-App2

    1. Click on file deploy

    2. Click edit and make a modification - like YES !!!!!

    3. Click Commit changes

    Note

    At this moment, you simulate a commit like a DevOps. This commit will trigger a webhook to Jenkins, so that Jenkins execute a pipeline.

  2. In Jenkins, click on DeployApp2 pipeline

  3. A pipeline is running, click on it

  4. You can follow the steps

_images/pipeline.png

Note

At this stage, App2 (Money Transfer app) is deployed un K8S. But you need to publish it via the controller.

Step 2 - Publish Money Transfer App with NGINX+ and Controller
  1. In the Jumphost open Postman

  2. Open collection Deploy Component App2

    1. Send the first call Log in NGINX Controller

    2. Send the second call Create App2 Component

    Note

    With one click, you created the component. Fast and no human mistake.

  3. Connect to Controller GUI and check the new component in web application arcadia

    _images/components.png

    Note

    You can notice the new Money Transfer component is created

  4. In Chrome refresh the page. You can see the new App Money Transfer

  5. Transfer some money to your friends in order to populate analytics

_images/app22.png

DevOps deploy Refer Friends Application

In this module, we will deploy the Refer Friends container for Arcadia Bank web application and we will publish it.

Note

At the end of this module, Arcadia Bank application will look like this.

_images/app32.png

Note

In this lab, all tasks will be automated. DevOps will deploy the app in K8S, and NetOps will create the new component at the same time.


Step 1 - Deploy Arcadia App3 and the new componenent with a CI/CD pipeline
  1. In Gitlab, click on Administrator / Arcadia-App3

    1. Click on file deploy

    2. Click edit and make a modification - like YES !!!!!

    3. Click Commit changes

    Note

    At this moment, you simulate a commit like a DevOps. This commit will trigger a webhook to Jenkins, so that Jenkins execute a pipeline.

  2. In Jenkins, click on DeployApp3 pipeline

  3. A pipeline is running, click on it

  4. You can follow the steps

    _images/pipeline1.png
  5. Connect to Controller GUI and check the new component in web application arcadia

    _images/components1.png
  6. In Chrome refresh the page. You can see the new App Refer friends

_images/app32.png

Note

Congrats, as you can notice, with one commit in Gitlab, you triggered a webhook that deployed the app and the infrastructure

Warning

Now, it’s time to protect Arcadia Finance web application with a BIG-IP.

Protect Arcadia Application with Declarative WAF

Warning

ONLY IF YOU START THE LAB FROM HERE - ELSE DON’T READ THIS WARNING. If you want to start from here (because you are only interested by Declarative WAF), and do not want to run all the steps before, you can use Postman and Jenkins to create everything for you. To do so, follow the steps below.

  1. Open Jenkins and run the pipeline DeployMainApp

  2. Open Postman, and select the collection Arcadia Manual Pipeline - no CICD

  3. Run the calls

    1. Login to NGINX Controller

    2. Create WebApp Application

    3. Create MainApp Component

    4. Create BackEnd Component

  4. Open Jenkins and run the pipeline DeployApp2

  5. Open Postman, and select the collection Arcadia Manual Pipeline - no CICD

  6. Run the call

    1. Create App2 Component

  7. Open Jenkins and run the pipeline DeployApp3

Now, Arcadia App is fully deployed and the NGINX Controller is set up.

In this module, we will deploy a WAF policy to protect Arcadia Bank application and we will publish it. With v16.0 (and in draft in v15.1), the WAF policy can be deployed via a declarative call, and the WAF policy itself is a JSON file.

Note

We use the new v15.1/v16.0 Declarative WAF policy. You can retrieve the JSON Policy in the GitLab repo and below.

{
    "policy": {
        "name": "policy-fund-1",
        "description": "Policy Example - Rapid Deployment",
        "template": {
            "name": "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
        },
        "enforcementMode": "blocking",
        "server-technologies": [
            {
                "serverTechnologyName": "MySQL"
            },
            {
                "serverTechnologyName": "Unix/Linux"
            },
            {
                "serverTechnologyName": "MongoDB"
            }
        ],
        "signature-settings": {
            "signatureStaging": false
        },
        "policy-builder": {
            "learnOnlyFromNonBotTraffic": false
        },
        "response-pages": [
            {
                "responsePageType": "ajax",
                "ajaxEnabled": true,
                "ajaxPopupMessage": "My customized popup message! Your support ID is: <%TS.request.ID()%>"
            }
            ]
    }
}

Note

You can notice this JSON policy is based in Rapid Deployment template and we added few things like Server-Technologies, Signature Staging, Policy Buidler and Response Page.


Step 1 - Send an attack
  1. In Chrome, in Arcadia web application, refer a friend

  2. Send an attack with the below payload in the refer friend field

    {\"$ne\":\"michael@gmail.com\"}
    

    Note

    This attacks means return everything not equals to michael@gmail.com

  3. Attack succeed and you can get the DB content

    _images/attack.png
Step 2 - Push AS3 declaration to deploy the WAF policy

Note

It is important to understand what we are doing here. We are leveraging all the new v16.0 Adv. WAF Declarative policy features. With one API call (done by Jenkins and Ansible), we will deploy a new AS3 declaration with a WAF policy.

Check the files used here
  1. In Gitlab, open Administrator / as3-waf project

  2. You can see several files, but the most important are

    1. playbook-v16.yaml

    2. as3-v16.json

    3. policy-fund-1.json

  3. Open policy-fund-1.json

    {
        "policy": {
            "name": "policy-fund-1",
            "description": "Policy Example - Rapid Deployment",
            "template": {
                "name": "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
            },
            "enforcementMode": "blocking",
            "server-technologies": [
                {
                    "serverTechnologyName": "MySQL"
                },
                {
                    "serverTechnologyName": "Unix/Linux"
                },
                {
                    "serverTechnologyName": "MongoDB"
                }
            ],
            "signature-settings": {
                "signatureStaging": false
            },
            "policy-builder": {
                "learnOnlyFromNonBotTraffic": false
            },
            "response-pages": [
                {
                    "responsePageType": "ajax",
                    "ajaxEnabled": true,
                    "ajaxPopupMessage": "My customized popup message! Your support ID is: <%TS.request.ID()%>"
                }
                ]
        }
    }
    

    Note

    This is our declarative JSON WAF policy

  4. Open as3-v16.json

    {
        "class": "AS3",
        "action": "deploy",
        "persist": true,
        "declaration": {
            "class": "ADC",
            "schemaVersion": "3.2.0",
            "id": "Prod_Web_AS3",
            "Web-Prod": {
                "class": "Tenant",
                "defaultRouteDomain": 0,
                "arcadia": {
                    "class": "Application",
                    "template": "generic",
                    "VS_WebApp": {
                        "class": "Service_HTTPS",
                        "remark": "Accepts HTTPS/TLS connections on port 443",
                        "virtualAddresses": ["10.1.10.26"],
                        "redirect80": false,
                        "pool": "pool_NGINX_WebApp",
                        "policyWAF": {
                            "use": "Arcadia_WAF_policy"
                        },
                        "securityLogProfiles": [{
                            "bigip": "/Common/Log all requests"
                        }],
                        "profileTCP": {
                            "egress": "wan",
                            "ingress": { "use": "TCP_Profile" } },
                        "profileHTTP": { "use": "custom_http_profile" },
                        "serverTLS": { "bigip": "/Common/arcadia_client_ssl" }
                    },
                    "Arcadia_WAF_policy": {
                        "class": "WAF_Policy",
                        "url": "http://10.1.20.4/root/as3-waf/-/raw/master/policy-fund-1.json",
                        "ignoreChanges": true
                    },
                    "pool_NGINX_WebApp": {
                        "class": "Pool",
                        "monitors": ["http"],
                        "members": [{
                            "servicePort": 8080,
                            "serverAddresses": ["10.1.20.10"]
                        }]
                    },
                    "custom_http_profile": {
                        "class": "HTTP_Profile",
                        "xForwardedFor": true
                    },
                    "TCP_Profile": {
                        "class": "TCP_Profile",
                        "idleTimeout": 60 }
                }
            }
        }
    }
    

    Note

    In this AS3 declaration, you can notice the new v16.0 Adv. WAF Reference section (Arcadia_WAF_policy). This section refers to our external JSON policy file, and will upload, import and apply the policy in the BIG-IP.

  5. Open playbook-v16.yaml`

    ---
    
    - hosts: bigip
    connection: local
    gather_facts: false
    vars:
        my_admin: "admin"
        my_password: "admin"
        bigip: "10.1.1.12"
    
    tasks:
    - name: Deploy AS3 WebApp
        uri:
        url: "https://{{ bigip }}/mgmt/shared/appsvcs/declare"
        method: POST
        headers:
            "Content-Type": "application/json"
            "Authorization": "Basic YWRtaW46YWRtaW4="
        body: "{{ lookup('file','as3-v16.json') }}"
        body_format: json
        validate_certs: no
        status_code: 200
    

    Note

    You can see the playbook is very simple in v16.0 thanks to the AS3 call. It will do all the job for us. This playbook is just sending an AS3 declaration call to the BIGIP.


Run the CI/CD pipeline
  1. In Jenkins, click on DeployWAF pipeline

  2. Run the pipeline

  3. In Chrome, launch an incognito window, and retry the attack

    {\"$ne\":\"michael@gmail.com\"}
    
  4. Attack fails and you can notice the AJAX blocking page set in the JSON declarative WAF policy

    _images/ajax.png
  5. Check logs in the BIG-IP

    _images/logs.png


Class 3 - Publish and Protect Arcadia API

In this section, we will publish and protect Arcadia API. There are 4 API allowing us to :

  • See last transactions

  • Buy stocks

  • Sell stocks

  • Make a money transfer

The API specification is available here : https://app.swaggerhub.com/apis/F5EMEASSA/Arcadia-OAS3/2.0.1-schema

_images/swagger.png

Module 1 - Publish API with OAS3 spec file from the Controller GUI

Note

In this section we will push OAS3 specification file into the controller GUI in order to create the API

Connect to Controller GUI via your laptop’s browser or the jumphost

login: admin@nginx-udf.internal

password: admin123!

Step 1 - Create an New Application
  1. Click on top left corner icon, and click on Apps

  2. Click Create

  3. Create a new Application

    1. name : app_api

    2. display name : API Application Arcadia

    3. Environment : Production Environment

  4. Click Summit

_images/apps.png

Step 2 - Create an API Definition
  1. Click on the left menu APIs

  2. Click Create API Definition

    1. Name : arcadia-api-def

    2. Display Name : Arcadia API Definition

    3. Version : v1

    4. Select OpenAPI specification

      1. and Copy and paste specification text if you are not connected in the jumphost from here : https://app.swaggerhub.com/apis/F5EMEASSA/Arcadia-OAS3/2.0.1-schema

      2. or Import file if your are connected in the jumphost, the file is located in the Desktop folder and its name is OAS3-Arcadia.yaml

      _images/oas_paste.png
    5. Click Next

    6. You can see all the resources have been imported from the swagger file and please open one resource to check its content.

      _images/resource_list.png _images/resource_money_transfer.png
    7. Click Summit


Step 3 - Publish the API

Note

At this stage, the API definition is created. So the controller knows the differents URI but doesn’t know yet where to forward the traffic to.

  1. Click on the API definition raw, and on the right frame, click on + Add Published API

    _images/add_published_api.png
  2. Configure the mandatory settings

    1. Name: prod-api

    2. Display Name: Production API

      _images/published-api-1.png
  3. Click Next

  4. Configure the deployment

    1. Environment: Production Environment

    2. App: API Application Arcadia

    3. Gateways: Gateway API

      _images/published-api-2.png
  5. It is time to configure the Routing. It is similar to the components in the WebApp configuration

  6. Create a new component, routing the traffic to the MainApp

    1. Click Add New in the Components section and configure it as below

      _images/component_1.png _images/component_2.png

      Note

      Click Done then click Next

      Note

      We only configure one workload as the API we will test is hosted in the main app K8S service (sell stocks and buy stocks)

    2. Click Next until the end and click Submit

  7. Now, drag and drop the 3 URI starting by /trading to the right Component MainApp

    _images/routing.png
  8. Click Next and Submit

    _images/api-definition.png

Step 4 - Test your API

RDP to the jumphost

login: user

password: user

  1. Open Postman

  2. Open up the collection Arcadia API

  3. Make 2 calls

    1. Last transactions

    2. POST Buy Stocks

  4. Both works and are routed to the MainApp pod in K8S thanks to the NIGNX+ API GW.

  5. You can check in the Web Application in Chrome if your Buy Stock call passed. It should appear in the last transaction GUI.

_images/webapp.png

Step 5 - Look at the analytics
  1. In the controler GUI

  2. Click on the left icon Apps

  3. Click on your API Application Arcadia

  4. You can see your analytics for this API

_images/analytics.png

Module 2 - Publish API with OAS3 spec file via API

Note

We will clean up the previous lab in order to configure exactly the same objetcts but with API calls only.

Clean up the APIm configuration
  1. In the controller GUI, go to APIs left menu and click on the existing API definintion arcadia-api-def

  2. On the right panel

    1. Delete the Production API by clicking the trash button

      _images/delete-published.png
    2. Delete the API definition arcadia-api-def

      _images/delete-definition.png

Note

Your API Definitions environment is clean.

Create and publish an API Definition with the Controller API

Note

We will execute exactly the same job but by using the NGINX Controller control plane only. No GUI.

  1. Connect to the Jumphost (user / user)

  2. Launch Postman

    1. Open Arcadia OAS collection

    2. And run all calls from top to bottom

    Note

    For every call, check what is happening in the controller GUI

  3. At then end, you should have the same results as the previous lab.

  4. Edit the Published API

    _images/edit-published.png
  5. Check the Routing. You can see the routes are imported from the OAS3 file and the mapping is done with the components.

    _images/routing1.png
  6. Make a quick test with the Arcadia API postman collection

Warning

Check the call Import API Definition OAS3, we imported an OAS3 YAML File directly in the Controller with all the definitions and documentations

Note

In a near future, we will learn more on API definition versions

Warning

As you can notice, there is no security applied on the Component. Let’s move to the next lab to assign a BIG-IP and Controller security policy

Module 3 - Protect Arcadia API with Adv. Waf and APM (Bearer SSO)

In this lab we will deploy a BIG-IP security policy based on Adv. WAF and APM, in front of the NGINX+ API GW. In order to make life better and simple for DevOps, we will delegate all the Authentication layer to APM. APM will authenticate JWT tokens coming from different providers with different keys, and we will use APM Bearer SSO in order to share a unique JWT key with the API gateways.

Note

APM will download keys from external providers automatically (by using OIDC discovery process) and will use another an unique key for internal SSO with NGINX API Gateways. This will allow DevOps to know only one key for all their deployments. And SecOps will manage the external providers.

_images/archi.png

Configure NGINX Controller with a new Identity Provider
  1. In the left menu, click on Identity Provider icon

  2. Create a new Identity Provider as below. Use the JSON code below for the JWK

    {
    "keys": [
          {
          "k": "aWxvdmVuZ2lueA",
          "kid": "9876543210",
          "kty": "oct"
          }
       ]
    }
    

    Note

    I invite you to decode the “k” value to know what is the key. As you can notice, we don’t use a RSA key, but a secret (just to simplify the lab). This secret is BASE64 encoded.

    _images/identity-provider.png
  3. Assign this Identity Provider with your API Definition

    1. Get back to your API definition and edit the Published API

      _images/edit-published1.png
    2. Click on routing and edit the Security Settings

      _images/edit-security.png
    3. Click on Add Authentication

      _images/add-auth.png
    4. Select the provider created previouly JWT Bearer SSO and Bearer

      _images/auth.png
    5. Click Done and Submit

    6. Click Submit again

  4. Make a quick test with Postman by sending a request to the Arcadia API like Last Transactions or Buy stocks

    1. You can see a 401 Unauthorized

      _images/401.png

Note

As you don’t insert any JWT token in your request, the API GW rejected the request. It is time to configure APM to inject this JWT Bearer SSO

Configure Adv. WAF and APM

Note

In this lab we will use Access Guided Configuration and we will do some custom tuning in the policies. There are several ways to protect API with BIG-IP, but at the moment, we will focus on AGC so that you can understand how it works. GSA team is working on a dedicated UDF Blueprint for API Declarative WAF policy with v16.0

  1. Connect to the Jumhost (user / user)

  2. Open Chrome and connect to the BIG-IP (admin / admin)

  3. Delete the existing vs-arcadia-api Virtual Server in the BIG-IP. We are going to create a new one from the Guided Configuration.

  4. Create a JWK Bearer SSO key. If you remember below, the key (encoded64) was aWxvdmVuZ2lueA, and decoded64 ilovenginx

    1. Click Access > Federation > JSON Web Token > Key Configuration

    2. Create a new key as below with the value ilovenginx as Shared Secret

      _images/bearer-key.png

    Warning

    Don’t forget to set an ID. It is mandatory in order to use this key in the Bearer SSO profile

  5. In Access, click on Guided Configuration and select the template API Protection Proxy in API Protection group

    _images/AGC-1.png
  6. Configure the template as below.

    Warning

    The AGC template does not support yet OpenAPI spec file Version 3. But only Version 2. We will use another version of the OAS file.

    Note

    The OAS file is located in Downloads directory and its name is swaggerArcadia2.json

    1. Check the boxes Use Rate Limiting and OAuth 2.0

      _images/AGC-2.png
      • Select the default Servrer at the bottom of the screen

      _images/AGC-3.png

      Note

      You can notice the URI and the back server have been imported from the OAS2 file

      _images/AGC-4.png _images/AGC-5.png
    2. Select AzureAD AAD-F5Sales as provider

      Warning

      Due to a bug in AGC, we can’t add more providers here. We will modify the list later on directly in the APM configuraiton (ID 835509)

      _images/AGC-6.png
    3. Configure Signle Sign-On Settings as below

      _images/AGC-7.png

      Note

      We will focus on Claims later on

    4. Configure Rate Limiting as below. We will limit request per user based on their Email address extracted from the JWT token. The value used for the User ID Key is subsession.oauth.scope.last.jwt.Email

      _images/AGC-8.png

    1. Configure the Virtual Server as below

      • VS : 10.1.10.18

      • Log All Requests

      • Client SSL arcadia_client_ssl

        _images/AGC-9.png
    2. Click Deploy

  7. Now we have to add manually the 2 more providers in the APM configuration (due to the BUGID in AGC 6.0)

    1. Unstrict the configuration in AGC, by clicking on the lock icon and approve the change.

      _images/unstrictness.png
    2. Click Access > Federation > JSON Web Token > Provider List and edit the existing profile

    3. Add provider1 and provider2 into the list

      _images/provider-list.png

Note

Congratulation, Arcadia API is protected by an Advanced WAF (you can check the policy) and APM in order to authenticate requests from 3 providers.

Note

I invite you to check the Access > API Protection configuration

Warning

In order to use Oauth with Azure AD, you have to force an update of the Azure JWT keys. In Federation > Oauth Client / Resource Server > Provider, click on Start button to force APM to download the new keys.

_images/refresh_keys.png

Test your protected API with Authentication, WAF and Rate Limiting
  1. Open Postman and select the Arcadia API collection

  2. Select one call, the one you want.

  3. F5ers only - For F5 partners and customers, please jump to the next bullet point. In authentication select Oauth 2.0. We will start with an Azure AD provider - similating a partner having an AAD subcription and wanting to use it.

    1. Click Get New Token

    2. I have already set the values for the Oauth Client. As a reminder, here, Postman is the Oauth Agent - it is requesting the Access Token

      _images/oauth2.png
    3. Authenticate with your Corporate F5 account. If it fails, it means you are not part of the F5 Sales Azure tenant (Open an IT Ticket)

    4. When done, click Use token and send your request.

    Note

    It passes. Token is approved by APM, and a new token is generated by APM and sent to the NGINX API GW (Bearer SSO)

  4. Available for F5ers, partners and customers. Now, try with the 2 other providers (partner1 and partner2)

    1. You can find the tokens on the desktop in the file JWT tokens.txt

    2. Don’t use Oauth 2.0, as we already have the tokens. But use Bearer Token instead. I generated these tokens from the website http://jwtbuilder.jamiekurtz.com/

    Partner 1:
    
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwYXJ0bmVyMSIsImlhdCI6MTU5MzQ1NTk4NSwiZXhwIjoxNjg4MDYzOTg1LCJhdWQiOiJhcGkuYXJjYWRpYS1maW5hbmNlLmlvIiwic3ViIjoiYXBpLmFyY2FkaWEtZmluYW5jZS5pbyIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjoiTWFuYWdlciJ9.JRboDfKWvSLVU3md6OULGifoVxJ-ryx7y-0DKrOlPOM
    
    Partner 2:
    
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwYXJ0bmVyMiIsImlhdCI6MTU5MzQ1NTk4NSwiZXhwIjoxNjg4MDYzOTg1LCJhdWQiOiJhcGkuYXJjYWRpYS1maW5hbmNlLmlvIiwic3ViIjoiYXBpLmFyY2FkaWEtZmluYW5jZS5pbyIsIkdpdmVuTmFtZSI6IkJvYiIsIlN1cm5hbWUiOiJUaGUgU3BvbmdlIiwiRW1haWwiOiJib2JAc3BvbmdlLmNvbSIsIlJvbGUiOiJDb250cmFjdG9yIn0.aqTxd6X4z7EFijJsyiuq8mZAKMLG519Bmjz1ra24L-s
    
  5. Test the Rate Limiting by sending 4 calls with the same token. The 4th will be block. You can notice the reponse code 429 Too Many Requests

    _images/ratelimit.png
  6. Send an attack

    1. Select the call POST Buy Stocks XSS attack

    2. Send the request and notice the 200 OK response. It means the WAF didn’t block the request

    3. Check why and change your policy accordingly.

Note

Tip : attack signatures are in Staging mode

Module 4 - Fine grained access with NGINX Controller APIm module

In this lab, we will allow access to the Arcadia API, only for Manager Role. To do so, we will first check the JWT token claims and understand how to forward a claim from a provider into the Bearer SSO.

Step 1 - Understand the JWT token claims

In the previous lab, we used 2 tokens:

Partner 1:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwYXJ0bmVyMSIsImlhdCI6MTU5MzQ1NTk4NSwiZXhwIjoxNjg4MDYzOTg1LCJhdWQiOiJhcGkuYXJjYWRpYS1maW5hbmNlLmlvIiwic3ViIjoiYXBpLmFyY2FkaWEtZmluYW5jZS5pbyIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjoiTWFuYWdlciJ9.JRboDfKWvSLVU3md6OULGifoVxJ-ryx7y-0DKrOlPOM
Partner 2:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwYXJ0bmVyMiIsImlhdCI6MTU5MzQ1NTk4NSwiZXhwIjoxNjg4MDYzOTg1LCJhdWQiOiJhcGkuYXJjYWRpYS1maW5hbmNlLmlvIiwic3ViIjoiYXBpLmFyY2FkaWEtZmluYW5jZS5pbyIsIkdpdmVuTmFtZSI6IkJvYiIsIlN1cm5hbWUiOiJUaGUgU3BvbmdlIiwiRW1haWwiOiJib2JAc3BvbmdlLmNvbSIsIlJvbGUiOiJDb250cmFjdG9yIn0.aqTxd6X4z7EFijJsyiuq8mZAKMLG519Bmjz1ra24L-s
  1. Navigate to https://jwt.io/ and paste Partner1 JWT token into the website. And check the claim Role. Partner 1 is a manager.

    _images/jwt-partner1.png
  2. Do the same with Partner2 JWT token. Partner 2 is a contractor

    _images/jwt-partner2.png
Step 2 - Create a new Claim in APM in order to forward this claim into the Bearer SSO

Note

The providers will inject a Claim into the JWT. This claim is Role. We need to re-inject this claim into the Bearer SSO token so that NGINX GW only accept requests from users belonging to Manager Role.

  1. In the BIG-IP > Federation > Oauth Authorization Server > Claim

  2. Click Create

  3. Create this Claim

    1. Name Claim_Role

    2. Claim Type String

    3. Claim Name Role

    4. Claim Value %{subsession.oauth.scope.last.jwt.Role}

  4. Click Save

Step 3 - Modify the Bearer SSO in order to inject this new Claim

Note

Now, it is time to tell to the Bearer SSO profile to inject this claim in the JWT SSO token

  1. In Single Sign-on > Oauth Bearer > arcadia-api-sso

  2. Add the previous created Claim into the Selected list

  3. Click Update

_images/claim.png
Step 4 - Update the authorization component setting in the controller

Note

Now, the BIG-IP APM is injecting the Claim in the JWT Bearer SSO token. It is time to tell to the NGINX GW, to only grant access if the Role contains Manager

  1. In the controller GUI

  2. In APIs > arcadia-api-def, edit the published API prod-api

    _images/edit-def.png
  3. Edit Authentication

    _images/edit-auth.png
  4. Click on Enable Conditional Access

  5. And enter the values below. This will allow access only if the Claim contains Manager. Select 401 as Failure Reposonse as 403 is not allowed as reponse type by Adv. Waf (by default)

    _images/conditional.png
  6. Click Submit and Submit

Step 5 - Make a test
  1. In Postman, send a request with Partner1 JWT token. As a reminder, he is Manager. Request passes.

    Partner 1:
    
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwYXJ0bmVyMSIsImlhdCI6MTU5MzQ1NTk4NSwiZXhwIjoxNjg4MDYzOTg1LCJhdWQiOiJhcGkuYXJjYWRpYS1maW5hbmNlLmlvIiwic3ViIjoiYXBpLmFyY2FkaWEtZmluYW5jZS5pbyIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjoiTWFuYWdlciJ9.JRboDfKWvSLVU3md6OULGifoVxJ-ryx7y-0DKrOlPOM
    
  2. Then, send the same request with Partner2 JWT token. As a reminder, he is Contractor. Request fails.

    Partner 2:
    
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwYXJ0bmVyMiIsImlhdCI6MTU5MzQ1NTk4NSwiZXhwIjoxNjg4MDYzOTg1LCJhdWQiOiJhcGkuYXJjYWRpYS1maW5hbmNlLmlvIiwic3ViIjoiYXBpLmFyY2FkaWEtZmluYW5jZS5pbyIsIkdpdmVuTmFtZSI6IkJvYiIsIlN1cm5hbWUiOiJUaGUgU3BvbmdlIiwiRW1haWwiOiJib2JAc3BvbmdlLmNvbSIsIlJvbGUiOiJDb250cmFjdG9yIn0.aqTxd6X4z7EFijJsyiuq8mZAKMLG519Bmjz1ra24L-s
    

Note

As you can notice, APM is collecting the different claims and only forward the relevant claims to the internal API GW. Then, API GWs grant access based on the claim values.

Module 5 - Developer Portal

Note

If you remember, we deployed 3 instances. One for the WebApp, one for the APIs and another one for the DevPortal. We will use the latest in this lab.

When we uploaded the OAS3 file, this file included the API documentation as well. There is only one step to publish the documentation into the DevPortal instance.

Step 1 - Create a Dev Portal object
  1. In APIs, then Dev Portals create a new Dev Portal object

    _images/create.png
  2. Configure the object as below
    1. Name: devportal

    2. Display Name: Dev Portal Arcadia

    3. Environment: Production Environment

    4. Gateway: Gateway Dev Portal

    5. Published API: prod-api

      _images/config.png
    6. Click Next

  3. Give a Brand name like API for Arcadia Application, and upload any logo if you want

  4. Click Next and Submit

Step 2 - Navigate to the Developer Portal
  1. RDP to Jumphost as user/user

  2. Open Chrome and click on bookmark Dev Portal APIm
    1. Click on Explore API and Get Started

      _images/devportal.png

Note

Navigate in the Developer Portal. As you can notice, this has been populated automatically thanks to the OAS file. As a reminder, the OAS file looks like that (this is an extract for the buy stock API).

/trading/rest/buy_stocks.php:
  post:
    summary: Add stocks to your portfolio
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/buy'
          example:
            trans_value: '312'
            qty: '16'
            company: MSFT
            action: buy
            stock_price: '198'
    responses:
      '200':
        description: 200 response
        content:
          application/json:
            example:
              status: success
              name: Microsoft
              qty: '16'
              amount: '312'
              transid: '855415223'