Reputation: 547
History:
I'm having a really hard time generating a url that will work. I've been trying to follow the directions described here: http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/index.html?PrivateContent.html
This is what I've got so far... doesn't work though - still getting access denied:
def url_safe(s)
s.gsub('+','-').gsub('=','_').gsub('/','~').gsub(/\n/,'').gsub(' ','')
end
def policy_for_resource(resource, expires = Time.now + 1.hour)
%({"Statement":[{"Resource":"#{resource}","Condition":{"DateLessThan":{"AWS:EpochTime":#{expires.to_i}}}}]})
end
def signature_for_resource(resource, key_id, private_key_file_name, expires = Time.now + 1.hour)
policy = url_safe(policy_for_resource(resource, expires))
key = OpenSSL::PKey::RSA.new(File.readlines(private_key_file_name).join(""))
url_safe(Base64.encode64(key.sign(OpenSSL::Digest::SHA1.new, (policy))))
end
def expiring_url_for_private_resource(resource, key_id, private_key_file_name, expires = Time.now + 1.hour)
sig = signature_for_resource(resource, key_id, private_key_file_name, expires)
"#{resource}?Expires=#{expires.to_i}&Signature=#{sig}&Key-Pair-Id=#{key_id}"
end
resource = "http://d27ss180g8tp83.cloudfront.net/iwantu.jpeg"
key_id = "APKAIS6OBYQ253QOURZA"
pk_file = "doc/pk-APKAIS6OBYQ253QOURZA.pem"
puts expiring_url_for_private_resource(resource, key_id, pk_file)
Can anyone tell me what I'm doing wrong here?
Upvotes: 8
Views: 6553
Reputation: 587
This is an old question but there is still very little out there on signing cloudfront urls using the ruby sdk, so adding some updated help. There is now a cloudfront sdk that makes this pretty easy:
signer = Aws::CloudFront::UrlSigner.new({
key_pair_id: "my_key_pair_id"
private_key_path: "./my_secret.pem" ,
# Or, you can just provide the contents of the pem as string
private_key = "--- long private key ---"
})
signed_url = signer.signed_url('http://my-cloudfront-domain.com/my/object/path', expires: 3600)
Upvotes: 4
Reputation: 1241
I agree with Dylan. He did good work with signing urls. I had the same issue. I went through the docs. There is one thing that I didn't find there. When you create a private distribution, then you usually give access for files, bucket, etc...
I got Access Denied errors until I assigned Bucket Policy.
You can assign policy like:
{
"Version":"2008-10-17",
"Id":"PolicyForCloudFrontPrivateContent",
"Statement":[{
"Sid":" Grant a CloudFront Origin Identity access to support private content",
"Effect":"Allow",
"Principal":{
"CanonicalUser":"here-goes-your-canonical-name-you-attached-to-cloudfront79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be"
},
"Action":"s3:GetObject",
"Resource":"arn:aws:s3:::change-me-to-your-bucketname/*"
}
]
}
Upvotes: 1
Reputation: 126
All,
I just created a small gem that can be used to sign CF URLs with Ruby using some of the code from this question:
https://github.com/stlondemand/aws_cf_signer
I will probably be making significant changes to it over the coming weeks as I try to actually use it in my application but wanted to let you all know as you are listed in the attributions section. :)
Thank you!
Upvotes: 11
Reputation: 547
I forked right_aws (they haven't responded to my pull request)... I set up cloudfront private streaming and downloads in their acf library: http://github.com/wiseleyb/right_aws
Upvotes: 1
Reputation: 469
Yep, leaving policy as policy = policy_for_resource(resource, expires)
worked for me.
Upvotes: 1
Reputation: 91
remove url_safe before you set policy: policy = policy_for_resource(resource, expires)
according to docs only Base64 should be safe Url-Safe (m) = CharReplace( Base64(m), "+=/", "-_~" )
.. and make sure that CloudFront is configured properly like: http://blog.cloudberrylab.com/2010/03/how-to-configure-private-content-for.html
Upvotes: 2