How to use F5 Distributed Cloud to block (OFAC) Sanctioned Countries

Over the last several days, the climate has changed significantly in Eastern Europe, and I have been getting asked a lot about the possibility of blocking Office of Foreign Assets Control - Sanctioned Countries (OFAC) with F5 Distributed Cloud, and how to do it. The answer is quite simple; yes we can do it and its a pretty simple configuration.  I think its also important to point out that this same process can be used to configure any other required GeoFencing policies as well.

Do we also have ways to block DDOS and provide WAAP services? Also yes, but outside the scope of this article.

In this article, I will focus on how to deploy & create:

  • [Namespace] Service Policies
  • Origin Pool(s) to send traffic to
  • Distributed listener / load balancer with the security policy assigned
  • View Security Events. 

Level Set

Most of this article will be based around ClickOps deployment of this use-case. That said, the F5 Distributed Cloud is an API first platform, so everything can be done with your tools of choice for interaction with declarative APIs.  I will include JSON manifests of the configured items as well to provide examples of what delcarations will resemble, as well as support direct import into the distributed cloud.  

It would be possible to say, set the policy configuration JSON into github as a source of truth, and have webhooks set up to push to the platform any time a change is made to ensure configurations stay within proper alignment.

Who do we block?

Before we can start blocking things, we need to know what exactly to block, so we need to acquire a list of OFAC Sanctioned Countries. There are a couple of options here as well.

For the sake of brevity here, I will focus on just some top level country sanctions based on country code versus IP Subnet, but thats up to preference.

Configuration

Log in to your F5 Distributed Cloud Console. (If you do not have a tenant today, you should reach out to your F5 Account Team immediately and rectify the situation!)

Landing Page Tiles

Service Policies for everyone!

There are a couple of options for service policies in the platform.

  • Shared Policies:  Policies created in the Shared namespace, can be shared globally within your tenant.
    • Benefit:  Globally set policy baseline for all applications in your tenant.
  • Namespace Policies:  Policies created in a Namespace can only be shared within that namespace.
    • Benefit:  Namespace service policies applied by default to all listeners / load balancers.

For this example, we will create the policy in a namespace. From the tiles, select Load Balancers, and then we need to ensure that we are in the proper namespace.  (As with everyting on the platform, there are multiple ways to get places, and multple ways to configure things, so this will only cover 1 example of how.)

Selecting Namespace.

Now we need to expand Security, hover over Service Policies, Click Service Policies, and in the new window click Add service policy.

Creating Service PoliciesService Policy Rules

Populate the Name under metadata, leave attachment as Any Server, and set Select Policy Rules to Denied Sources.  Now, we could use IP blocks, but for this example we will just use the Country List configuration parameter and enter country codes.  This will pull from GeoIP validation.  

Save and Exit.

UPDATE:  I have been getting a lot of notes on this article based on Ukraine versus Crimea, and how to specify since its not seperated out as a country code.  Can we Allow Ukraine and block Crimea?  Absolutely!  

For Crimea, we need to pull from another database, so for this example I am going to pull from https://bgpview.io/search/Crimea and we are going to block by ASN.  So within our service policy, click Add item under BGP ASN Set.  And on this screen we enter in all the ASN's that we discovered from the previous link. BGP ASN List

Then click Apply.  (Making sure to now remove Ukraine from our Block List.)

Then we need to determine Default Action.  This is where you can cause some pain for yourself, so pay special attention when selecting Default action (“Default Action for requests from sources that do not belong to this list”), if you are using Next Policy, ensure the next policy allows traffic, or set the Default action to Allow, or the application will not receive any traffic.  In this example I will only be using one policy, so I will set the Default Action to Allow (as noted in the JSON).  Save and Exit.

UPDATE 2:  OK, you guys are killing me!  Can we go to City Level or target regions outside of ASN?  Yes!  Here is how you do that.  (I should plan better in the future for less edits!)

Just to keep things clean, lets add a new Service Policy.  This time, under Select Policy Rules, we are going to select Custom Rule List from the drop down.

Custom Rule List

Then from here, we want to click Configure under Rules, then Add Item.  Give our new rule a name, and click Configure under Rule Specification.

Rule NameFrom here, we are going to change the dropdown under Clients - Client Selection from Any Client to Group of Clients by Label Selector.  Then under Selector Expression, Add Label.  In the available selections you will find geoip.ves.io/city, country, and region (as well as some really cool IP Intelligence options but those are out of scope for this article.). 

Selector

Lets do a Region first to see how that works. Selct geoip.ves.io/region, then =, then start typing a region, for example Crimea.  Once we have it set, scroll down and click Apply.

Crimea

 Now, lets add another rule, but this time we are going to select city.

City

We are already blocking Russia in our earlier policy, but just for an example lets add = Moscow.   

Moscow

Now scroll down and click Apply.  Thats it!  Now we have policies to block based on GeoIP Country, Region, and City, as well as BGP ASN.  We can apply all of them to our application at the same time.

Now, lets say you just want to cheat, and copy and paste some JSON in, or you want to build it into a pipeline.  You can go and check out the API specifications for Service Policy here:  https://docs.cloud.f5.com/docs/api/service-policy  

The JSON would resemble the following for our first policy:

