Grib
Grib

Reputation: 33

Signed URLs in CloudFront with wildcards

I'm using PHP to sign URLs to access my S3 bucket through CloudFront, signing individual files works fine using the code below. But after generating the string with a wildcard with is substituted for the the actual filename, e.g. index.html or main.css in the URL (according to the documentation here) but access is denied.

<?php 

function getSignedURL($resource, $timeout)
{
//This comes from key pair you generated for cloudfront
$keyPairId = "MYKEYPAIR";

$expires = time() + $timeout; //Time out in seconds
$json = '{"Statement":[{"Resource":"'.$resource.'","Condition":{"DateLessThan":{"AWS:EpochTime":'.$expires.'}}}]}';     

//Read Cloudfront Private Key Pair
$fp=fopen("aws.pem","r"); 
$priv_key=fread($fp,8192); 
fclose($fp); 

//Create the private key
$key = openssl_get_privatekey($priv_key);
if(!$key)
{
    echo "<p>Failed to load private key!</p>";
    return;
}

//Sign the policy with the private key
if(!openssl_sign($json, $signed_policy, $key, OPENSSL_ALGO_SHA1))
{
    echo '<p>Failed to sign policy: '.openssl_error_string().'</p>';
    return;
}

//Create url safe signed policy
$base64_signed_policy = base64_encode($signed_policy);
$signature = str_replace(array('+','=','/'), array('-','_','~'), $base64_signed_policy);

//Construct the URL
$url = $resource.'?Expires='.$expires.'&Signature='.$signature.'&Key-Pair-Id='.$keyPairId;

return $url;
}

$url = getSignedURL("http://cdn.mydomain.com/path/*", 3000);
print_r($url);

?>

My bucket policy is as follows:

{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
    {
        "Sid": "1",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::bucketname/*"
    }
]
}

Any help would be appreciated.

Upvotes: 2

Views: 2642

Answers (2)

Jessuvius
Jessuvius

Reputation: 41

This is way old, but I found it through a Google search and eventually figured out the answer based off of a hint in Mark's answer so I figured I'd share in case some other future person stumbles across this question.

I went back to the CF docs (https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html) and read a little more carefully for a policy to be a "custom policy" you have to include the actual base64-encoded policy as its own kv-pair in the query string.

I'm not super experienced in php, but probably editing your code to be something like:

$url = $resource.'?Expires='.$expires.'&Policy='.$base64_signed_policy.'&Signature='.$signature.'&Key-Pair-Id='.$keyPairId;

Upvotes: 2

Mark Simpson
Mark Simpson

Reputation: 23365

Are you using a canned or a custom policy? I found that you cannot use wildcard URLs unless you're using a custom policy, so give that a try.

Upvotes: 2

Related Questions