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:
ACL | Permissions Added to ACL |
---|---|
:private | Owner gets FULL_CONTROL . No one else has access rights (default). |
:public_read | Owner gets FULL_CONTROL . The AllUsers group gets READ access. |
:public_read_write | Owner gets FULL_CONTROL . The AllUsers group gets READ and WRITE access. |
Granting this on a bucket is generally not recommended. | |
:authenticated_read | Owner gets FULL_CONTROL . The AuthenticatedUsers group gets READ access. |
:bucket_owner_read | Object owner gets FULL_CONTROL . Bucket owner gets READ access. |
:bucket_owner_full_control | Both 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.