https://github.com/govtechsg/terraform-s3-generic
https://github.com/govtechsg/terraform-s3-generic
terraform
Last synced: 10 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/govtechsg/terraform-s3-generic
- Owner: GovTechSG
- License: mit
- Created: 2021-10-23T08:00:35.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2025-03-27T14:12:15.000Z (about 1 year ago)
- Last Synced: 2025-03-27T15:25:30.093Z (about 1 year ago)
- Topics: terraform
- Language: HCL
- Homepage:
- Size: 44.9 KB
- Stars: 0
- Watchers: 53
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# s3-generic
Creates a s3 bucket with policies to allow using it, for attaching to other roles/users
## Example
```hcl
module "s3-generic" {
source = "../..//"
object_ownership = "BucketOwnerEnforced" # Optional, defaults to BucketOwnerEnforced
s3_buckets = {
backups = {
bucket = "my-backups"
permissions_boundary = "arn:aws:iam::${get_aws_account_id()}:policy/MyBoundary"
region = "ap-southeast-1"
acl = "private"
object_ownership = "BucketOwnerPreferred" # Optional, overrides the module-level setting
log_bucket_for_s3 = "my-access-logs"
malware_protection = true # Optional, enables GuardDuty Malware Protection for this bucket
policies = [jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
Action : "s3:GetBucketAcl",
Effect : "Allow",
Resource : "arn:aws:s3:::my-backups",
Principal : { "Service" : "logs.ap-southeast-1.amazonaws.com" }
},
{
Action : "s3:PutObject",
Effect : "Allow",
Resource : "arn:aws:s3:::my-backups/**",
Condition : { "StringEquals" : { "s3:x-amz-acl" : "bucket-owner-full-control" } },
Principal : { "Service" : "logs.ap-southeast-1.amazonaws.com" }
}
]
}
)]
server_side_encryption_configuration = {
rule = {
bucket_key_enabled = true
apply_server_side_encryption_by_default = {
sse_algorithm = "aws:kms"
}
}
}
}
}
}
```
## Features
### GuardDuty Malware Protection
When `malware_protection = true` is set for a bucket, this module will:
1. Create a dedicated IAM role with the appropriate permissions for GuardDuty to scan objects
2. Configure an AWS GuardDuty Malware Protection Plan to monitor the bucket
3. Enable object tagging to mark scanned objects
The IAM role follows the principle of least privilege with permissions based on AWS recommended policies for GuardDuty Malware Protection.
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [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 |
| [path](#input\_path) | Desired path for the IAM user | `string` | `"/"` | no |
| [s3\_buckets](#input\_s3\_buckets) | A map of bucket names to an object describing the S3 bucket settings for the bucket. |
map(object({ bucket = string permissions_boundary = string region = string acl = optional(string) log_bucket_for_s3 = optional(string) object_ownership = optional(string) malware_protection = optional(bool, false) policies = list(string) server_side_encryption_configuration = any cors_configuration = optional( list( object({ allowed_methods = list(string) allowed_origins = list(string) allowed_headers = optional(list(string)) expose_headers = optional(list(string)) max_age_seconds = optional(number) id = optional(string) }) ) ) lifecycle_rules = optional(list(object({ id = optional(string) enabled = optional(bool, true) filter = optional(object({ prefix = optional(string) object_size_greater_than = optional(number) object_size_less_than = optional(number) tags = optional(map(string)) })) transition = optional(list(object({ days = optional(number) date = optional(string) storage_class = string }))) }))) })) | no |
| [tags](#input\_tags) | (Optional) A mapping of tags to assign to the bucket. | `map(string)` | `{}` | no |
| [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 |
## Outputs
| Name | Description |
|------|-------------|
| [role](#output\_role) | The role which has access to the bucket |
| [s3_buckets](#output\_s3_buckets) | The names of the bucket. |
## Example
```hcl
module "s3-generic" {
source = "../..//"
s3_buckets = {
backups = {
bucket = "my-backups"
permissions_boundary = "arn:aws:iam::${get_aws_account_id()}:policy/MyBoundary"
region = "ap-southeast-1"
acl = "private"
log_bucket_for_s3 = "my-access-logs"
policies = [jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
Action : "s3:GetBucketAcl",
Effect : "Allow",
Resource : "arn:aws:s3:::my-backups",
Principal : { "Service" : "logs.ap-southeast-1.amazonaws.com" }
},
{
Action : "s3:PutObject",
Effect : "Allow",
Resource : "arn:aws:s3:::my-backups/**",
Condition : { "StringEquals" : { "s3:x-amz-acl" : "bucket-owner-full-control" } },
Principal : { "Service" : "logs.ap-southeast-1.amazonaws.com" }
}
]
}
)]
server_side_encryption_configuration = {
rule = {
bucket_key_enabled = true
apply_server_side_encryption_by_default = {
sse_algorithm = "aws:kms"
}
}
}
lifecycle_rules = [
{
id = "backup-lifecycle-rule"
enabled = true
filter = {
object_size_greater_than = 0
}
transition = [
{
days = 30
storage_class = "STANDARD_IA"
},
{
days = 60
storage_class = "GLACIER"
},
{
days = 150
storage_class = "DEEP_ARCHIVE"
}
]
noncurrent_version_transition = [
{
noncurrent_days = 30
storage_class = "STANDARD_IA"
},
{
noncurrent_days = 60
storage_class = "GLACIER"
},
{
noncurrent_days = 150
storage_class = "DEEP_ARCHIVE"
}
]
expiration = {
days = 183
}
noncurrent_version_expiration = {
noncurrent_days = 151
}
}
]
}
}
}
```
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [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 |
| [object\_lock\_enabled](#input\_object\_lock\_enabled) | (Optional) Enable object lock for the S3 bucket | `bool` | `false` | no |
| [object\_ownership](#input\_object\_ownership) | (Optional) Object ownership. Valid values: BucketOwnerEnforced, BucketOwnerPreferred or ObjectWriter | `string` | `"BucketOwnerEnforced"` | no |
| [path](#input\_path) | Desired path for the IAM user | `string` | `"/"` | no |
| [s3\_buckets](#input\_s3\_buckets) | A map of bucket names to an object describing the S3 bucket settings for the bucket. |
map(object({
bucket = string
permissions_boundary = string
region = string
acl = optional(string)
log_bucket_for_s3 = optional(string)
object_ownership = optional(string)
policies = list(string)
server_side_encryption_configuration = any
malware_protection = optional(bool, false)
malware_protection_prefix = optional(list(string))
cors_configuration = optional(
list(
object({
allowed_methods = list(string)
allowed_origins = list(string)
allowed_headers = optional(list(string))
expose_headers = optional(list(string))
max_age_seconds = optional(number)
id = optional(string)
})
)
)
lifecycle_rules = optional(list(object({
id = optional(string)
enabled = optional(bool, true)
filter = optional(object({
prefix = optional(string)
object_size_greater_than = optional(number)
object_size_less_than = optional(number)
tags = optional(map(string))
}))
transition = optional(list(object({
days = optional(number)
date = optional(string)
storage_class = string
})))
expiration = optional(object({
date = optional(string)
days = optional(number)
expired_object_delete_marker = optional(bool)
}))
noncurrent_version_expiration = optional(object({
noncurrent_days = optional(number)
newer_noncurrent_versions = optional(number)
}))
noncurrent_version_transition = optional(list(object({
noncurrent_days = optional(number)
newer_noncurrent_versions = optional(number)
storage_class = string
})))
abort_incomplete_multipart_upload_days = optional(number)
})))
})) | {
"main": {
"bucket": "",
"log_bucket_for_s3": "",
"malware_protection": false,
"malware_protection_prefix": [],
"permissions_boundary": "",
"policies": [],
"region": "ap-southeast-1",
"server_side_encryption_configuration": {
"rule": {
"apply_server_side_encryption_by_default": {
"sse_algorithm": "AES256"
}
}
}
}
} | no |
| [tags](#input\_tags) | (Optional) A mapping of tags to assign to the bucket. | `map(string)` | `{}` | no |
## Outputs
| Name | Description |
|------|-------------|
| [role](#output\_role) | The role which has access to the bucket |
| [s3\_buckets](#output\_s3\_buckets) | The names of the bucket. |