IMPORTANT: There is a previous post on this topic where I’ve introduced some interesting concepts about using CloudFront as CDN. I recommend you to read it before reading this one.
Distributing private content using CloudFront
One of the most important differences between CDNs are the way that they allow you to distribute private content. There are several options to distribute private content from a CDN, but depending on the number of private files to distribute is important the way that you can do it.
CloudFront lets you generate temporal signed URLs to allow third parties access private content through these links. CloudFront signatures can be generated using the PHP SDK and the Amazon account credentials without any need of external API calls. If your webpage contains more than one private file to load, usually avoiding external calls can improve your response time. It always depend on the application behavior but adding a latency time more than twice to your response time does not seems a good idea at all.
The easier option when defining the data origin for a CloudFront distribution is to chose an S3 bucket. It lets you to manage your files with your favorite S3 files manager (I have just discovered Dragondisk
, and it is extremely useful for managing your Amazon buckets) without further configurations.
Applying this setup will distribute your static files through the CloudFront locations as long as you defined these files as public. If you define some S3 objects as private, CloudFront daemons won’t be able to read the object content and they won’t be able to replicate it across their distributed sites. At this point you will need to start thinking about OAIs.
OAIs are virtual users that can be allowed to access S3 objects without defining these objects as public (they will be kept as private objects but defined OAIs will be able to access them). Creating OAIs, and granting them read access to S3 files are simple operations but they are (IMHO) not clearly explained in the AWS official documentation.Using the official AWS SDK for PHP, the OAI set up is as easy as:
$cf = new AmazonCloudFront();
$res = $cf->create_oai(‘referer’);
You will need to remember the “referer” value for future operations. It isn’t possible to create two different OAIs with the same referer so, you will need to use different values for different OAIs.
Setting S3 object permissions
Grating OAIs access to S3 objects is another easy task as long as yo know what to do. Although it is a mandatory step to have a private distribution, in my humble opinion, it isn’t enough highlighted in the official documentation (anyway you will find it if you know what you are looking for).Once again, using the official SDK for PHP:
$s3Instance = new AmazonS3();
$custom_acl = array(
array( ‘id’ => ‘oai_canonical_id’, ‘permission’ => AmazonS3::GRANT_READ ),
array( ‘id’ => ‘aws_user_canonical_id’, ‘permission’ => AmazonS3::GRANT_FULL_CONTROL));
$res = $s3Instance->set_object_acl(‘bucket_name’, ‘s3_object_name’, $custom_acl);
Note that you will need to find the OAI and the AWS user canonical IDs, I found them listing OAIs and S3 objects properties using the SDK. Canonical IDs are hashes that seem to be unique all across the AWS services (it is just a personal evaluation, I’ve not confirmed this with anyone from Amazon) and let you grant OAIs access to S3 objects.
Creating a private content distribution
This is the final step to have a private (signed) content CloudFront distribution. When I was working with CloudFront, it wasn’t possible to set up a distribution like this using the AWS web console so, I will show how to do it using the SDK:$cf = new AmazonCloudFront();
$opts = array(
‘Enabled’ => true,
‘OriginAccessIdentity’ => ‘oai_id’,
‘TrustedSigners’ => array(‘Self’));
$res = $cfInstance->create_distribution(‘bucket-name’, ‘dist_name’, $opts);
Note that you need to configure the AmazonCloudFront object with additional security credentials and that you will need to retrieve the OAI id to create the distribution.
Once the distribution is created, all objects within will need to be retrieved using a signature from the AWS user (that’s the reason why the TrustedSigners property have ‘Self’ as value). But this is something that I will explain in the next CloudFront-related post.