Introducing s3-compliance: An OpenTofu Module for Secure and Standardized S3 Buckets

In this blog post, I give you an overview of the s3-compliance OpenTofu module, for provisioning and managing Amazon S3 buckets, while adhering to data classification standards. What is s3-compliance? S3-compliance is an opinionated OpenTofu module designed to: Create and manage one or more S3 buckets using a parameterized deployment. Embed organizational standards and policies into your infrastructure provisioning, based on data classifications. Provide flexibility for users to specify certain settings while enforcing pre-approved defaults. Not all types of data require every S3 bucket feature such as versioning or object lock. The s3-compliance module addresses these diverse needs by allowing different sets of configurations for different data classifications. This tailored approach ensures that buckets are configured with only the necessary features for their specific data classification, striking a balance between security, efficiency and cost. With this module, teams can focus on their work while ensuring their provisioned S3 buckets align with organization standards and recommended practices. Data Classifications The s3-compliance module uses data classifications (e.g., public, internal, compliance) to determine which features to mandate. For example: Public Data: Minimal security features, with public access intentionally enabled where appropriate. Internal Data: Encryption using KMS and logging are mandatory; versioning is optional. Regulated Data: Strict compliance requirements, including encryption, versioning, object lock, and logging. By matching user-provided configurations to data classifications, the module allows flexibility for some settings, while enforcing others, thereby ensuring efficiency and compliance. Compliance File The s3-compliance.tf file embedded in the module defines organizational standards for various data classifications, including: Public access restrictions Encryption settings CloudTrail Logging Versioning Object locks for immutable storage Security teams vet this file to ensure compliance with organizational and regulatory requirements. A workflow may be triggered upon any changes to this compliance file to solicit the security team's approval. Alternatively, the security team may host this file in their own repository and make it available as a module output for consumption by the s3-compliance module. Input parameters Given below is the variable structure for the input parameters, showing that the s3_buckets variable accepts a list of S3 buckets for provisioning. Most of the optional configurations have defaults pre-defined as per the s3-compliance file. variable "s3_buckets" { description = "List of S3 bucket configurations." type = list(object({ # Basic configuration name = string data_classification = string # Defaults are "public", "internal" and "compliance" public_access_enabled = optional(bool) versioning_enabled = optional(bool) logging_enabled = optional(bool) tags = optional(map(string), {}) # Encryption settings kms_master_key_id = optional(string) # Use S3-managed keys by default compliance_standard = optional(string) # e.g., "PCI-DSS", "HIPAA", "ISO27001" # Object Lock settings object_lock = optional(object({ mode = optional(string) # "GOVERNANCE" or "COMPLIANCE" retention_days = optional(number) # Number of days to retain objects in locked state }), null) # Lifecycle configuration lifecycle_transitions = optional(object({ intelligent_tiering_days = optional(number, null) # Days for transitioning objects to the Intelligent Tiering class glacier_ir_days = optional(number, null) # Days for transitioning objects to the Glacier Instant Retrieval class glacier_fr_days = optional(number, null) # Days for transitioning objects to the Glacier Flexible Retrieval class glacier_da_days = optional(number, null) # Days for transitioning objects to the Glacier Deep Archive class }), null) expiration_days = optional(number, null) # Expiration after the latest transition })) Example Usage The s3-compliance module may be used as shown below. # Provision S3 buckets for a sales application module "sales-s3" { source = "git::https://github.com/cybergavin/terraform-aws-s3-compliance.git?ref=57e686755fd9c0c89b57ba1babe3f741ad6d6515 org = var.org app_id = var.app_id environment = var.environment s3_buckets = var.s3_buckets s3_logs = var.s3_logs global_tags = var.global_tags } An example s3_buckets variable for provisioning three S3 buckets for a sales application, is given below. s3_buckets = [ { name = "catalogs" data_classification = "public" public_access_enabled = true tags = { "description" = "Sales product

Jan 18, 2025 - 07:47
Introducing s3-compliance: An OpenTofu Module for Secure and Standardized S3 Buckets

In this blog post, I give you an overview of the s3-compliance OpenTofu module, for provisioning and managing Amazon S3 buckets, while adhering to data classification standards.

What is s3-compliance?

S3-compliance is an opinionated OpenTofu module designed to:

  • Create and manage one or more S3 buckets using a parameterized deployment.
  • Embed organizational standards and policies into your infrastructure provisioning, based on data classifications.
  • Provide flexibility for users to specify certain settings while enforcing pre-approved defaults.

Not all types of data require every S3 bucket feature such as versioning or object lock. The s3-compliance module addresses these diverse needs by allowing different sets of configurations for different data classifications. This tailored approach ensures that buckets are configured with only the necessary features for their specific data classification, striking a balance between security, efficiency and cost. With this module, teams can focus on their work while ensuring their provisioned S3 buckets align with organization standards and recommended practices.

Data Classifications

The s3-compliance module uses data classifications (e.g., public, internal, compliance) to determine which features to mandate. For example:

  • Public Data: Minimal security features, with public access intentionally enabled where appropriate.
  • Internal Data: Encryption using KMS and logging are mandatory; versioning is optional.
  • Regulated Data: Strict compliance requirements, including encryption, versioning, object lock, and logging.

