README.md

# erliam

erlang library for caching credentials and signing AWS API requests.

## usage

1. Add `erliam` to application dependencies or do `application:start(erliam)`.

2. Call `erliam:credentials()` to obtain latest cached credentials (stored in ets and
automatically refreshed before expiry).

3. Call `awsv4:headers(Credentials, Parameters)` to obtain awsv4-signed request headers to
use in AWS API calls.

If not using instance metadata, set `aws_access_key` and `aws_secret_key` in `erliam`
application environment to your long-term credentials; these will be used to obtain a
session token periodically.

## example

### Fetch an object from S3

```
> application:start(erliam).
> QueryParams = #{"prefix" => "some/prefix/",
                  "delimiter" => "/",
                  "list-type" => "2",
                  "encoding-type" => "url"}.
> Headers = awsv4:headers(erliam:credentials(),
                          #{service => "s3",
                            region => "us-west-2",
                            host => "bucketname.s3.amazonaws.com",
                            path => "/",
                            query_params => QueryParams}).
> httpc:request(get, {lists:flatten("https://bucketname.s3.amazonaws.com/?" ++
                                    awsv4:canonical_query(QueryParams)), Headers}, [], []).

{ok, {{"HTTP/1.1", 200, "OK"},
 [{"date", "Fri, 02 Jun 2017 23:26:21 GMT"},
  {"server", "AmazonS3"},
  {"content-length", "496"},
  {"content-type", "application/xml"},
  {"x-amz-id-2", "SOME-ID"},
  {"x-amz-request-id", "SOME-OTHER-ID"},
  {"x-amz-bucket-region", "us-west-2"}],
 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>bucketname</Name>..."}}
```

### Encrypt plaintext using KMS

```
> application:start(erliam).
> QueryParams = #{}.
> KeyId = <<"xxxx-xxxx-xxxx-xxxx-xxxxxxxxxx">>
> RequestBody = jiffy:encode(#{<<"EncryptionContext">> => #{<<"application">> => <<"thing encryptor">>},
                               <<"KeyId">> => KeyId,
                               <<"Plaintext">> => base64:encode(<<"setec astronomy">>)}).
> SignedHeaders = #{"content-type" => "application/x-amz-json-1.1"}.
> Headers = awsv4:headers(erliam:credentials(),
                          #{service => "kms",
                            target_api => "TrentService.Encrypt",
                            method => "POST",
                            region => "us-east-1",
                            query_params => QueryParams,
                            signed_headers => SignedHeaders},
                          RequestBody).
> httpc:request(post, {lists:flatten(["https://kms.us-east-1.amazonaws.com", "/?",
                                      awsv4:canonical_query(QueryParams)]),
                       Headers,
                       proplists:get_value("content-type", Headers), RequestBody}, [], []).

{ok, {{"HTTP/1.1", 200, "OK"},
     [{"content-length", "307"},
      {"content-type", "application/x-amz-json-1.1"},
      {"x-amzn-requestid", "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"}],
     "{\"CiphertextBlob\":\"B64ENCODED CIPHERTEXT\",\"KeyId\":\"KEY ARN\"}"}}
```