How to protect Amazon S3 media links with Elixir and Arc

How to protect Amazon S3 media links with Elixir and Arc - Coletiv Blog

A good way to add an extra layer of security when sharing files stored somewhere in the cloud is by using a signed url. This means that the url will have an expiration time attached and it should not be easily guessable by someone who wants to access the server’s hosted resources.

Usually, there’s an algorithm that generates a unique token to be used as a parameter at the url string.

With this article, I will describe how the signing can be achieved in Elixir with the Arc library, an Amazon S3 bucket, and an EC2 machine.

Setting up the Infrastructure 🛠

Amazon S3 bucket

The bucket should be configured using the *Block all public access *option to ensure the bucket is isolated and no-one can access it from the outside 🔒

Block all public access — **on** Block all public access — on

Amazon EC2 instance

Since our S3 bucket is not accessible from an EC2 instance we need to create an IAM Role with an IAM Policy attached that grants the EC2 instance access to the S3 bucket and perform, for example, a GET operation on some resource.

  1. Policy

Go to the IAM service and create a new policy using the JSON editor mode, then use the following code:

  "Version": "2020-04-24",
  "Statement": [
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
      "Resource": ["arn:aws:s3:::BUCKET_NAME"]

This policy allows the GET, PUT and DELETE action on all objects under the Amazon Resource Name (ARN) listed on the “Resource” array. Note that you can copy the ARN identifier from the S3 buckets list. You just need to select the bucket and then press the Copy ARN button:

S3 Bucket — Copy ARN S3 Bucket — Copy ARN

  1. IAM Role

Go to the Roles section and press the Create role button. Then select AWS Services and the EC2 use case:

IAM Role — EC2 use case IAM Role — EC2 use case

Hit next and then search for the Policy created above and attach it:

Attach Policy Attach Policy

Create the role and name it something meaningful to be used next.

  1. Attach the Role to the EC2 instance

Go to the EC2 Service page and select the EC2 instance that should have access to the S3 bucket, then press Actions and Attach/Replace IAM Role:

Attach Role Attach Role

Then you just need to select the created role and attach it to the EC2 instance.

Elixir code ✍️

Arc is a very useful library, it handles the file storage from/to an S3 bucket using the exawss3 library.

Unfortunately, this library doesn’t have any release since 2018, but it's widely used, and for sure serves its purpose. To use Arc in your project you just need to set up the dependencies and configs as explained in its

Then you just need to store some files using the store function or the arcecto _[castattachments]( as described on GitHub.

After your file is safe and secure on your private S3 bucket you can retrieve it with a signed link:

# From:
Avatar.url({"selfie.png", user}, :thumb, signed: true, expires_in: 3600)
#=> ""

You can specify an expiration time to the url using the expiresin_ parameter, the default value for the expiration time on Arc is 5 minutes, the maximum allowed by the exawss3 is 7 days.

The recommendation is for this expiration time to be as low as possible, to reduce the chance that some external user catches the url and access the private resource.

Final Thoughts 🤔

With this simple solution, we ensure that the S3 buckets are more secure. This doesn’t mean that the files are behind some bullet proof wall but surely means that getting into them is more difficult.

Thank you for reading!

Thank you so much for reading, it means a lot to us! Don’t forget to follow Coletiv on Facebook, Twitter, and LinkedIn as we keep posting interesting articles on technologies, processes, and experiences.

If you'd like to work with us on a digital product just drop us a message here.

Do you want to become part of our community?

Join our newsletter 😎