CloudFront Signed URLs | AWS + .NET Core | Part 3

Fardeen Khan
Code Panthers
7 min readApr 15, 2022

--

This is Part 3 of a series. All the links are below

In this article, we are going to modify the logic for generating Presigned URLs for private S3 objects with CloudFront Signed URLs.

TL;DR
Instead of creating Presigned S3 URLs to access files uploaded to S3 we will use CloudFront signed URLs.

Why CloudFront

CloudFront is an Edge service (CDN), delivering content from AWS’s Points of Presence (Edge Locations) which are much closer to the consumer Internet when compared to AWS Datacenters. Hence CloudFront boasts blazing fast content delivery and caching mechanism which makes it very suitable for delivering short-lived content.

Also, CloudFront traffic is very priced pretty cheap and 1M invocations are free for each month perpetually. It also offers a finer control on the distribution of content across the world based on geolocation, IP whitelisting, great security measures, etc. It is a package full of stuff that helps Content-based applications.

Prerequisites

Assuming you have followed the previous tutorials in the series, there isn't much required other than the GitHub project we have built so far. If you are missing out on the link, here’s it down below

Terms

CloudFront Distribution

They are used to define the

  • Resource origin (something like an S3 bucket, Load Balancers, Media store/package container)
  • Security and Access configuration — who can access the resource from where
  • Caching and expiration policies
  • Restrictions — Geographic or policy-based

There are many more configuration options. I hope you get the idea about how Distributions can shape how your CDN delivers content and how it is accessed.

Origin Access Identity (OAI)

This is an S3-specific feature in CloudFront. Usually, we deliver private S3 content over the internet. That means that by default the S3 bucket is off access to CloudFront and we need to provide special privileges for CF to access S3. This is where OAI comes into the picture.

An OAI is more like a User role which we associate with a Distribution. Next, we update the S3 bucket policy to allow this OAI to access its content.

Through this, we ensure that we don't offer direct access to our S3 files, instead of access is delegated to the requestor through the authenticated OAI

SSL Certification for Custom Domain

If you want to have your custom domain used in the Distribution endpoint rather than the random one AWS provides then you need to create an ACM certificate for the domain/subdomain and add it to the Distribution. This will allow HTTPS traffic without any hookup and you would be able to add your customized CloudFront URL

Note that this step is completely optional

Setup CloudFront Distribution

Head over to the AWS Console > CloudFront homepage and select the option to Create a Distribution. Setup the following configuration

  • Origin — Select your S3 bucket
  • Name — Set a user-friendly name for the Distribution (s3-upload-service)
  • S3 bucket access —
    Yes > Create a new OAI
    Set a name (s3-upload-service-oai.ap-south-1.amazonaws.com)
    Yes Update the bucket policy (AWS auto adds Bucket read permission for the OAI)
    Note that the OAI access policy will not change existing policy actions. If you wish to remove all other existing statements in your S3 bucket policy you will have to manually do so.

You can skip all the remaining steps and create the distribution.

Follow the below step to enable a custom domain for the CloudFront network.

Custom Domain Setup

Acquire an ACM Certificate

Ignore this step if you are not into adding your domain to CloudFront URLs

Head over to the ACM console and make sure to select N. Virginia (us-east-1) as your region as CloudFront looks for certificates only in that region.

Request a public certificate

In the next Screen

  • Enter the fully qualified Domain name you have access to
  • Select validation method — By DNS/Email

For Domain validation you will have to add a CNAME record generated by the certificate. If you already have the domain as a Hosted Zone in Route 53, select the option for Create records in Route 53

Once validated you can continue to the next step in setting up the Distribution.

Distribution settings

In the Settings Section

  • Alternate domain name (CNAME) section — Add your Domain name as per the ACM certificate
  • Custom SSL Certificate — Select the ACM certificate just created
  • Disable IPv6, if you don't need it (will have to add two CNAME records otherwise)

Wait for a couple of minutes until the Distribution has the status of Enabled/Deployed

Route 53 changes

I will only be covering CNAME changes for domains registered in Route 53. For other domain registrars, have a look at this article

Head over to the Route 53 Console and select your Hosted zone.

Add a new A record and use Alias instead of Value. Point the alias to the Distribution name as shown below

I have left the Record name blank as I would be using the root DNS address.

Now you should be able to access the S3 resources over your custom domain.

Generating CloudFront KeyPair

CloudFront requires a KeyPair (public and private key) to sign and verify the incoming requests. This is required for our use case as we will be using Signed URLs.

To create a CloudFront KeyPair we have two methods

  • Generate one using the Root account’s Security Credential menu, which is totally not recommended
  • Create a Trusted KeyGroup manually which is signed and trusted

We will follow the second approach as it is recommended by AWS and a much more secure option. To better understand the differences refer to the following article

If you are on Windows, then follow the below article to setup OpenSSL on your machine

Steps

  • Generate the Private Key
openssl genrsa -out private_key.pem 2048
  • Generate the Public Key
openssl rsa -pubout -in private_key.pem -out public_key.pem

Note: In case there is some error when using the public key generated through this method such as an Invalid RSA Key, then try generating keys through any other popular method such as the mentioned below

  • Head over to CloudFront Console > Key Management > Public Keys
  • Create a new Key with an Id and paste the content of the public_key.pem file
  • Create a Key Group using the newly created Public Key

Restricting Viewer Access in Distribution

You must have noticed that currently, the CloudFront Distribution we created is giving open access to our private S3 bucket, which is not desirable. Now that we have a Trusted Key Group, we can limit access to these resources to only those requests which are properly Signed by the Private key of our KeyGroup.

To enforce this condition, edit the Distribution > Behavior > Restrict User Access. Set the option to Yes and select the newly created Key Group.

Trying to access any resources through the Distribution without proper signing will give the following error

Finally, with all this, we have properly configured the various services and are now ready to make changes in our project and generate CloudFront Signed URLs through AWS SDK

CODE IT

Dependencies

  • Add Nuget Package AWSSDK.CloudFront (v3.7.4.58)
  • Copy the RSA Private Key PEM file save it to the Project Root
  • Edit appsettings.json to include the following parameters
    CloudFront Domain name
    CloudFront Public Key Id
{
......,
"AWS": {
"Profile": "default",
"Region": "ap-south-1"
},
.....
"CloudFrontDomain": "<DomainName>",
"CloudFrontKeyId": "<PublicKeyId>",
}
  • Edit the Startup.cs file and add the following lines to inject the CloudFront Service in the DI Container
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddAWSService<IAmazonCloudFront>();
.....
}

Generating Signed URL

Add the below logic to generate Signed URLs with a lifespan of 7 days

Conclusion…

So these were the steps you need to follow in order to generate CloudFront Signed URLs for Private S3 resources. In case you wish to have a look at the full code, here’s a link. If you like what you see, then do award a star to the repo.

Thanks!!!!!! See you soon

--

--