Home

Awesome

Modernisation Platform Terraform S3 Bucket Module

Standards Icon Format Code Icon Scorecards Icon SCA Icon Terraform SCA Icon

A Terraform module to standardise S3 buckets with sensible defaults.

Usage

module "s3-bucket" {
    source = "github.com/ministryofjustice/modernisation-platform-terraform-s3-bucket?ref=v7.0.0"

  bucket_prefix                            = "s3-bucket"
  versioning_enabled                       = true

  # to disable ACLs in preference of BucketOwnership controls as per https://aws.amazon.com/blogs/aws/heads-up-amazon-s3-security-changes-are-coming-in-april-of-2023/ set:
  ownership_controls = "BucketOwnerEnforced"

  # Refer to the below section "Replication" before enabling replication
  replication_enabled                      = false
  # Below variable and providers configuration is only relevant if 'replication_enabled' is set to true
  # replication_region                       = "eu-west-2"
  providers = {
    # Here we use the default provider Region for replication. Destination buckets can be within the same Region as the
    # source bucket. On the other hand, if you need to enable cross-region replication, please contact the Modernisation
    # Platform team to add a new provider for the additional Region.
    # Leave this provider block in even if you are not using replication
    aws.bucket-replication = aws
  }

  lifecycle_rule = [
    {
      id      = "main"
      enabled = "Enabled"
      prefix  = ""

      tags = {
        rule      = "log"
        autoclean = "true"
      }

      transition = [
        {
          days          = 90
          storage_class = "STANDARD_IA"
          }, {
          days          = 365
          storage_class = "GLACIER"
        }
      ]

      expiration = {
        days = 730
      }

      noncurrent_version_transition = [
        {
          days          = 90
          storage_class = "STANDARD_IA"
          }, {
          days          = 365
          storage_class = "GLACIER"
        }
      ]

      noncurrent_version_expiration = {
        days = 730
      }
    }
  ]

  tags                 = local.tags
}
<!-- BEGIN_TF_DOCS -->

Requirements

NameVersion
<a name="requirement_terraform"></a> terraform>= 1.0.1
<a name="requirement_aws"></a> aws~> 5.0

Providers

NameVersion
<a name="provider_aws"></a> aws~> 5.0
<a name="provider_aws.bucket-replication"></a> aws.bucket-replication~> 5.0

Modules

No modules.

Resources

NameType
aws_iam_policy.replication_policyresource
aws_iam_role.replication_roleresource
aws_iam_role_policy_attachment.replicationresource
aws_s3_bucket.defaultresource
aws_s3_bucket.replicationresource
aws_s3_bucket_acl.defaultresource
aws_s3_bucket_acl.replicationresource
aws_s3_bucket_lifecycle_configuration.defaultresource
aws_s3_bucket_lifecycle_configuration.replicationresource
aws_s3_bucket_logging.default_bucket_objectresource
aws_s3_bucket_notification.bucket_notificationresource
aws_s3_bucket_notification.bucket_notification_replicationresource
aws_s3_bucket_ownership_controls.defaultresource
aws_s3_bucket_ownership_controls.replicationresource
aws_s3_bucket_policy.defaultresource
aws_s3_bucket_policy.log_bucket_policyresource
aws_s3_bucket_policy.replicationresource
aws_s3_bucket_public_access_block.defaultresource
aws_s3_bucket_public_access_block.replicationresource
aws_s3_bucket_replication_configuration.defaultresource
aws_s3_bucket_server_side_encryption_configuration.defaultresource
aws_s3_bucket_server_side_encryption_configuration.replicationresource
aws_s3_bucket_versioning.defaultresource
aws_s3_bucket_versioning.replicationresource
aws_caller_identity.currentdata source
aws_iam_policy_document.bucket_policy_v2data source
aws_iam_policy_document.defaultdata source
aws_iam_policy_document.replicationdata source
aws_iam_policy_document.replication-policydata source
aws_iam_policy_document.s3-assume-role-policydata source

Inputs

