Protect your web app in under 5 minutes.

Background

Adding protection for your web-facing app shouldn’t require you to be an expert in security or networking. Having no deep expertise in either area made me an ideal candidate to try out F5’s new SaaS offer: F5 Essential App Protect Service

In my last article I used Amazon Lightsail to set up a full WordPress stack with a new domain. While the full app stack approach is incredibly convenient, it’s unlikely to deploy the latest patched version of that app: stacks are typically locked to major app versions, it takes time & effort to test each stack configuration, and frankly it’s up to end-users to ensure their app stays up-to-date. WordPress, just like any other popular app, has vulnerabilities: both core and from its many plug-ins. So, adding an extra level of protection in the form of Essential App Protect is really a no-brainer, as it shields against common attacks like XSS and SQL Injection. 

Below are the “minimal steps” to create and set up a web application firewall (WAF) with my app:

Pre-requisites

  • F5 Cloud Services subscription: I started with an active subscription; if you don’t have one already get your own here
  • Access to update your DNS with a CNAME value: I’m using Amazon Route 53, but we can do the same on any other registrar like GoDaddy. You may need to talk to your IT/NetOps team if you are in a company that manages this kind of stuff for you.
  • Your app IP or Domain: I’m using the AWS-provided IP address for my app, but we could also use a domain name value instead. 
  • API Interaction: I’m using cURL on my Mac, but it’s also native on Windows 10 1803 onwards. Of course, you can use your favorite way to interact with an API, such as Postman, Fiddler, or code. 

Essential App Protect Setup 

Part A: Login and Ready

We’ll use the F5 Cloud Services API to log in and retrieve a few values needed for creating our Essential App Protect subscription. 

1. Log in – use the username / password to authenticate and retrieve the authorization token that we’ll need to use in the header of the subsequent API calls to the F5 portal.

API Request:

curl --location --request POST 'https://api.cloudservices.f5.com/v1/svc-auth/login' --data-raw '{"username": "", "password": "" }"'

API Response (tokens cropped):

We’ll save the token into a file ‘headers.txt’, which we can reference in the header of subsequent calls using cURL’s @filename feature (as of 7.55.0) . Our token needs to be stored in ‘headers.txt’ in a single line (no carriage returns) in this format: Authorization: Bearer <your token>. On a separate line we’ll add another header, such as: Content-Type: application/json. The resulting ‘headers.txt’ file would therefore look like this:

2. Get User Account ID – next let’s retrieve the “ID” value for our account, which is one of the two values needed to subscribe to the Essential App Protect catalog and also to create a service subscription instance for our app. 

API Request:

curl --location --request GET 'https://api.cloudservices.f5.com/v1/svc-account/user' --header @headers.txt

API Response:

3. Get Catalogs – Here we will retrieve the list of all available Catalogs and get the Catalog ID for the Essential App Protect service, which is designated with “service_type”:”waf”. 

API Request:

curl --location --request GET 'https://api.cloudservices.f5.com/v1/svc-catalog/catalogs' --header @headers.txt

API Response:

4. Subscribe to Catalog -- This step can be skipped you have already subscribed to Essential App Protect catalog (in the portal or through API). We will use the account “id and the 

catalog_id” values retrieved earlier.

API Request:

curl --location --request POST 'https://api.cloudservices.f5.com/v1/svc-account/accounts/<your-account-id>/catalogs' --data-raw '{"account_id": "<your-account-id>","catalog_id": "c-aa9N0jgHI4"}' --header @headers.txt

API Response:

At this point we are logged in and subscribed to the Catalog. Next let’s create our service instance.

Part B: Create and Activate Subscription

5. Create Subscription – Here we will use the account “id” and the 

catalog_id” values retrieved earlier, plus a few other values for our app hosted on AWS. In the response we will need to capture the "subscription_id.


 

API Request:

