Waffle.Storage.S3 (waffle v1.1.6)

The module to facilitate integration with S3 through ExAws.S3

config :waffle,
  storage: Waffle.Storage.S3,
  bucket: {:system, "AWS_S3_BUCKET"}

Along with any configuration necessary for ExAws.

ExAws is used to support Amazon S3.

To store your attachments in Amazon S3, you'll need to provide a bucket destination in your application config:

config :waffle,
  bucket: "uploads"

You may also set the bucket from an environment variable:

config :waffle,
  bucket: {:system, "S3_BUCKET"}

In addition, ExAws must be configured with the appropriate Amazon S3 credentials.

ExAws has by default the following configuration (which you may override if you wish):

config :ex_aws,
  json_codec: Jason,
  access_key_id: [{:system, "AWS_ACCESS_KEY_ID"}, :instance_role],
  secret_access_key: [{:system, "AWS_SECRET_ACCESS_KEY"}, :instance_role]

This means it will first look for the AWS standard AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, and fall back using instance meta-data if those don't exist. You should set those environment variables to your credentials, or configure an instance that this library runs on to have an iam role.

Specify multiple buckets

Waffle lets you specify a bucket on a per definition basis. In case you want to use multiple buckets, you can specify a bucket in the definition module like this:

def bucket, do: :some_custom_bucket_name

You can also use the current scope to define a target bucket

def bucket({_file, scope}), do: scope.bucket || bucket()

Access Control Permissions

Waffle defaults all uploads to private. In cases where it is desired to have your uploads public, you may set the ACL at the module level (which applies to all versions):

@acl :public_read

Or you may have more granular control over each version. As an example, you may wish to explicitly only make public a thumbnail version of the file:

def acl(:thumb, _), do: :public_read

Supported access control lists for Amazon S3 are:

ACLPermissions Added to ACL
:privateOwner gets FULL_CONTROL. No one else has access rights (default).
:public_readOwner gets FULL_CONTROL. The AllUsers group gets READ access.
:public_read_writeOwner gets FULL_CONTROL. The AllUsers group gets READ and WRITE access.
Granting this on a bucket is generally not recommended.
:authenticated_readOwner gets FULL_CONTROL. The AuthenticatedUsers group gets READ access.
:bucket_owner_readObject owner gets FULL_CONTROL. Bucket owner gets READ access.
:bucket_owner_full_controlBoth the object owner and the bucket owner get FULL_CONTROL over the object.

For more information on the behavior of each of these, please consult Amazon's documentation for Access Control List (ACL) Overview.

S3 Object Headers

The definition module may specify custom headers to pass through to S3 during object creation. The available custom headers include:

  • :cache_control
  • :content_disposition
  • :content_encoding
  • :content_length
  • :content_type
  • :expect
  • :expires
  • :storage_class
  • :website_redirect_location
  • :encryption (set to "AES256" for encryption at rest)

As an example, to explicitly specify the content-type of an object, you may define a s3_object_headers/2 function in your definition, which returns a Keyword list, or Map of desired headers.

def s3_object_headers(version, {file, scope}) do
  [content_type: MIME.from_path(file.file_name)] # for "image.png", would produce: "image/png"
end

Alternate S3 configuration example

If you are using a region other than US-Standard, it is necessary to specify the correct configuration for ex_aws. A full example configuration for both waffle and ex_aws is as follows:

config :waffle,
  bucket: "my-frankfurt-bucket"

config :ex_aws,
  json_codec: Jason,
  access_key_id: "my_access_key_id",
  secret_access_key: "my_secret_access_key",
  region: "eu-central-1",
  s3: [
    scheme: "https://",
    host: "s3.eu-central-1.amazonaws.com",
    region: "eu-central-1"
  ]

For your host configuration, please examine the approved AWS Hostnames. There are often multiple hostname formats for AWS regions, and it will not work unless you specify the correct one.

Link to this section Summary

Link to this section Functions

Link to this function

delete(definition, version, arg)

Link to this function

put(definition, version, arg)

Link to this function

url(definition, version, file_and_scope, options \\ [])