{"id":19107133,"url":"https://github.com/govtechsg/terraform-s3-generic","last_synced_at":"2025-08-09T23:04:08.242Z","repository":{"id":40773178,"uuid":"420350610","full_name":"GovTechSG/terraform-s3-generic","owner":"GovTechSG","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-27T14:12:15.000Z","size":46,"stargazers_count":0,"open_issues_count":2,"forks_count":2,"subscribers_count":53,"default_branch":"master","last_synced_at":"2025-03-27T15:25:30.093Z","etag":null,"topics":["terraform"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GovTechSG.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-23T08:00:35.000Z","updated_at":"2025-03-27T14:10:48.000Z","dependencies_parsed_at":"2024-11-06T10:47:33.550Z","dependency_job_id":"4b2f7ed4-dc19-4025-8bf4-7ab5370a942f","html_url":"https://github.com/GovTechSG/terraform-s3-generic","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/GovTechSG/terraform-s3-generic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fterraform-s3-generic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fterraform-s3-generic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fterraform-s3-generic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fterraform-s3-generic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GovTechSG","download_url":"https://codeload.github.com/GovTechSG/terraform-s3-generic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GovTechSG%2Fterraform-s3-generic/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269649848,"owners_count":24453541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-09T02:00:10.424Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["terraform"],"created_at":"2024-11-09T04:11:23.962Z","updated_at":"2025-08-09T23:04:08.217Z","avatar_url":"https://github.com/GovTechSG.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# s3-generic\n\nCreates a s3 bucket with policies to allow using it, for attaching to other roles/users\n## Example\n\n```hcl\nmodule \"s3-generic\" {\n  source = \"../..//\"\n  object_ownership = \"BucketOwnerEnforced\" # Optional, defaults to BucketOwnerEnforced\n  s3_buckets = {\n    backups = {\n      bucket               = \"my-backups\"\n      permissions_boundary = \"arn:aws:iam::${get_aws_account_id()}:policy/MyBoundary\"\n      region               = \"ap-southeast-1\"\n      acl                  = \"private\"\n      object_ownership     = \"BucketOwnerPreferred\" # Optional, overrides the module-level setting\n      log_bucket_for_s3    = \"my-access-logs\"\n      malware_protection   = true                   # Optional, enables GuardDuty Malware Protection for this bucket\n      policies = [jsonencode(\n        {\n          \"Version\" : \"2012-10-17\",\n          \"Statement\" : [\n            {\n              Action : \"s3:GetBucketAcl\",\n              Effect : \"Allow\",\n              Resource : \"arn:aws:s3:::my-backups\",\n              Principal : { \"Service\" : \"logs.ap-southeast-1.amazonaws.com\" }\n            },\n            {\n              Action : \"s3:PutObject\",\n              Effect : \"Allow\",\n              Resource : \"arn:aws:s3:::my-backups/**\",\n              Condition : { \"StringEquals\" : { \"s3:x-amz-acl\" : \"bucket-owner-full-control\" } },\n              Principal : { \"Service\" : \"logs.ap-southeast-1.amazonaws.com\" }\n            }\n          ]\n        }\n      )]\n      server_side_encryption_configuration = {\n        rule = {\n          bucket_key_enabled = true\n          apply_server_side_encryption_by_default = {\n            sse_algorithm = \"aws:kms\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n## Features\n\n### GuardDuty Malware Protection\n\nWhen `malware_protection = true` is set for a bucket, this module will:\n\n1. Create a dedicated IAM role with the appropriate permissions for GuardDuty to scan objects\n2. Configure an AWS GuardDuty Malware Protection Plan to monitor the bucket\n3. Enable object tagging to mark scanned objects\n\nThe IAM role follows the principle of least privilege with permissions based on AWS recommended policies for GuardDuty Malware Protection.\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| \u003ca name=\"input_force_destroy\"\u003e\u003c/a\u003e [force\\_destroy](#input\\_force\\_destroy) | When destroying this user, destroy even if it has non-Terraform-managed IAM access keys, login profile or MFA devices. Without force\\_destroy a user with non-Terraform-managed access keys and login profile will fail to be destroyed. | `bool` | `false` | no |\n| \u003ca name=\"input_path\"\u003e\u003c/a\u003e [path](#input\\_path) | Desired path for the IAM user | `string` | `\"/\"` | no |\n| \u003ca name=\"input_s3_buckets\"\u003e\u003c/a\u003e [s3\\_buckets](#input\\_s3\\_buckets) | A map of bucket names to an object describing the S3 bucket settings for the bucket. | \u003cpre\u003emap(object({ \u003c/br\u003e    bucket                               = string \u003c/br\u003e    permissions_boundary                 = string \u003c/br\u003e    region                               = string \u003c/br\u003e    acl                                  = optional(string) \u003c/br\u003e    log_bucket_for_s3                    = optional(string) \u003c/br\u003e    object_ownership                     = optional(string) \u003c/br\u003e    malware_protection                   = optional(bool, false) \u003c/br\u003e    policies                             = list(string) \u003c/br\u003e    server_side_encryption_configuration = any \u003c/br\u003e    cors_configuration = optional( \u003c/br\u003e      list( \u003c/br\u003e        object({ \u003c/br\u003e          allowed_methods = list(string) \u003c/br\u003e          allowed_origins = list(string) \u003c/br\u003e          allowed_headers = optional(list(string)) \u003c/br\u003e          expose_headers  = optional(list(string)) \u003c/br\u003e          max_age_seconds = optional(number) \u003c/br\u003e          id              = optional(string) \u003c/br\u003e        }) \u003c/br\u003e      ) \u003c/br\u003e    ) \u003c/br\u003e    lifecycle_rules = optional(list(object({ \u003c/br\u003e      id      = optional(string) \u003c/br\u003e      enabled = optional(bool, true) \u003c/br\u003e      filter = optional(object({ \u003c/br\u003e        prefix                   = optional(string) \u003c/br\u003e        object_size_greater_than = optional(number) \u003c/br\u003e        object_size_less_than    = optional(number) \u003c/br\u003e        tags                     = optional(map(string)) \u003c/br\u003e      })) \u003c/br\u003e      transition = optional(list(object({ \u003c/br\u003e        days          = optional(number) \u003c/br\u003e        date          = optional(string) \u003c/br\u003e        storage_class = string \u003c/br\u003e      }))) \u003c/br\u003e    }))) \u003c/br\u003e  })) \u003c/br\u003e\u003c/pre\u003e | no |\n| \u003ca name=\"input_tags\"\u003e\u003c/a\u003e [tags](#input\\_tags) | (Optional) A mapping of tags to assign to the bucket. | `map(string)` | `{}` | no |\n| \u003ca name=\"input_object_ownership\"\u003e\u003c/a\u003e [object\\_ownership](#input\\_object\\_ownership) | (Optional) Default object ownership setting for all buckets. Can be overridden at the bucket level using the `object_ownership` property in the bucket configuration. Valid values: BucketOwnerEnforced, BucketOwnerPreferred or ObjectWriter | `string` | `\"BucketOwnerEnforced\"` | no |\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| \u003ca name=\"output_role\"\u003e\u003c/a\u003e [role](#output\\_role) | The role which has access to the bucket |\n| \u003ca name=\"output_s3_buckets\"\u003e\u003c/a\u003e [s3_buckets](#output\\_s3_buckets) | The names of the bucket. |\n\n\u003c!-- BEGIN_TF_DOCS --\u003e\n\n\n## Example\n\n```hcl\nmodule \"s3-generic\" {\n  source = \"../..//\"\n  s3_buckets = {\n    backups = {\n      bucket               = \"my-backups\"\n      permissions_boundary = \"arn:aws:iam::${get_aws_account_id()}:policy/MyBoundary\"\n      region               = \"ap-southeast-1\"\n      acl                  = \"private\"\n      log_bucket_for_s3    = \"my-access-logs\"\n      policies = [jsonencode(\n        {\n          \"Version\" : \"2012-10-17\",\n          \"Statement\" : [\n            {\n              Action : \"s3:GetBucketAcl\",\n              Effect : \"Allow\",\n              Resource : \"arn:aws:s3:::my-backups\",\n              Principal : { \"Service\" : \"logs.ap-southeast-1.amazonaws.com\" }\n            },\n            {\n              Action : \"s3:PutObject\",\n              Effect : \"Allow\",\n              Resource : \"arn:aws:s3:::my-backups/**\",\n              Condition : { \"StringEquals\" : { \"s3:x-amz-acl\" : \"bucket-owner-full-control\" } },\n              Principal : { \"Service\" : \"logs.ap-southeast-1.amazonaws.com\" }\n            }\n          ]\n        }\n      )]\n      server_side_encryption_configuration = {\n        rule = {\n          bucket_key_enabled = true\n          apply_server_side_encryption_by_default = {\n            sse_algorithm = \"aws:kms\"\n          }\n        }\n      }\n      lifecycle_rules = [\n        {\n          id      = \"backup-lifecycle-rule\"\n          enabled = true\n          filter = {\n            object_size_greater_than = 0\n          }\n          transition = [\n            {\n              days          = 30\n              storage_class = \"STANDARD_IA\"\n            },\n            {\n              days          = 60\n              storage_class = \"GLACIER\"\n            },\n            {\n              days          = 150\n              storage_class = \"DEEP_ARCHIVE\"\n            }\n          ]\n          noncurrent_version_transition = [\n            {\n              noncurrent_days = 30\n              storage_class   = \"STANDARD_IA\"\n            },\n            {\n              noncurrent_days = 60\n              storage_class   = \"GLACIER\"\n            },\n            {\n              noncurrent_days = 150\n              storage_class   = \"DEEP_ARCHIVE\"\n            }\n          ]\n          expiration = {\n            days = 183\n          }\n          noncurrent_version_expiration = {\n            noncurrent_days = 151\n          }\n        }\n      ]\n    }\n  }\n}\n```\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| \u003ca name=\"input_force_destroy\"\u003e\u003c/a\u003e [force\\_destroy](#input\\_force\\_destroy) | When destroying this user, destroy even if it has non-Terraform-managed IAM access keys, login profile or MFA devices. Without force\\_destroy a user with non-Terraform-managed access keys and login profile will fail to be destroyed. | `bool` | `false` | no |\n| \u003ca name=\"input_object_lock_enabled\"\u003e\u003c/a\u003e [object\\_lock\\_enabled](#input\\_object\\_lock\\_enabled) | (Optional) Enable object lock for the S3 bucket | `bool` | `false` | no |\n| \u003ca name=\"input_object_ownership\"\u003e\u003c/a\u003e [object\\_ownership](#input\\_object\\_ownership) | (Optional) Object ownership. Valid values: BucketOwnerEnforced, BucketOwnerPreferred or ObjectWriter | `string` | `\"BucketOwnerEnforced\"` | no |\n| \u003ca name=\"input_path\"\u003e\u003c/a\u003e [path](#input\\_path) | Desired path for the IAM user | `string` | `\"/\"` | no |\n| \u003ca name=\"input_s3_buckets\"\u003e\u003c/a\u003e [s3\\_buckets](#input\\_s3\\_buckets) | A map of bucket names to an object describing the S3 bucket settings for the bucket. | \u003cpre\u003emap(object({\u003cbr/\u003e    bucket                               = string\u003cbr/\u003e    permissions_boundary                 = string\u003cbr/\u003e    region                               = string\u003cbr/\u003e    acl                                  = optional(string)\u003cbr/\u003e    log_bucket_for_s3                    = optional(string)\u003cbr/\u003e    object_ownership                     = optional(string)\u003cbr/\u003e    policies                             = list(string)\u003cbr/\u003e    server_side_encryption_configuration = any\u003cbr/\u003e    malware_protection                   = optional(bool, false)\u003cbr/\u003e    malware_protection_prefix            = optional(list(string))\u003cbr/\u003e    cors_configuration = optional(\u003cbr/\u003e      list(\u003cbr/\u003e        object({\u003cbr/\u003e          allowed_methods = list(string)\u003cbr/\u003e          allowed_origins = list(string)\u003cbr/\u003e          allowed_headers = optional(list(string))\u003cbr/\u003e          expose_headers  = optional(list(string))\u003cbr/\u003e          max_age_seconds = optional(number)\u003cbr/\u003e          id              = optional(string)\u003cbr/\u003e        })\u003cbr/\u003e      )\u003cbr/\u003e    )\u003cbr/\u003e    lifecycle_rules = optional(list(object({\u003cbr/\u003e      id      = optional(string)\u003cbr/\u003e      enabled = optional(bool, true)\u003cbr/\u003e      filter = optional(object({\u003cbr/\u003e        prefix                   = optional(string)\u003cbr/\u003e        object_size_greater_than = optional(number)\u003cbr/\u003e        object_size_less_than    = optional(number)\u003cbr/\u003e        tags                     = optional(map(string))\u003cbr/\u003e      }))\u003cbr/\u003e      transition = optional(list(object({\u003cbr/\u003e        days          = optional(number)\u003cbr/\u003e        date          = optional(string)\u003cbr/\u003e        storage_class = string\u003cbr/\u003e      })))\u003cbr/\u003e      expiration = optional(object({\u003cbr/\u003e        date                         = optional(string)\u003cbr/\u003e        days                         = optional(number)\u003cbr/\u003e        expired_object_delete_marker = optional(bool)\u003cbr/\u003e      }))\u003cbr/\u003e      noncurrent_version_expiration = optional(object({\u003cbr/\u003e        noncurrent_days           = optional(number)\u003cbr/\u003e        newer_noncurrent_versions = optional(number)\u003cbr/\u003e      }))\u003cbr/\u003e      noncurrent_version_transition = optional(list(object({\u003cbr/\u003e        noncurrent_days           = optional(number)\u003cbr/\u003e        newer_noncurrent_versions = optional(number)\u003cbr/\u003e        storage_class             = string\u003cbr/\u003e      })))\u003cbr/\u003e      abort_incomplete_multipart_upload_days = optional(number)\u003cbr/\u003e    })))\u003cbr/\u003e  }))\u003c/pre\u003e | \u003cpre\u003e{\u003cbr/\u003e  \"main\": {\u003cbr/\u003e    \"bucket\": \"\",\u003cbr/\u003e    \"log_bucket_for_s3\": \"\",\u003cbr/\u003e    \"malware_protection\": false,\u003cbr/\u003e    \"malware_protection_prefix\": [],\u003cbr/\u003e    \"permissions_boundary\": \"\",\u003cbr/\u003e    \"policies\": [],\u003cbr/\u003e    \"region\": \"ap-southeast-1\",\u003cbr/\u003e    \"server_side_encryption_configuration\": {\u003cbr/\u003e      \"rule\": {\u003cbr/\u003e        \"apply_server_side_encryption_by_default\": {\u003cbr/\u003e          \"sse_algorithm\": \"AES256\"\u003cbr/\u003e        }\u003cbr/\u003e      }\u003cbr/\u003e    }\u003cbr/\u003e  }\u003cbr/\u003e}\u003c/pre\u003e | no |\n| \u003ca name=\"input_tags\"\u003e\u003c/a\u003e [tags](#input\\_tags) | (Optional) A mapping of tags to assign to the bucket. | `map(string)` | `{}` | no |\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| \u003ca name=\"output_role\"\u003e\u003c/a\u003e [role](#output\\_role) | The role which has access to the bucket |\n| \u003ca name=\"output_s3_buckets\"\u003e\u003c/a\u003e [s3\\_buckets](#output\\_s3\\_buckets) | The names of the bucket. |\n\u003c!-- END_TF_DOCS --\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgovtechsg%2Fterraform-s3-generic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgovtechsg%2Fterraform-s3-generic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgovtechsg%2Fterraform-s3-generic/lists"}