NameDescriptionTypeDefaultRequired
<a name="input_acl"></a> aclUse canned ACL on the bucket instead of BucketOwnerEnforced ownership controls. var.ownership_controls must be set to corresponding value below.string"private"no
<a name="input_bucket_name"></a> bucket_namePlease use bucket_prefix instead of bucket_name to ensure a globally unique name.stringnullno
<a name="input_bucket_policy"></a> bucket_policyJSON for the bucket policylist(string)<pre>[<br/> "{}"<br/>]</pre>no
<a name="input_bucket_policy_v2"></a> bucket_policy_v2Alternative to bucket_policy. Define policies directly without needing to know the bucket ARN<pre>list(object({<br/> effect = string<br/> actions = list(string)<br/> principals = optional(object({<br/> type = string<br/> identifiers = list(string)<br/> }))<br/> conditions = optional(list(object({<br/> test = string<br/> variable = string<br/> values = list(string)<br/> })), [])<br/> }))</pre>[]no
<a name="input_bucket_prefix"></a> bucket_prefixBucket prefix, which will include a randomised suffix to ensure globally unique namesstringnullno
<a name="input_custom_kms_key"></a> custom_kms_keyKMS key ARN to usestring""no
<a name="input_custom_replication_kms_key"></a> custom_replication_kms_keyKMS key ARN to use for replication to eu-west-2string""no
<a name="input_force_destroy"></a> force_destroyA boolean that indicates all objects (including any locked objects) should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable.boolfalseno
<a name="input_lifecycle_rule"></a> lifecycle_ruleList of maps containing configuration of object lifecycle management.any<pre>[<br/> {<br/> "enabled": "Enabled",<br/> "expiration": {<br/> "days": 730<br/> },<br/> "id": "main",<br/> "noncurrent_version_expiration": {<br/> "days": 730<br/> },<br/> "noncurrent_version_transition": [<br/> {<br/> "days": 90,<br/> "storage_class": "STANDARD_IA"<br/> },<br/> {<br/> "days": 365,<br/> "storage_class": "GLACIER"<br/> }<br/> ],<br/> "prefix": "",<br/> "tags": {<br/> "autoclean": "true",<br/> "rule": "log"<br/> },<br/> "transition": [<br/> {<br/> "days": 90,<br/> "storage_class": "STANDARD_IA"<br/> },<br/> {<br/> "days": 365,<br/> "storage_class": "GLACIER"<br/> }<br/> ]<br/> }<br/>]</pre>no
<a name="input_log_bucket"></a> log_bucketUnique name of s3 bucket to log to (not defined in terraform)stringnullno
<a name="input_log_bucket_names"></a> log_bucket_namesUnique names of s3 bucket to log to (not defined in terraform)set(string)nullno
<a name="input_log_buckets"></a> log_bucketsMap containing log bucket details and its associated bucket policy.map(any)nullno
<a name="input_log_partition_date_source"></a> log_partition_date_sourcePartition logs by date. Allowed values are 'EventTime', 'DeliveryTime', or 'None'.string"None"no
<a name="input_log_prefix"></a> log_prefixPrefix for all log object keys.stringnullno
<a name="input_notification_enabled"></a> notification_enabledBoolean indicating if a notification resource is required for the bucketboolfalseno
<a name="input_notification_events"></a> notification_eventsThe event for which we send notificationslist(string)<pre>[<br/> ""<br/>]</pre>no
<a name="input_notification_sns_arn"></a> notification_sns_arnThe arn for the bucket notification SNS topicstring""no
<a name="input_ownership_controls"></a> ownership_controlsBucket Ownership Controls - for use WITH acl var above options are 'BucketOwnerPreferred' or 'ObjectWriter'. To disable ACLs and use new AWS recommended controls set this to 'BucketOwnerEnforced' and which will disabled ACLs and ignore var.aclstring"ObjectWriter"no
<a name="input_replication_bucket"></a> replication_bucketName of bucket used for replication - if not specified then * will be used in the policystring""no
<a name="input_replication_enabled"></a> replication_enabledActivate S3 bucket replicationboolfalseno
<a name="input_replication_region"></a> replication_regionRegion to create S3 replication bucketstring"eu-west-2"no
<a name="input_replication_role_arn"></a> replication_role_arnRole ARN to access S3 and replicate objectsstring""no
<a name="input_sse_algorithm"></a> sse_algorithmThe server-side encryption algorithm to usestring"aws:kms"no
<a name="input_suffix_name"></a> suffix_nameSuffix for role and policy namesstring""no
<a name="input_tags"></a> tagsTags to apply to resources, where applicablemap(any)n/ayes
<a name="input_versioning_enabled"></a> versioning_enabledActivate S3 bucket versioningbooltrueno

Outputs

NameDescription
<a name="output_bucket"></a> bucketDirect aws_s3_bucket resource with all attributes
<a name="output_bucket_notifications"></a> bucket_notificationsn/a
<a name="output_bucket_policy"></a> bucket_policyPolicy of the bucket
<a name="output_bucket_server_side_encryption"></a> bucket_server_side_encryptionBucket server-side encryption configuration
<a name="output_policy"></a> policyDirect aws_iam_policy resource with all attributes
<a name="output_role"></a> roleDirect aws_iam_role resource with all attributes
<!-- END_TF_DOCS -->

Upgrading from versions below 6.0.0

Version 6.0.0 of this module uses the Hashicorp AWS Provider 4.0 as a minimum. AWS Provider 4.0 introduces some significant changes to the s3_bucket resources as documented here.

We have worked to make the change as seamless to your code as possible, but you should expect to update your value for Status from a boolean value of true | false to a string value of Enabled | Disabled.

Bucket policies

Regardless of whether a custom bucket policy is set as part of this module, we will always include policy statement to require the use of SecureTransport (SSL) for every action on and every resource within the bucket.

Replication

If replication is enabled then:

There are two ways to create the IAM role for replication:

Outputs

See the aws_s3_bucket attributes reference. This module outputs the resource map, i.e. aws_s3_bucket, so you can access each attribute from Terraform directly under the bucket output, e.g. module.s3-bucket.bucket.id for the bucket ID.

Looking for issues?

If you're looking to raise an issue with this module, please create a new issue in the Modernisation Platform repository.

S3 bucket versioning notes

S3 is not suitable to store application logs directly but is ok for archived logs

Every version is charged as an individual object

Versioning allows recovering files that are accidentally deleted

Versioning requires separate lifecycle management configuration

References

  1. Using versioning in S3 buckets
  2. https://serverfault.com/questions/116011/aws-where-should-we-store-images-css-and-log-files-of-the-application
  3. https://www.quora.com/What-is-the-best-way-to-send-application-logs-directly-to-S3
  4. How S3 Versioning works