AWS-Signature-V4
view release on metacpan or search on metacpan
eg/README.md view on Meta::CPAN
modules (`HTTP::Tiny` needs `IO::Socket::SSL` for HTTPS), plus CryptX for
the X.509 ones. Run them from a checkout (they load `../lib`).
Set `DRY_RUN=1` to see the signed request instead of sending it. This is
handy to try them out without any AWS access, e.g. with dummy credentials:
```shell
export AWS_ACCESS_KEY_ID=AKIDEXAMPLE AWS_SECRET_ACCESS_KEY=secret DRY_RUN=1
```
Credentials come from `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and
optionally `AWS_SESSION_TOKEN`; the region from `AWS_REGION` where it
makes sense (default `us-east-1`).
`HTTP::Tiny` is used only because it is in the core: the module does not
depend on it, and any other user agent can be used the same way. Mind that
`HTTP::Tiny` wants to set the `Host` header itself, so the examples remove
it from the headers they pass (it is still part of the signature). They
also ask it to verify TLS certificates explicitly (`verify_SSL => 1`),
because versions of `HTTP::Tiny` before 0.083, bundled with older Perls,
do not do it by default: without it, anybody in the middle could read the
signed requests and, in example 07, the temporary credentials.
## 01-sts-get-caller-identity.pl
The simplest case: a signed POST with credentials taken from the
environment. It asks STS who the caller is, so it is also a quick way to
check that the credentials work: it prints the answer either way, and
exits non-zero when the request fails.
```shell
./eg/01-sts-get-caller-identity.pl
DRY_RUN=1 ./eg/01-sts-get-caller-identity.pl
```
## 02-s3-get-object.pl
Download an S3 object, printing it on the standard output or saving it in
a file. S3 is special (paths are neither normalized nor double-encoded,
the payload hash goes in a header) but the module knows it from the
service name.
```shell
./eg/02-s3-get-object.pl my-bucket path/to/key.txt
AWS_REGION=eu-west-1 ./eg/02-s3-get-object.pl my-bucket photo%20one.jpg photo.jpg
```
Like 03, 04 and 05, this example puts the key in the URL as it is
written, so the key must be given as it appears there: ASCII,
percent-encoded (a space is `%20`, a percent sign `%25`, and so on).
Handing over a raw space makes `HTTP::Tiny` write an invalid request
line, and a raw `%`, `?` or `#` truncates the key or breaks the
signature.
These four examples also use the virtual-hosted URL, where the bucket is
part of the host name. That host does not match the
`*.s3.REGION.amazonaws.com` certificate when the bucket name contains a
dot, and the answer is not to turn TLS verification off: use the
path-style URL `https://s3.REGION.amazonaws.com/BUCKET/KEY` for those
buckets.
Because the bucket and `AWS_REGION` end up in the host name, they are
checked before use, as in 10: a `/` in either would move the host
somewhere else altogether (a bucket of `evil.example.com/x` gives
`https://evil.example.com/x.s3...`) and the request would be signed and
sent there, session token and all. The key needs no such check, since it
lands in the path: `sign` already refuses control characters in the URL,
and the rest is the encoding caveat above.
## 03-s3-put-object-from-file.pl
Upload a file to S3 without loading it in memory: the payload hash is
computed from a filehandle (`body_fh`, which is left where it was), and
`HTTP::Tiny` then reads the same file a piece at a time when sending.
```shell
./eg/03-s3-put-object-from-file.pl backup.tar.gz my-bucket backups/backup.tar.gz
DRY_RUN=1 ./eg/03-s3-put-object-from-file.pl big.iso my-bucket isos/big.iso
```
## 04-s3-presigned-urls.pl
Presigned URLs: the signature travels in the query string, so anyone
holding the URL can use it until it expires, with any client at all. It
prints one URL to read the object and one to write it.
```shell
./eg/04-s3-presigned-urls.pl my-bucket path/to/key.txt
./eg/04-s3-presigned-urls.pl my-bucket path/to/key.txt 600 # valid for 10 minutes
```
The output suggests how to use them with `curl`.
## 05-s3-chunked-upload.pl
Streaming upload to S3 (`aws-chunked`): the body is sent in signed
chunks, so the whole payload does not need to be hashed in advance nor
held in memory. The total size must be known, because the `Content-Length`
of the encoded body is computed with `encoded_length` and the chunker
checks that the data matches. In dry-run mode it also encodes the file and
reports how many bytes the body has, compared with the announced length.
To try a trailing checksum, set the `@checksum` variable in the script to
`(checksum => 'crc32c')`: it is passed to both `encoded_length` and
`sign`, because the announced length has to count the trailer too.
```shell
./eg/05-s3-chunked-upload.pl data.bin my-bucket uploads/data.bin
DRY_RUN=1 ./eg/05-s3-chunked-upload.pl data.bin my-bucket uploads/data.bin
```
## 06-dynamodb-json-api.pl
A JSON API, where the operation is chosen by a header
(`X-Amz-Target`), signed like all the others. It lists the DynamoDB tables
( run in 1.938 second using v1.01-cache-2.11-cpan-b554fb43c41 )