These examples demonstrate practical, real-world usage patterns for the s3-bucket module. Each example is self-contained and ready to run—simply copy the configuration, customize the values for your environment, and apply.

Getting Started

To run any example, follow these steps:

  1. Authenticate with the registry: terraform login registry.patterneddesigns.ca
  2. Initialize the working directory: terraform init
  3. Review the execution plan: terraform plan
  4. Apply the configuration: terraform apply

Usage Examples

Basic Usage

Minimal configuration for a secure S3 bucket

module "data_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name = "my-app-data"
}

With Versioning

S3 bucket with versioning enabled for data protection

module "versioned_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name        = "important-documents"
  versioning_enabled = true

  lifecycle_rules = [
    {
      prefix                       = ""
      noncurrent_version_expiration_days = 90
    }
  ]
}

KMS Encrypted

S3 bucket with customer-managed KMS encryption

resource "aws_kms_key" "bucket" {
  description             = "KMS key for S3 bucket encryption"
  deletion_window_in_days = 7
  enable_key_rotation     = true
}

resource "aws_kms_alias" "bucket" {
  name          = "alias/s3-bucket-key"
  target_key_id = aws_kms_key.bucket.key_id
}

module "secure_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name        = "sensitive-data"
  versioning_enabled = true
  encryption_type    = "aws:kms"
  kms_key_arn        = aws_kms_key.bucket.arn
}

Static Website

S3 bucket configured for static website hosting

module "website_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name        = "www-example-com"
  versioning_enabled = false

  website_configuration = {
    index_document = "index.html"
    error_document = "error.html"
  }

  cors_configuration = {
    cors_rules = [{
      allowed_headers = ["*"]
      allowed_methods = ["GET", "HEAD"]
      allowed_origins = ["https://example.com"]
      max_age_seconds = 86400
    }]
  }
}

resource "aws_s3_bucket_policy" "website" {
  bucket = module.website_bucket.bucket_id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Sid       = "PublicReadGetObject"
      Effect    = "Allow"
      Principal = "*"
      Action    = "s3:GetObject"
      Resource  = "${module.website_bucket.bucket_arn}/*"
    }]
  })
}

With Lifecycle Rules

S3 bucket with automated lifecycle management

module "data_lake" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name        = "data-lake-raw"
  versioning_enabled = true
  encryption_type    = "aws:kms"
  kms_key_arn        = module.kms.key_arn

  lifecycle_rules = [
    {
      id      = "logs-cleanup"
      prefix  = "logs/"
      enabled = true

      expiration_days = 90
    },
    {
      id      = "archive-old-data"
      prefix  = "data/"
      enabled = true

      transition_days  = 30
      transition_class = "STANDARD_IA"
    },
    {
      id      = "deep-archive"
      prefix  = "backups/"
      enabled = true

      transition_days  = 90
      transition_class = "GLACIER"
    },
    {
      id      = "cleanup-incomplete-uploads"
      prefix  = ""
      enabled = true

      abort_incomplete_multipart_upload_days = 7
    }
  ]
}

Cross-Region Replication

S3 bucket with cross-region replication for disaster recovery

provider "aws" {
  alias  = "replica"
  region = "us-west-2"
}

module "source_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name        = "data-primary-us-east-1"
  versioning_enabled = true
  encryption_type    = "aws:kms"
  kms_key_arn        = aws_kms_key.primary.arn
}

module "replica_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  providers = {
    aws = aws.replica
  }

  bucket_name        = "data-replica-us-west-2"
  versioning_enabled = true
  encryption_type    = "aws:kms"
  kms_key_arn        = aws_kms_key.replica.arn
}

resource "aws_iam_role" "replication" {
  name = "s3-replication-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = {
        Service = "s3.amazonaws.com"
      }
      Action = "sts:AssumeRole"
    }]
  })
}

resource "aws_s3_bucket_replication_configuration" "main" {
  bucket = module.source_bucket.bucket_id
  role   = aws_iam_role.replication.arn

  rule {
    id     = "replicate-all"
    status = "Enabled"

    destination {
      bucket        = module.replica_bucket.bucket_arn
      storage_class = "STANDARD"

      encryption_configuration {
        replica_kms_key_id = aws_kms_key.replica.arn
      }
    }

    source_selection_criteria {
      sse_kms_encrypted_objects {
        status = "Enabled"
      }
    }
  }
}

CloudFront Origin

S3 bucket as a secure CloudFront distribution origin

module "assets_bucket" {
  source  = "registry.patterneddesigns.ca/essentials/s3-bucket/aws"
  version = "3.0.0"

  bucket_name        = "cdn-assets"
  versioning_enabled = true
}

resource "aws_cloudfront_origin_access_control" "main" {
  name                              = "s3-oac"
  description                       = "OAC for S3 bucket"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

resource "aws_cloudfront_distribution" "cdn" {
  enabled             = true
  default_root_object = "index.html"

  origin {
    origin_id                = "s3-origin"
    domain_name              = module.assets_bucket.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.main.id
  }

  default_cache_behavior {
    target_origin_id       = "s3-origin"
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

resource "aws_s3_bucket_policy" "cdn" {
  bucket = module.assets_bucket.bucket_id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Sid       = "AllowCloudFrontServicePrincipal"
      Effect    = "Allow"
      Principal = {
        Service = "cloudfront.amazonaws.com"
      }
      Action   = "s3:GetObject"
      Resource = "${module.assets_bucket.bucket_arn}/*"
      Condition = {
        StringEquals = {
          "AWS:SourceArn" = aws_cloudfront_distribution.cdn.arn
        }
      }
    }]
  })
}