By matching user-provided configurations to data classifications, the module allows flexibility for some settings, while enforcing others, thereby ensuring efficiency and compliance.

Compliance File

The s3-compliance.tf file embedded in the module defines organizational standards for various data classifications, including:

  • Public access restrictions
  • Encryption settings
  • CloudTrail Logging
  • Versioning
  • Object locks for immutable storage

Security teams vet this file to ensure compliance with organizational and regulatory requirements. A workflow may be triggered upon any changes to this compliance file to solicit the security team's approval. Alternatively, the security team may host this file in their own repository and make it available as a module output for consumption by the s3-compliance module.

Input parameters

Given below is the variable structure for the input parameters, showing that the s3_buckets variable accepts a list of S3 buckets for provisioning. Most of the optional configurations have defaults pre-defined as per the s3-compliance file.

variable "s3_buckets" {
  description = "List of S3 bucket configurations."
  type = list(object({
    # Basic configuration
    name                  = string
    data_classification   = string # Defaults are "public", "internal" and "compliance"
    public_access_enabled = optional(bool)
    versioning_enabled    = optional(bool)
    logging_enabled       = optional(bool)
    tags                  = optional(map(string), {})

    # Encryption settings
    kms_master_key_id   = optional(string) # Use S3-managed keys by default
    compliance_standard = optional(string) # e.g., "PCI-DSS", "HIPAA", "ISO27001"

    # Object Lock settings
    object_lock = optional(object({
      mode           = optional(string) # "GOVERNANCE" or "COMPLIANCE"
      retention_days = optional(number) # Number of days to retain objects in locked state
    }), null)

    # Lifecycle configuration
    lifecycle_transitions = optional(object({
      intelligent_tiering_days = optional(number, null) # Days for transitioning objects to the Intelligent Tiering class
      glacier_ir_days          = optional(number, null) # Days for transitioning objects to the Glacier Instant Retrieval class
      glacier_fr_days          = optional(number, null) # Days for transitioning objects to the Glacier Flexible Retrieval class
      glacier_da_days          = optional(number, null) # Days for transitioning objects to the Glacier Deep Archive class
    }), null)

    expiration_days = optional(number, null) # Expiration after the latest transition
  }))

Example Usage

The s3-compliance module may be used as shown below.

# Provision S3 buckets for a sales application
module "sales-s3" {
  source = "git::https://github.com/cybergavin/terraform-aws-s3-compliance.git?ref=57e686755fd9c0c89b57ba1babe3f741ad6d6515
  org         = var.org
  app_id      = var.app_id
  environment = var.environment
  s3_buckets  = var.s3_buckets
  s3_logs     = var.s3_logs
  global_tags = var.global_tags
}

An example s3_buckets variable for provisioning three S3 buckets for a sales application, is given below.

s3_buckets = [
    {
        name = "catalogs"
        data_classification = "public"
        public_access_enabled = true
        tags = {
            "description" = "Sales product catalogs"
        }
    },
    {
        name = "inventory"
        data_classification = "internal"
        tags = {
            "description" = "Sales inventory"
        }
        lifecycle_transitions = {
            intelligent_tiering_days = 180
        }
        expiration_days = 365
    },
    {
        name = "payment"
        data_classification = "compliance"
        compliance_standard = "PCI-DSS"
        tags = {
            "description" = "Sales payment transactions"
        }
        object_lock = {
            mode = "COMPLIANCE"
            retention_days = "2555"
        }
        lifecycle_transitions = {
            intelligent_tiering_days = 180
            glacier_ir_days = 365
            glacier_fr_days = 730
        }
        expiration_days = 2555
    }
]

For a more detailed example of using the module refer the sales-s3 example.

Getting Started

  1. Clone the module repository from GitHub: git clone https://github.com/cybergavin/terraform-aws-s3-compliance.git
  2. Review the s3-compliance.tf file with your security team and configure it to meet your data classification standards.
  3. Integrate the module into your OpenTofu project.
  4. Customize configurations where needed, while adhering to enforced defaults and use the module as per the example provided.

CI/CD workflow for module build

The module repository includes a GitHub Actions CI/CD workflow used for building the module that includes linting (tofu fmt and tflint), scanning (checkov) , testing in a sandbox environment, creating a pre-release tag, creating a pull request and create a stable release tag. This built-in CI/CD workflow could be a good starting point for you to maintain the module, if required. Alternatively, you may integrate the module into your ecosystem (TACOS, Atlantis, Digger, HCP Cloud, etc.) and use the available features for a build and release workflow.

Conclusion

The s3-compliance OpenTofu module bridges the gap between flexibility and security, allowing teams to provision S3 buckets that meet organizational standards easily. By embedding compliance directly into the provisioning process, this module simplifies operations, reduces risks, and accelerates infrastructure deployment.

Check out the s3-compliance module on GitHub and get started today! Feel free to leave me feedback on this blog post and/or raise issues on GitHub.