{
  "metadata": {
    "name": "coleman-ofac-deny",
    "namespace": "m-coleman",
    "labels": {},
    "annotations": {},
    "description": "",
    "disable": false
  },
  "spec": {
    "algo": "FIRST_MATCH",
    "any_server": {},
    "rules": [
      {
        "kind": "service_policy_rule",
        "uid": "c12f8c5d-44c2-495c-83e8-30842e9e0a7f",
        "tenant": "f5-sa-rnxeudss",
        "namespace": "m-coleman",
        "name": "ves-io-service-policy-coleman-ofac-deny-asn-list"
      },
      {
        "kind": "service_policy_rule",
        "uid": "5d24d0d0-6c6b-4c7b-b5b3-4bec67c2ffed",
        "tenant": "f5-sa-rnxeudss",
        "namespace": "m-coleman",
        "name": "ves-io-service-policy-coleman-ofac-deny-country-list"
      },
      {
        "kind": "service_policy_rule",
        "uid": "f9df0b83-21de-4c13-aebf-4e27fc580ed0",
        "tenant": "f5-sa-rnxeudss",
        "namespace": "m-coleman",
        "name": "ves-io-service-policy-coleman-ofac-deny-default-action"
      }
    ],
    "deny_list": {
      "ip_prefix_set": [],
      "asn_list": {
        "as_numbers": [
          204791,
          205515,
          208090,
          28761,
          41269,
          43222,
          43564,
          49617,
          59744,
          8654
        ]
      },
      "asn_set": [],
      "country_list": [
        "COUNTRY_BY",
        "COUNTRY_BA",
        "COUNTRY_BI",
        "COUNTRY_CF",
        "COUNTRY_CU",
        "COUNTRY_IR",
        "COUNTRY_IQ",
        "COUNTRY_KP",
        "COUNTRY_XK",
        "COUNTRY_LY",
        "COUNTRY_MK",
        "COUNTRY_SO",
        "COUNTRY_SD",
        "COUNTRY_SY",
        "COUNTRY_ZW",
        "COUNTRY_CD",
        "COUNTRY_LB",
        "COUNTRY_NI",
        "COUNTRY_RU",
        "COUNTRY_SS",
        "COUNTRY_VE",
        "COUNTRY_YE"
      ],
      "tls_fingerprint_classes": [],
      "tls_fingerprint_values": [],
      "default_action_allow": {}
    },
    "simple_rules": []
  }
}

And our second policy JSON puts us over the limit for the article, but all JSON from these configs are in the attached file.

Origin Pools

Origin Pools are where we send traffic to, so if you are familiar with BIG-IP its just the Pool, and if you are familiar with NGINX its our Upstream.  All of the settings and nerd knobs that are part of origin pools are out of scope of this article, so we are just going to point our origin at a single public IP and move on.

To create an Origin Pool, Expand the Manage Block, hover over Load Balancers, click Origin Pools, and then Add Origin Pool.

Give the Origin Pool a Name under Metadata.  Then under Origin Servers click Add Item so we can add an upstream server.  For this example I am going to use a Public DNS Name of Origin Server, but you should use whichever applies best to your situation.  Click Add Item once done, which will return us to the Origin Pool Config.  Make sure to select the correct port, and any TLS settings for your environment. Click Save and Exit.

Create Origin Pool

Origin Pool Destination

Load Balancer / Listener

Now that we have somewhere to send traffic, we need a way to receive traffic and assign security policies.  We will be staying within scope for this use-case as well and not highlighting all of the details within the load balancer configuration.

To create a Load Balancer, Expand the Manage Block, hover over Load Balancers, click HTTP Load Balancers, and then Add HTTP load balancer.

Set a Name under Metadata.  Under Basic Configuration, Domains, add a domain for the application.  If you have delegated a DNS zone to the platform, we can automate DNS (and make certificate management super easy, but not required).  

HTTP Loadbalancer Configs

Under Default Origin Servers, click Add Item, and in the Origin Pool drop down, select the pool that was created previously, then click Add Item.

Default Origin Pool

For VIP configuration we will leave as Advertise on Internet.  You will notice under Security Configuration, Service Policies are already set to Apply Namespace Service Policies.  Since I have a few policies in my namespace already, and I want to demonstrate OFAC policies, I am going to change this to Apply Specified Service Policies, and under Apply Specified Service Policies click Configure and select the previously created policy, then click Apply. 

Assigning Service Policy

Selecting Created Policy

Save and Exit

From here click Save and Exit.

Testing

Using a VPN we can make sure that our policy is up and running.  Since we did not configure a custom response page of any sort we should just get a 403 - Forbidden page.  While users accessing from non OFAC countries will be able to access the application.

Accessing via VPN in sanctioned Country.Accessing from non-Sanctioned Country.

Reporting

We should be able to access the security events now as well, Expand Virtual Hosts, HTTP Load Balancers, and then over the load balancer we created earlier a hyperlink for Security Monitoring will show up, click it.  We can see in the dashboard a L7 security event, and if we select Security Events, we will see that our VPN based request was flagged (l7_policy_sec_event, Rule to match CountryList). If its not totally legible, I VPN'd to Belarus and tried to access the page.

Security Event Dashboard

Hint:  Being able to use the JSON to copy policies is really great, I have used this in action with several customers to show how quickly we can backup and copy policies between environments in a few seconds.

Thats it, now your web application is blocking traffic from OFAC sanctioned countries, and anyone else you want to keep out.

Updated Mar 03, 2022
Version 4.0

Was this article helpful?