Jabaa
Jabaa

Reputation: 1753

Configure AWS cloudfront for serving signed url from s3 bucket

i've have a folder named private in my s3 bucket and the contents in that folder only accessed by authorised user (ie Public read access is disabled).

So i am generating sigened url's for accessing one of the object in that folder it works fine.

Here is the signed URL format

s3-<region>.amazonaws.com/<folder>/<imagename>??X-Amz-Content-Sha256=.......

Also i have created cloudfront distribution for the above s3 bucket for better performance. here is the cloudfront url xxxxjjjj.cloudfront.net

So how can i serve my signed url with this cloudfront distribution??

When i try with this url

xxxxjjjj.cloudfront.net/<folder>/<imagename>??X-Amz-Content-Sha256=.......

I will get access denied error,i think this is not the right way to deliver the s3 signed url content with cloudfront distribution.

Using php laravel framework

Upvotes: 0

Views: 3131

Answers (3)

Pawan Verma
Pawan Verma

Reputation: 1269

There is an easiest way to generate cloudfront Signed URL. There is a cloudfront signed URL signer on GitHub, edit the config and use it.

  1. The package can be installed via Composer:

    composer require dreamonkey/laravel-cloudfront-url-signer

2.The configuration file can optionally be published via:

php artisan vendor:publish --provider="Dreamonkey\CloudFrontUrlSigner\CloudFrontUrlSignerServiceProvider"
  1. URL's can be signed with the sign method:

    use CloudFrontUrlSigner;

    CloudFrontUrlSigner::sign('https://myapp.com/resource');

Upvotes: 0

Alaeddin AL Zeybek
Alaeddin AL Zeybek

Reputation: 739

There is an example for what you are asking using PHP SDK in this link https://docs.aws.amazon.com/aws-sdk-php/v3/guide/service/cloudfront-signed-url.html

and here's the equivalent code in Larave (5.3) using custom policy:

public static function signedUrl($resourceKey) {
    //$resourceKey = 'videos/example.mp4'
    $baseUrl = 'https://xxxxjjjj.cloudfront.net';
    $fullUrl = $baseUrl . '/' . $resourceKey;
    $expires = time() + 300;
    $customSigningPolicy = <<<POLICY
{
    "Statement": [
        {
            "Resource": "{$fullUrl}",
            "Condition": {
                "DateLessThan": {"AWS:EpochTime": {$expires}}
            }
        }
    ]
}
POLICY;

    // CloudFront Signed Urls
    /** @var CloudFrontClient $cloudFront */
    $cloudFront = \AWS::createClient('CloudFront');
    $url = $cloudFront->getSignedUrl([
        'url' => $fullUrl,
        'policy' =>  $customSigningPolicy,
        'key_pair_id' => 'YOUR_KEY_PAIR_ID',
        'private_key' => '/path/to/your/cloudfront-private-key.pem'
    ]);

    return $url;
}

P.S. I found a mistake in the aws example, since they used the $resourceKey as the Resource value in the policy which is not woking, what worked with me is to use the full url of the file.

Their code:

$resourceKey = 'videos/example.mp4';
$customPolicy = <<<POLICY
{
    "Statement": [
        {
            "Resource": "{$resourceKey}",
            "Condition": {
                "IpAddress": {"AWS:SourceIp": "{$_SERVER['REMOTE_ADDR']}/32"},
                "DateLessThan": {"AWS:EpochTime": {$expires}}
            }
        }
    ]
}
POLICY;

What Worked:

$resourceKey = 'videos/example.mp4'; // or $resourceKey = 'videos/*'; or $resourceKey = '*';
$fullUrl = $baseUrl . '/' . $resourceKey;
$customPolicy = <<<POLICY
{
    "Statement": [
        {
            "Resource": "{$fullUrl}",
            "Condition": {
                "IpAddress": {"AWS:SourceIp": "{$_SERVER['REMOTE_ADDR']}/32"},
                "DateLessThan": {"AWS:EpochTime": {$expires}}
            }
        }
    ]
}
POLICY;

Upvotes: 1

Michael - sqlbot
Michael - sqlbot

Reputation: 178956

Signed URLs for CloudFront use a different format and different credentials than signed URLs for S3.

Read Serving Private Content through CloudFront.

There is a laravel-url-signer on GitHub or you can write your own code from this example in the CloudFront docs.

For testing your CloudFront and S3 settings, you can use aws cloudfront sign ... in aws-cli to generate a test signed URL.

Upvotes: 5

Related Questions