Create CloudFront Signed URL from Laravel application on Elastic Beanstalk

Yutaro Shimamura
4 min readAug 24, 2021

The way of creating a CloudFront signed URL from a Laravel application is pretty straightforward like this article, if you just want to test it out on your local environment.

I struggled some points when I had to do that on AWS Elastic Beanstalk environment, especially dealing with the private key needed to generate CloudFront signed URL.

Here is how I managed it.

(This article focused on URL generation, so I won’t cover the details of storing files to S3 in details here.)

TL;DR.

  • Create a key pair
  • Upload private key to private S3 bucket
  • Create a config file for private key inside .ebextensions
  • Write some Laravel codes for creating URLs
  • Deploy and check

Create a key pair

Basically, you just need to follow this document to create a key pair.

Generate an RSA key pair

openssl genrsa -out private_key.pem 2048

Extract public_key.pem from private_key.pem

openssl rsa -pubout -in private_key.pem -out public_key.pem

Upload public_key.pem to CloudFront

In your CloudFront navigation, select Public keys, Add public key, and paste the result of the following cat command in the window.

cat public_key.pem

Add public key to key group

In the navigation, select Key groups and Add key group. Select your key and Create key group.

Upload private key to private S3 bucket

Upload your private key to S3 bucket. For this time, I will use the bucket which was already created for the Beanstalk environment.

(Please check your bucket policy is secure enough and the bucket blocks all public access)

This time I will just upload the private_key.pem to the root of the bucket.

Create a .ebextensions config file

We will need a new config file to use the private key from the Elastic Beanstalk environment.

We just need to follow the example.

For buckets in Resources:, specify your Beanstalk-generated bucket.
For source in files , specify your key path in S3 bucket.

Resources:
AWSEBAutoScalingGroup:
Metadata:
AWS::CloudFormation::Authentication:
S3Auth:
type: "s3"
buckets: ["elasticbeanstalk-us-west-2-123456789012"]
roleName:
"Fn::GetOptionSetting":
Namespace: "aws:autoscaling:launchconfiguration"
OptionName: "IamInstanceProfile"
DefaultValue: "aws-elasticbeanstalk-ec2-role"
files:
# Private key
"/etc/pki/tls/certs/private_key.pem":
mode: "000400"
owner: root #change if necessary
group: root #change if necessary
authentication: "S3Auth"
source: https://elasticbeanstalk-us-west-2-123456789012.s3.us-west-2.amazonaws.com/private_key.pem

Write some Laravel codes for creating URLs

Install SDK

composer require aws/aws-sdk-php-laravel

Edit config/app.php

Add to providers.

'providers' => array(
// ...
Aws\Laravel\AwsServiceProvider::class,
)

Add to aliases.

'aliases' => array(
// ...
'AWS' => Aws\Laravel\AwsFacade::class,
)

Generate Signed URL

use Aws\Laravel\AwsFacade;// ...
$path = $path_of_your_file
$client = AwsFacade::createClient('cloudfront');
$signedUrl = $client->getSignedUrl([
'url' => config('filesystems.disks.s3.url') . '/' . $path,
'expires' => time() + 30, // seconds
'private_key' => realpath(config('app.private_key_path')),
'key_pair_id' => config('app.key_pair_id'),
]);

The above code generates a CloudFront Signed URL for a file stored in S3 bucket.

Here is the config and env for the Elastic Beanstalk environment if that helps.

config/app.php

// ...
'key_pair_id' => env('AWS_CLOUDFRONT_KEY_PAIR_ID', ''),
'private_key_path' => env('PRIVATE_KEY_PATH', ''),

env variables for the Beanstalk environment

// ...
AWS_URL=https://xxxxxxxxxxxxx.cloudfront.net
PRIVATE_KEY_PATH=/etc/pki/tls/private/private_key.pem
AWS_CLOUDFRONT_KEY_PAIR_ID=XXXXXXXXXXXXXX

Deploy and check

Now, deploy your laravel application to Elastic Beanstalk and check if the URL generation works.

If you succeed, your url returns your S3 uploaded file.

If the URL becomes invalid (ex. expired), you will get this message.

Thanks for reading! Hope if this helps you a little.

Feel free to share, comment, or follow me on Twitter!

Below is the Japanese(日本語) version of this article.

--

--