Blog

Enforce Geo Fencing on Media Assets

June 2, 2020 · by Javier Garza ·
Categories:

Geo fencing allows you to ensure that media assets can only be accessed in a given country or region. In this blog, I'll walk through how you can set up a simple web app that runs on Heroku. With this app, you can serve a basic page with a specific video asset hosted on NetStorage for any requests starting with /videos. 

In this walk through, we'll restrict the video to only be available in specific countries by adding logic to our Akamai configuration. We'll add some logic to ensure videos are only accessible in Netherlands. So if anyone tries to access videos under /videos/nl/*, they must be located in the Netherlands.

I went ahead and copied the JSON code needed to implement the GEO protection into local files, let’s take a look using the command line utility jq which will help us validate the JSON and colorize the output:

Netherlands GEO Protection

Akamai DevOps [~] >> jq . nl.json
{
   "name": "GEO-protection-NL",
   "children": [],
   "behaviors": [
       {
           "name": "denyAccess",
           "options": {
               "reason": "not-NL",
               "enabled": true
           }
       }
   ],
   "criteria": [
       {
           "name": "path",
           "options": {
               "matchOperator": "MATCHES_ONE_OF",
               "values": [
                   "/videos/nl/*"
               ],
               "matchCaseSensitive": false
           }
       },
       {
           "name": "userLocation",
           "options": {
               "field": "COUNTRY",
               "matchOperator": "IS_NOT_ONE_OF",
               "countryValues": [
                   "NL"
               ],
               "checkIps": "BOTH",
               "useOnlyFirstXForwardedForIp": false
           }
       }
   ],
   "criteriaMustSatisfy": "all"
}

You can also use cURL to test whether or not you can request the video file:

Akamai DevOps [~] >> curl -sD - http://jgarza.sandbox.akamaideveloper.com/videos/nl/mobile-apps.mp4


HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-MD5: 3PLfmHSJpPOMgBE8lyRjsg==
Content-Type: video/mp4
ETag: "dcf2df987489a4f38c80113c972463b2:1589914510.974512"
Last-Modified: Tue, 19 May 2020 18:55:10 GMT
Server: AkamaiNetStorage
Content-Length: 10647839
Expires: Tue, 19 May 2020 22:15:25 GMT
Cache-Control: max-age=0, no-cache, no-store
Pragma: no-cache
Date: Tue, 19 May 2020 22:15:25 GMT
Connection: keep-alive
X-Akamai-Staging: EdgeSuite

As you can see above, the “200 OK” response code shows a successful response. 

Next, you can download the Akamai configuration, merge the new code, upload it, and activate it on the staging network. 

Once you download the configuration, you can use the diagnostics API to confirm that IP addresses in the US can’t access the media asset. There are different ways to retrieve the Akamai configuration, but in this example, we'll use the property CLI for simplicity.

The following command allows you to download version 27 of the Akamai configuration and save it to a file called rules.json.

Akamai DevOps [~] >> akamai property retrieve jgarza.sandbox.akamaideveloper.com --file rules.json --propver 27

... searching propertyName for jgarza.sandbox.akamaideveloper.com
... getting info for prp_432421
Retrieving jgarza.sandbox.akamaideveloper.com v27
... retrieving property (jgarza.sandbox.akamaideveloper.com) v27
Writing jgarza.sandbox.akamaideveloper.com rules to rules.json
Command time: 0.11 mins

The JSON code should look like this:

Akamai DevOps [~] >> jq . rules.json

Now we can use jq to merge the two JSON code snippets into our configuration and save the output in a new file called new-rules.json:

Akamai DevOps [~] >> jq ".rules.children += [`jq -c . nl.json`]" rules.json > new-rules.json

We can also use jq to validate the output:

Akamai DevOps [~] >> jq . new-rules.json

Before we upload and activate the new version, we will use the command line tool called “diff” to compare the current and the new file to ensure the new changes are in and nothing else:

Akamai DevOps [~] >> diff rules.json new-rules.json

Output looks good, let’s commit the new version to Akamai using the property CLI. I am indicating the parameter “update” which creates a new version using the JSON file I am passing as a parameter and also adding change notes indicating the changes we implemented which is a best practice for configuration management:

Akamai DevOps [~] >> akamai property update jgarza.sandbox.akamaideveloper.com --file new-rules.json --notes "adding GEO protection"

Next step is to activate the configuration in staging using the “activate” parameters and indicating the akamai property and the staging network since production is the default

Akamai DevOps [~] >> akamai property activate jgarza.sandbox.akamaideveloper.com --network staging

Activations in staging are pretty fast and usually well under 5 minutes, While we wait for the activation to complete we are going to see how we can leverage the Diagnostics API to make requests from almost anywhere in the world which is pretty useful for testing things like GEO fencing.

Let’s go to developer.akamai.com/api and search for “Diagnostics”. This API is great for debugging, let’s search for “locations” to find the API endpoint that allows us to list all the different locations where we can run API calls.

Here it is, the endpoint is called List Available Ghost Locations. And look like we just need to make a GET request to /diagnostic-tools/v2/ghost-locations/available

I am going to use HTTPie to make the API request, and then use jq to filter the JSON output to print the location IDs of servers in Los Angeles or Amsterdam:

Akamai DevOps [~] >> http --print b -A edgegrid -a default: :/diagnostic-tools/v2/ghost-locations/available | jq --raw-output '.locations[] | select(.value | contains("angeles") or contains("Amsterdam")) | .id'

OK, now that we have the location IDs,we are going to use the Run curl from a Ghost Location endpoint. 

I just need to make a POST request to /diagnostic-tools/v2/ghost-locations/{locationId}/curl-results (replacing locationId with the city where I want to initiate the curl request) and then I need to pass the URL in the post body. 

Let’s take a look at the HTTPie command needed to do request the video that is restricted to Netherlands from a server in Amsterdam:

Akamai DevOps [~] >> http --print b -A edgegrid -a default: POST :/diagnostic-tools/v2/ghost-locations/amsterdam-netherlands/curl-results url="http://jgarza.sandbox.akamaideveloper.com/videos/nl/mobile-apps.mp4"

This API call should take a few seconds, I am basically connecting from California to a physical server in Amsterdam, and that server will request the 10MB video file. As you can see the response shows a 200 status code which means it was able to get the video fine as expected. 

Let’s now run a similar command and see if we are able to to do the same from a server in Los Angeles, that should not be allowed by the GEO fencing code we put in place:

Akamai DevOps [~] >> http --print b -A edgegrid -a default: POST :/diagnostic-tools/v2/ghost-locations/losangeles-ca-unitedstates/curl-results url="http://jgarza.sandbox.akamaideveloper.com/videos/nl/mobile-apps.mp4"

We could do a similar API request to verify the US content can’t be allowed from outside the US.

You Might Also Like:

About the Author

Javier

Javier Garza is a developer evangelist at Akamai Technologies where he helps the largest companies on the internet run fast and secure apps by leveraging web performance, security and DevOps best practices. Javier has written many articles on HTTP/2 and web performance, and is the co-author of the O’Reilly Book “Learning HTTP/2”. In 2018, Javier spoke at more than 20 developer-related events around the world, including well-known conferences like Velocity, AWS Re:Invent, and PerfMatters. His life’s motto is: share what you learn, and learn what you don’t. In his free time he enjoys challenging workouts and volunteering for non-profits in areas like children and education