Skip to content

epomatti/aws-cloudfront-s3-oac-oai

Repository files navigation

AWS CloudFront OAC OAI

AWS CloudFront S3 origina with OAC and OAI.

As per the current documentation, OAC authenticated requests supports:

  • All Amazon S3 buckets in all AWS Regions, including opt-in Regions launched after December 2022
  • Amazon S3 server-side encryption with AWS KMS (SSE-KMS)
  • Dynamic requests (PUT and DELETE) to Amazon S3

First, create a key pair for the CloudFront signed URL stuff (ref1, ref2):

mkdir keys
openssl genrsa -des3 -out keys/private.pem 2048
openssl rsa -in keys/private.pem -outform PEM -pubout -out keys/public.pem

Create the .auto.tfvars file from the sample:

The ACM certificate verification will be required

cloudfront_price_class              = "PriceClass_100"
certificate_domain                  = "cf.example.com"
cloudfront_minimum_protocol_version = "TLSv1.2_2021"

To create the infrastructure:

terraform init
terraform apply -auto-approve

As described in the S3 origin documentation, S3 regional domains should be used:

# Use the regional bucket domain
<bucket-name>.s3.<region>.amazonaws.com

For server-side encryption (SSE) The implementation enabled aws:kms (SSE-KMS) encryption for OAC, and AES256 (SSE-S3)for OAI.

To test the distribution access the endpoints on paths /oac and /oai respectively.

Policy implementation between the two authentication methods differ:

Policy OAC OAI
Principal cloudfront.amazonaws.com OAI identity id
Condition AWS:SourceArn with the distribution ARN n/a

Sharing Objects with URLs

There are two types of share with URLs:

S3 presigned URLs

You can generate a presigned URL which will use the credentials of the user who generated the URLs. This would be useful for users who do not have access to the account with AWS credentials ("anonymous").

Generate a presigned URL, open an anonymous browser session and use the link to access the object:

# For regions launched prior to 2019
aws s3 presign s3://bucket-presignedurl-vouchers010203/vouchers/voucher.txt --expires-in 604800

CloudFront Signed URLs

Signed URLs are more secure and offer additional controls with canned policies but specially with custom policies.

Edit the policy.json file accordingly, and generate the signature:

cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha1 -sign keys/private.pem | openssl base64 -A | tr -- '+=/' '-_~'

The signed URL will look like this:

https://ddddddd00001111.cloudfront.net/vouchers/voucher.txt?Expires=1698637841&Signature=<SIGNATURE>&Key-Pair-Id=KQPALV128937

Ciphers + Enforce TLS

Setting a custom certificate on ACM for CloudFront allows you to select the Ciphers list.

For details, check Supported protocols and ciphers between viewers and CloudFront.

The following S3 bucket policy enforces TLS by denying insecure transport via "aws:SecureTransport" : "false":

"Statement" : [
  {
    "Sid" : "EnforceTLS",
    "Action" : "s3:*",
    "Effect" : "Deny",
    "Resource" : [
      "arn:aws:s3:::DOC-EXAMPLE-BUCKET",
      "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
    ],
    "Condition" : {
      "Bool" : {
        "aws:SecureTransport" : "false"
      }
    }
  }
]

Clean-up

Destroy the resources when you're done using it:

terraform destroy -auto-approve