Create CloudFront Signed URL from Laravel application on Elastic Beanstalk

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.