curl --location --request POST 'https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions' --data-raw '{
  "account_id": "<your-account-id>",
  "catalog_id": "c-aa9N0jgHI4",
  "service_instance_name": "<descriptive name>",
  "service_type": "waf",
  "configuration": {
    "waf_service": {
      "application": {
        "domain": "<cool domain>",
        "remark": "<cool remark>",
        "waf_regions": {
          "aws": {
            "us-west-2": {
              "endpoint": {
                "ips": [
                  "<your ip here>"
                ],
                "port": 80,
                "use_TLS": false
              }
            }
          }
        }
      },
      "event_logging": {
        "enabled": true
      },
      "industry": "finance",
      "policy": {
        "compliance_enforcement": {
          "data_guard": {
            "cc": true,
            "enabled": true,
            "ssn": true
          },
          "sensitive_parameters": {
            "enabled": true
          }
        },
        "encoding": "utf-8",
        "high_risk_attack_mitigation": {
          "allowed_methods": {
            "enabled": true,
            "methods": [
              {
                "contains_http_data": true,
                "name": "POST"
              },
              {
                "contains_http_data": false,
                "name": "HEAD"
              },
              {
                "contains_http_data": false,
                "name": "GET"
              }
            ]
          },
          "api_compliance_enforcement": {
            "enabled": true
          },
          "disallowed_file_types": {
            "enabled": true,
            "file_types": [
              "exe",
              "com",
              "bat",
              "dll",
              "back",
              "cfg",
              "dat",
              "cmd",
              "bck",
              "eml",
              "bin",
              "config",
              "ini",
              "old",
              "sav",
              "save",
              "idq",
              "idc",
              "ida",
              "htw",
              "exe1",
              "exe_renamed",
              "hta",
              "htr"
            ]
          },
          "enabled": true,
          "enforcement_mode": "blocking",
          "geolocation_enforcement": {
            "disallowed_country_codes": [],
            "enabled": true
          },
          "http_compliance_enforcement": {
            "enabled": true
          },
          "ip_enforcement": {
            "enabled": true,
            "ips": [
              {
                "action": "block",
                "address": "178.18.62.195",
                "description": "This is anonymous proxy",
                "log": true
              },
              {
                "action": "allow",
                "address": "1.2.3.5",
                "description": "some description",
                "log": false
              }
            ]
          },
          "signature_enforcement": {
            "enabled": true
          },
          "websocket_compliance_enforcement": {
            "enabled": true
          }
        },
        "malicious_ip_enforcement": {
          "enabled": true,
          "enforcement_mode": "blocking",
          "ip_categories": [
            {
              "block": true,
              "log": true,
              "name": "tor_proxies"
            },
            {
              "block": false,
              "log": true,
              "name": "cloud_services"
            }
          ]
        },
        "threat_campaigns": {
          "enabled": true,
          "enforcement_mode": "blocking"
        }
      }
    }
  }
}' --header @headers.txt

API Response (truncated):

 

6. Activate Subscription – Now we are ready to activate the instance using the “subscription_id” captured in the previous step. Note that if the returned “service_state” is “UNDEPLOYED” it just means it’s being activated, re-running the same API call should eventually return “service_state”: “DEPLOYED”. 

API Request:

 

curl --location --request POST 'https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/<your-subscription-id>/activate' --data-raw '{
 "subscription_id": "<your-subscription-id>",
 "omit_config": true
}' --header @headers.txt

API Response:

With this our Essential App Protect service should be live, ready to accept requests, and should look like this in the portal:

CNAME & Domain Update

The only remaining thing is to retrieve the CNAME value of our live Essential App Protect service. This is what we can browse to test our site, and where we will need to send traffic from our domain. Let’s do it:

7. Get CNAME Value – using the same “subscription_id” from the previous step, let’s get the info for our service and retrieve “CNAMEValue”. 

API Request:

 

curl --location --request GET 'https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/<your-subscription-id>' --header @headers.txt

API Response:

8. Browser Check – let’s validate what it looks like in our browser (copy + paste the value of CNAMEValue). We can see our blog, and can even try to do something like adding a disallowed filetype at the end of the URL:

9. Domain records update – finally let’s update the Amazon Route 53 configuration for our site with the new CNAME. We will need to add a record type CNAME and provide CNAMEValue. This will essentially route blog.haxrip.net traffic to Essential App Protect, which in turn will route it to the IP that we specified earlier. 

Conclusion

Adding protection to a website with F5’s Essential App Protect is pretty straightforward and requires just a few API calls. If you’re running a web-facing app and don’t have the time or resources to keep it constantly updated to protect against known vulnerabilities -- it’s a good idea to have an extra protection in place for possible (and likely) attacks. 

Published Jan 15, 2020
Version 1.0

Was this article helpful?

3 Comments

  • How is this different from Silverline WAF? Is there a comparison matrix between Silverline and 'ssential-app-protect-service' ?

  • Hi  Silverline WAF is a managed service, while Essential App Protect is a SaaS. Hope this helps clarify the main difference.

  • Right on,  !

     , let me know if you need additional information on EAP and maybe we can set up a meeting to go through the service.

     

    Thanks,

    Ziv