s3 (terraform)
Introduction
Terraform s3 configuration changed significantly for provider hashicorp/aws version 4.
Examples shown use the new configuration.
For creating an user and giving it access to S3 bucket, see:
https://sites.google.com/site/pawneecity/terraform/iam-terraform#h.m7i6tdp3tf70
Sample: Private S3 bucket with versioning, encryption & lifecycle
modules/s3/variables.tf
variable "env" {}
variable "ci" {}
variable "Department" {}
variable "Program" {}
variable "bucket_data1" {}
modules/s3/outputs.tf
# Buckets regional domain name, taken from any of them
output "s3_domain" {
value = aws_s3_bucket.myapp-bucket-data1.bucket_regional_domain_name
}
output "s3_data1_arn" {
value = aws_s3_bucket.myapp-bucket-data1.arn
}
output "s3_data1_bucket" {
value = aws_s3_bucket.myapp-bucket-data1.bucket
}
output "s3_data1_id" {
value = aws_s3_bucket.myapp-bucket-data1.id
}
modules/s3/s3.tf
resource "aws_s3_bucket" "data1" {
bucket = "${var.env}-${var.ci}-${var.bucket_data1}"
tags = {
Name = "${var.bucket_data1}-s3-${var.env}"
ci = var.ci
Departament = var.Department
COUEnv = var.env
Programa = var.Program
}
}
resource "aws_s3_bucket_acl" "data1_acl" {
bucket = aws_s3_bucket.myapp-bucket-data1.id
acl = "private"
}
resource "aws_s3_bucket_versioning" "data1_versioning" {
bucket = aws_s3_bucket.myapp-bucket-data1.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data1_encrypt" {
bucket = aws_s3_bucket.myapp-bucket-data1.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_lifecycle_configuration" "data1_lifecycle" {
depends_on = [aws_s3_bucket_versioning.data1_versioning]
bucket = aws_s3_bucket.data1.id
rule {
id = "all_tiering_expire"
status = "Enabled"
filter {} # Applies to all objects in the bucket
expiration {
days = var.bucket_data1_lifecycle_expiration_days
}
transition {
days = 256
storage_class = "INTELLIGENT_TIERING" //Intelligent-Tiering
}
transition {
days = 512
storage_class = "GLACIER_IR" //Glacier Isntant Retrieval
}
#Permanently delete noncurrent versions of objects >> Days after objects become noncurrent
noncurrent_version_expiration {
noncurrent_days = 384
}
noncurrent_version_transition {
noncurrent_days = 4
storage_class = "GLACIER_IR" //Glacier Instant Retrieval
}
#Delete expired object delete markers or incomplete multipart uploads >> Incomplete multipart uploads
abort_incomplete_multipart_upload {
days_after_initiation = 128
}
}
}
Sample: Frontend app via CloudFront (Block all public access)
Eg: fwdefense
modules/s3/variables
variable "front_policy_text" {
nullable = false
}
#finalwork_cors_origins. Eg: ["http://localhost:4200", "https://${local.domain}]"]
variable "finalwork_cors_origins" {
description = "CORS AllowedOrigins array"
type = list(string)
nullable = false
}
modules/s3/s3.tf
# Frontend app
resource "aws_s3_bucket" "frontend" {
bucket = "${var.env}-${var.ci}-s3"
force_destroy = true
}
# Block all public access
resource "aws_s3_bucket_public_access_block" "frontend" {
bucket = aws_s3_bucket.frontend.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# ACL private [1/2] (frontend)
resource "aws_s3_bucket_ownership_controls" "frontend" {
bucket = aws_s3_bucket.frontend.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
# ACL private [2/2] (frontend)
resource "aws_s3_bucket_acl" "frontend" {
depends_on = [aws_s3_bucket_ownership_controls.frontend]
bucket = aws_s3_bucket.frontend.id
acl = "private"
}
# Allow access from CloudFront (frontend)
# The policy text (JSON) is generated from the module 'cloudfront' using one of:
# data "aws_iam_policy_document" "origin_access_control" (attribute 'json')
# data "aws_iam_policy_document" "origin access identity" (attribute 'json')
resource "aws_s3_bucket_policy" "front_policy" {
bucket = aws_s3_bucket.frontend.id
policy = var.front_policy_text
}
# CORS. Ensure the browser AJAX fill be able to POST for uploading the file
resource "aws_s3_bucket_cors_configuration" "finalwork_cors" {
bucket = aws_s3_bucket.finalwork_s3.id
cors_rule {
allowed_headers = ["*"] //Eg: ["*"]
allowed_methods = ["GET", "HEAD", "POST"]
allowed_origins = var.finalwork_cors_origins
expose_headers = [] //Eg: ["ETag"]
max_age_seconds = 3000
}
}