ttakashinn
Troubleshooting AWS CloudFront Signed URL Generation for Accessing S3 Images
I’m trying to generate a signed URL using AWS CloudFront to access images stored on AWS S3.
Here’s the code snippet to retrieve the private key.
defp load_private_key() do
System.get_env("AWS_PRIVATE_KEY")
|> Base.decode64!()
|> :public_key.pem_decode()
|> hd()
|> :public_key.pem_entry_decode()
end
And here’s the code snippet to generate the signed URL.
defp generate_cloudfront_signed_url(s3_object_key) do
private_key = load_private_key()
key_pair_id = System.get_env("AWS_KEY_PAIR_ID")
# Generate CloudFront signed URL
generate_cloudfront_signed_url(s3_object_key, private_key, key_pair_id)
end
defp generate_cloudfront_signed_url(s3_object_key, private_key, key_pair_id) do
url = get_object_url(s3_object_key)
expires_when = calculate_expiration_in_unix_time()
policy = create_custom_policy(url, expires_when)
signature = :public_key.sign(policy, :sha, private_key)
# signature = :crypto.sign(:rsa, :sha, policy, private_key)
encoded_signature = Base.url_encode64(signature)
"#{url}?Expires=#{expires_when}&Signature=#{encoded_signature}&Key-Pair-Id=#{key_pair_id}"
end
However, when accessing the generated URL, I always encounter an error.
<Error>
<Code>MalformedSignature</Code>
<Message>Could not unencode Signature</Message>
</Error>
If anyone has experience working with CloudFront and S3, please help me out. Thank you very much.
Marked As Solved
ttakashinn
Thank you for your response. After referring to the code in the file above, I discovered the error was in the line
signature = :public_key.sign(policy, :sha, private_key)
encoded_signature = Base.url_encode64(signature)
Base.url_encode64 didn’t encode signature correctly as CloudFront requires. After changing it to
encoded_signature =
policy
|> :public_key.sign(:sha, private_key)
|> Base.encode64()
|> String.to_charlist()
|> Enum.map(&replace/1)
|> to_string()
#---------
@compile {:inline, replace: 1}
defp replace(?+), do: ?-
defp replace(?=), do: ?_
defp replace(?/), do: ?~
defp replace(c), do: c
I was able to create the signed URL normally.
Thank you.
Also Liked
karlosmid
Hi! In my previous project, I was using Elixir Arc library for that:
Here is my blog post how to sign and extend default signature valid duration:







