Token authentication with "Azure Verizon Premium CDN"
Last updated
Last updated
This walkthrough demonstrates how to use "Azure CDN Premium from Verizon" in front of a private blob storage container as origin.
In this system, the client's browser should securely access an asset stored in a private container in blob storage, via CDN. Secure in this context means that access to the cached asset in CDN should only be granted to authorized clients, and access from the CDN to the origin should be authenticated as well. The term 'origin' usually refers to the service 'behind' the CDN, in our case an Azure Storage Account.
To implement this, the client signs in 'somehow' to the web application, using whatever is in place (step 1 below). The web application generates a 'CDN auth token', and tells the browser to fetch the asset from CDN (step 2 below). That CDN URL contains the CDN auth token in the URL's query string. The CDN endpoint (strictly speaking the CDN's point of presence (PoP) or edge node) validates the CDN auth token, and (when allowed) either serves the cached copy of the asset, or fetches the contents from the origin (step 3 below).
Config
Storage account name: cdnorigi
Force HTTPS
Enable storage account keys
cdnfiles
Inside the container, create an "Stored access policy"
Policy identifier: cdn
Permissions: [Read]
Start time: Yesterday
Expiry time: Something far in the future
After creating the policy, go the the container's "Shared access tokens" tab
Signing key: Key 1 or Key 2
Stored access policy == cdn
Click "Generate SAS token and URL"
The Blob SAS token looks like this: si=cdn&spr=https&sv=2021-06-08&sr=c&sig=Eod7p4YFtfp2rQX2OWT9ZJbNogCNa3Y%2FoH7O82%2F4UdI%3D
The Blob SAS URL looks like https://cdnorigi.blob.core.windows.net/cdnfiles?si=cdn&spr=https&sv=2021-06-08&sr=c&sig=Eod7p4YFtfp2rQX2OWT9ZJbNogCNa3Y%2FoH7O82%2F4UdI%3D
Upload a sample file to the container
After uploading the file, check that the SAS actually works, by putting the filename into the middle of the SAS URL, such as
https://cdnorigi.blob.core.windows.net/cdnfiles/2021-01-11-Captain-Haddock-02.jpg?si=cdn&spr=https&sv=2021-06-08&sr=c&sig=Eod7p4YFtfp2rQX2OWT9ZJbNogCNa3Y%2FoH7O82%2F4UdI%3D
Select "Explore other offerings" (instead of the default "Azure Front Door")
In "Choose other offerings", pick "Azure CDN Premium from Verizon"
In Profile Details
Name: cdnchgeuer
Region: Global
, Pricing Tier: Premium Verizon
Tick the "Create a new CDN endpoint" box
CDN Endpoint name: cdnchgeuer20230119
which means our public hostname will be https://cdnchgeuer20230119.azureedge.net
, unless we later enable a custom domain name.
Origin type: "Storage"
Origin hostname: Pick your storage account, in my case cdnorigi.blob.core.windows.net
Click Create
, and take a cup of coffee.
What now happens is that Azure in the back calls out to APIs of Edgecast/Verizon to provision a CDN profile for you. That can take a while, because Verizon under the hood will roll out your chosen hostname globally to all the various edge nodes (also called 'points of presence')
Configure the endpoint: Once provisioning is finished, in the resource group you should see the Storage account, the CDN profile, and the CDN endpoint:
In the endpoint's "Origin" settings, you might consider disabling the http
port
All the rest of the fine-grained configuration happens by navigating to "Advanced Features" and clicking the "Manage" link at the top of the page:
You now are authenticated and redirected to cdn.windowsazure.com/http/token/default.aspx
, which is the place where we can configure token authentication:
HTTP Large Object Token-Based Authentication
In the Linux shell (for example in a bash shell in WSL), we'll be using OpenSSL to generate to high-entropy cryptographic keys:
Run openssl rand -hex 160
twice and note down the results. This command generates hexadecimal encoded cryptographically strong random numbers, and the number is the number of bytes. 160 bytes would be 1280 bit, encoded in 320 hex characters.
Prefix the first value with primary
and the second one with backup
, so it's easier to see which key you're looking at.
You can also bump up the "Minimum Encryption Version" from V2
to V3
By clicking on the "HTTP Large" menu on the top, and selecting "Rules Engine V4.0", you come to the graphical rule editing experience.
Click the +New
button, and type in a new name for the draft rule, such as v1
, and click "Continue"
Click the +Rule
button
Rule Description: Require CDN Token
Click the +
dropdown and select Match
The Select Category
dropdown should be URL
The second dropdown should be URL Path Directory Wildcard
The Result
dropdown should be Match
The Value
is the path in the CDN URL, something like /cdnfiles/
.
The Relative To
dropdown should be Origin
Enforce token auth: Next, click the indented +
and select Feature
Select Category
dropdown == Access
Select Feature
dropdown == Token Auth
Enabled
== yes
Name the token parameter:
Add another Feature
, this time Access
and Token Auth Parameter
, and Enabled=yes
Finally, save our first rule.
Click +Rule
to add a second rule, with a rule description of Append SAS Token
or similar
Click the +
button and again select Match
, this time with General
/ Always
On the indented +
button, add a Feature
in the URL
category, with feature being URL Rewrite
Now we need to tell the CDN how incoming URLs should be re-written to the external origin server (Azure Blob storage in our case).
To know the string we need to know, temporarily click the bottom +
button to add another Match
, and select Origin
/ Customer Origin
. In the Value dropdown, you should see something like this:
In the dropdown (marked with a 1
in the screenshot), you can see a customer origin identifier, in our case /801A0567/cdnchgeuer20230119/
. Please type this text into the Source
and Destination
. The cdnchgeuer20230119
part in this string is the name of the endpoint which you configured earlier in the Azure portal.
However, the /801A0567/
looks slightly random. In practice, this is your Verizon customer ID, which you can see in the upper righthand corner of the portal (1A0567
), prefixed with the 80
. So in theory, you could just look at your user account info on screen, but in case that 80
prefix changes in the future, temporarily creating a customer origin rule makes it easy to lookup.
Now please delete the temporarily created match, by clicking the little recycle bin icon (2
).
Our screen should now look like this:
Now that our Source
and Destination
textboxes have the base information, we need to extend it with a mechanism to inject our shared access signature token.
In the Source
textbox, append the name of your container, and the regular expression (.*)\?(.*)
to the content, so it looks like this: /801A0567/cdnchgeuer20230119/cdnfiles/(.*)\?(.*)
The request coming on to the CDN looks something like this: https://cdnchgeuer20230119.azureedge.net/cdnfiles/somefile.zip?cdntoken=xxx
, i.e. the path prefix /cdnfiles/
, a file (somefile.zip
), and the query string containing our CDN token (?cdntoken=xxx
).
The regular expression cracks up the path around the questionmark (\?
), into the file name (somefile.zip
) in the first regex capture group, and the query string (cdntoken=xxx
) in the second regex capture group.
In the Destination
text box, we concatenate the following strings
Our base /801A0567/cdnchgeuer20230119/
Our storage account container name cdnfiles/
Then we put the file name, which is captured in the 1st capture group, by adding $1
The ?
to start the query string again
Our SAS string (si=cdn&spr=https&sv=2021-06-08&sr=c&sig=Eod7p4YFtfp2rQX2OWT9ZJbNogCNa3Y%2FoH7O82%2F4UdI%3D
)
An additional &
for additional parameters
The second capture group $2
So the overall result is /801A0567/cdnchgeuer20230119/cdnfiles/$1?si=cdn&spr=https&sv=2021-06-08&sr=c&sig=Eod7p4YFtfp2rQX2OWT9ZJbNogCNa3Y%2FoH7O82%2F4UdI%3D&$2
Save the second rule, and click "Lock Draft as Policy"
In the Raw XML
window, you can also see an XML representation of the rules
Now, click the "Deploy Request" Button, select the "Production" environment, type in a deployment message (like "Deploying v1"), and "Create Deploy Request"
Once submitted, the Verizon system will validate the rules, after a couple of seconds, you should be seeing an "Approved" mark in the Activity log. Overall, the deployment of the rules to the various edge / PoP nodes might take a few minutes.
Finally, we can create a CDN token, to test our solution. We navigate back to the "HTTP Large / Token Auth" page. Further down on that page is an "Encrypt Tool" section, a small web-based UI to create a CDN token. For a simple test, we need two properties in the token, an expiration date (ec_expire
) and a part of the URL we're granting access to (ec_url_allow
).
The ec_expire
header must be an epoch value, an integer which you can create using web sites such as unixtimestamp.com or epochconverter.com. For example, the timestamp "Wed Dec 31 2025 23:59:59 UTC" corresponds to the epoch value 1767225599
.
The ec_url_ allow
can contain values such as /cdnfiles
.
Encrypting these two parameters under my primary key gives me a generated token of is9St4wZ7gTK8tuPXxKQtcmh7Bi3aMJ8b-yHxvJgyDdcJOyrePUmVIj9HXVFl1WbLWRDiuS-3RaeEgpg-JIsJT9ChNKfqis
In your solution, you (of course) won't visit the Verizon portal to generate a CDN token. You will be using your web application to (protected) generate web links pointing to CDN. So in your web solution, you need to generate these CDN tokens programatically, you certainly want to make these short-lived, limit them to a specific client, and use all the other good features.
On the .NET side, I created a small library Azure-Samples/edgecast-cdn-token-fsharp: A .NET sample to create tokens for Edgecast Azure CDN which can help you generating such tokens. In a C# solution for example, you could generate tokens like this:
With all that information, we can now hit the CDN endpoint and access a file in our private blob storage container.
As a quick reminder, the direct URL to hit our origin server (blob storage) contained the shared access signature:
Instead of the SAS, the CDN URL contains our cdntoken
:
When we hit the CDN without token, or a modified one, we get a 403 - Forbidden
page.
Otherwise, you can enjoy this beautiful image:
In the Name
text box, pick the name under which your web app will convey CDN tokens to the CDN. That could be cdntoken
The Source
and Destination
text boxes have a little resize handle in the bottom right, you might want to make these text boxes larger to see what you're putting here.