Reputation: 33
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
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
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