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
https://github.com/Frameio/cloudfront-signer/blob/master/lib/cloudfront_signer/signature.ex
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:
https://github.com/stavro/arc?tab=readme-ov-file#url-generation
Here is my blog post how to sign and extend default signature valid duration:
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance










