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

  }

}