From 3631fb57155ffb07aa5e9a35658b9d74bd14cda0 Mon Sep 17 00:00:00 2001 From: Mayank Sharma <83959396+mayank0202@users.noreply.github.com> Date: Tue, 13 Aug 2024 22:26:17 +0530 Subject: [PATCH] Addition of S3 bucket event notification resource and Addition of S3 directory optional resource (#240) * Addition of S3 bucket event notification resource and Addition of S3 directory optional resource * Ran Makefile * ran terraform fmt * comments resolved * added empty line --------- Co-authored-by: mayank0202 Co-authored-by: Andriy Knysh --- README.md | 5 +++++ docs/terraform.md | 5 +++++ main.tf | 48 +++++++++++++++++++++++++++++++++++++++++++++-- variables.tf | 40 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f407dca0..a1efe31a 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,7 @@ Available targets: | [aws_s3_bucket_cors_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_cors_configuration) | resource | | [aws_s3_bucket_lifecycle_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource | | [aws_s3_bucket_logging.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource | +| [aws_s3_bucket_notification.bucket_notification](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification) | resource | | [aws_s3_bucket_object_lock_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_object_lock_configuration) | resource | | [aws_s3_bucket_ownership_controls.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | | [aws_s3_bucket_policy.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | @@ -251,6 +252,7 @@ Available targets: | [aws_s3_bucket_versioning.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | | [aws_s3_bucket_website_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_website_configuration) | resource | | [aws_s3_bucket_website_configuration.redirect](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_website_configuration) | resource | +| [aws_s3_directory_bucket.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_directory_bucket) | resource | | [time_sleep.wait_for_aws_s3_bucket_settings](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [aws_canonical_user_id.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/canonical_user_id) | data source | | [aws_iam_policy_document.aggregated_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -270,16 +272,19 @@ Available targets: | [allow\_ssl\_requests\_only](#input\_allow\_ssl\_requests\_only) | Set to `true` to require requests to use Secure Socket Layer (HTTPS/SSL). This will explicitly deny access to HTTP requests | `bool` | `false` | no | | [allowed\_bucket\_actions](#input\_allowed\_bucket\_actions) | List of actions the user is permitted to perform on the S3 bucket | `list(string)` |
[
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload"
]
| no | | [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | +| [availability\_zone\_id](#input\_availability\_zone\_id) | The ID of the availability zone. | `string` | `null` | no | | [block\_public\_acls](#input\_block\_public\_acls) | Set to `false` to disable the blocking of new public access lists on the bucket | `bool` | `true` | no | | [block\_public\_policy](#input\_block\_public\_policy) | Set to `false` to disable the blocking of new public policies on the bucket | `bool` | `true` | no | | [bucket\_key\_enabled](#input\_bucket\_key\_enabled) | Set this to true to use Amazon S3 Bucket Keys for SSE-KMS, which may or may not reduce the number of AWS KMS requests.
For more information, see: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html | `bool` | `false` | no | | [bucket\_name](#input\_bucket\_name) | Bucket name. If provided, the bucket will be created with this name instead of generating the name from the context | `string` | `null` | no | | [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | | [cors\_configuration](#input\_cors\_configuration) | Specifies the allowed headers, methods, origins and exposed headers when using CORS on this bucket |
list(object({
id = optional(string)
allowed_headers = optional(list(string))
allowed_methods = optional(list(string))
allowed_origins = optional(list(string))
expose_headers = optional(list(string))
max_age_seconds = optional(number)
}))
| `[]` | no | +| [create\_s3\_directory\_bucket](#input\_create\_s3\_directory\_bucket) | Control the creation of the S3 directory bucket. Set to true to create the bucket, false to skip. | `bool` | `false` | no | | [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| [event\_notification\_details](#input\_event\_notification\_details) | (optional) S3 event notification details |
object({
enabled = bool
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
filter_prefix = string
filter_suffix = string
})), [])

queue_list = optional(list(object({
queue_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])

topic_list = optional(list(object({
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])

})
|
{
"enabled": false
}
| no | | [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | Account ID of the expected bucket owner.
More information: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html | `string` | `null` | no | | [force\_destroy](#input\_force\_destroy) | When `true`, permits a non-empty S3 bucket to be deleted by first deleting all objects in the bucket.
THESE OBJECTS ARE NOT RECOVERABLE even if they were versioned and stored in Glacier. | `bool` | `false` | no | | [grants](#input\_grants) | A list of policy grants for the bucket, taking a list of permissions.
Conflicts with `acl`. Set `acl` to `null` to use this.
Deprecated by AWS in favor of bucket policies.
Automatically disabled if `s3_object_ownership` is set to "BucketOwnerEnforced". |
list(object({
id = string
type = string
permissions = list(string)
uri = string
}))
| `[]` | no | diff --git a/docs/terraform.md b/docs/terraform.md index 571a4ffc..d8e7b9a3 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -34,6 +34,7 @@ | [aws_s3_bucket_cors_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_cors_configuration) | resource | | [aws_s3_bucket_lifecycle_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource | | [aws_s3_bucket_logging.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource | +| [aws_s3_bucket_notification.bucket_notification](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification) | resource | | [aws_s3_bucket_object_lock_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_object_lock_configuration) | resource | | [aws_s3_bucket_ownership_controls.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | | [aws_s3_bucket_policy.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | @@ -43,6 +44,7 @@ | [aws_s3_bucket_versioning.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | | [aws_s3_bucket_website_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_website_configuration) | resource | | [aws_s3_bucket_website_configuration.redirect](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_website_configuration) | resource | +| [aws_s3_directory_bucket.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_directory_bucket) | resource | | [time_sleep.wait_for_aws_s3_bucket_settings](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [aws_canonical_user_id.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/canonical_user_id) | data source | | [aws_iam_policy_document.aggregated_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -62,16 +64,19 @@ | [allow\_ssl\_requests\_only](#input\_allow\_ssl\_requests\_only) | Set to `true` to require requests to use Secure Socket Layer (HTTPS/SSL). This will explicitly deny access to HTTP requests | `bool` | `false` | no | | [allowed\_bucket\_actions](#input\_allowed\_bucket\_actions) | List of actions the user is permitted to perform on the S3 bucket | `list(string)` |
[
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload"
]
| no | | [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | +| [availability\_zone\_id](#input\_availability\_zone\_id) | The ID of the availability zone. | `string` | `null` | no | | [block\_public\_acls](#input\_block\_public\_acls) | Set to `false` to disable the blocking of new public access lists on the bucket | `bool` | `true` | no | | [block\_public\_policy](#input\_block\_public\_policy) | Set to `false` to disable the blocking of new public policies on the bucket | `bool` | `true` | no | | [bucket\_key\_enabled](#input\_bucket\_key\_enabled) | Set this to true to use Amazon S3 Bucket Keys for SSE-KMS, which may or may not reduce the number of AWS KMS requests.
For more information, see: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html | `bool` | `false` | no | | [bucket\_name](#input\_bucket\_name) | Bucket name. If provided, the bucket will be created with this name instead of generating the name from the context | `string` | `null` | no | | [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | | [cors\_configuration](#input\_cors\_configuration) | Specifies the allowed headers, methods, origins and exposed headers when using CORS on this bucket |
list(object({
id = optional(string)
allowed_headers = optional(list(string))
allowed_methods = optional(list(string))
allowed_origins = optional(list(string))
expose_headers = optional(list(string))
max_age_seconds = optional(number)
}))
| `[]` | no | +| [create\_s3\_directory\_bucket](#input\_create\_s3\_directory\_bucket) | Control the creation of the S3 directory bucket. Set to true to create the bucket, false to skip. | `bool` | `false` | no | | [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| [event\_notification\_details](#input\_event\_notification\_details) | (optional) S3 event notification details |
object({
enabled = bool
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
filter_prefix = string
filter_suffix = string
})), [])

queue_list = optional(list(object({
queue_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])

topic_list = optional(list(object({
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])

})
|
{
"enabled": false
}
| no | | [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | Account ID of the expected bucket owner.
More information: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html | `string` | `null` | no | | [force\_destroy](#input\_force\_destroy) | When `true`, permits a non-empty S3 bucket to be deleted by first deleting all objects in the bucket.
THESE OBJECTS ARE NOT RECOVERABLE even if they were versioned and stored in Glacier. | `bool` | `false` | no | | [grants](#input\_grants) | A list of policy grants for the bucket, taking a list of permissions.
Conflicts with `acl`. Set `acl` to `null` to use this.
Deprecated by AWS in favor of bucket policies.
Automatically disabled if `s3_object_ownership` is set to "BucketOwnerEnforced". |
list(object({
id = string
type = string
permissions = list(string)
uri = string
}))
| `[]` | no | diff --git a/main.tf b/main.tf index 8fb2ab42..ffefecbe 100644 --- a/main.tf +++ b/main.tf @@ -1,6 +1,7 @@ locals { - enabled = module.this.enabled - partition = join("", data.aws_partition.current[*].partition) + enabled = module.this.enabled + partition = join("", data.aws_partition.current[*].partition) + directory_bucket_name = var.create_s3_directory_bucket ? "${local.bucket_name}-${var.availability_zone_id}" : "" object_lock_enabled = local.enabled && var.object_lock_configuration != null replication_enabled = local.enabled && var.s3_replication_enabled @@ -579,3 +580,46 @@ resource "time_sleep" "wait_for_aws_s3_bucket_settings" { create_duration = "30s" destroy_duration = "30s" } +// S3 event Bucket Notifications +resource "aws_s3_bucket_notification" "bucket_notification" { + count = var.event_notification_details.enabled ? 1 : 0 + bucket = local.bucket_id + + dynamic "lambda_function" { + for_each = var.event_notification_details.lambda_list + content { + lambda_function_arn = lambda_function.value.arn + events = lambda.value.events + filter_prefix = lambda_function.value.filter_prefix + filter_suffix = lambda_function.value.filter_suffix + } + } + + dynamic "queue" { + for_each = var.event_notification_details.queue_list + content { + queue_arn = queue.value.queue_arn + events = queue.value.events + } + } + + dynamic "topic" { + for_each = var.event_notification_details.topic_list + content { + topic_arn = topic.value.topic_arn + events = topic.value.events + } + } +} + +/// Directory Bucket +// https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_directory_bucket +resource "aws_s3_directory_bucket" "default" { + count = var.create_s3_directory_bucket ? 1 : 0 + bucket = local.directory_bucket_name + force_destroy = var.force_destroy + + location { + name = var.availability_zone_id + } +} diff --git a/variables.tf b/variables.tf index 316fe91d..3b9e732b 100644 --- a/variables.tf +++ b/variables.tf @@ -465,4 +465,42 @@ variable "expected_bucket_owner" { Account ID of the expected bucket owner. More information: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html EOT -} \ No newline at end of file +} +variable "event_notification_details" { + type = object({ + enabled = bool + lambda_list = optional(list(object({ + lambda_function_arn = string + events = optional(list(string), ["s3:ObjectCreated:*"]) + filter_prefix = string + filter_suffix = string + })), []) + + queue_list = optional(list(object({ + queue_arn = string + events = optional(list(string), ["s3:ObjectCreated:*"]) + })), []) + + topic_list = optional(list(object({ + topic_arn = string + events = optional(list(string), ["s3:ObjectCreated:*"]) + })), []) + + }) + description = "(optional) S3 event notification details" + default = { + enabled = false + } +} + +variable "create_s3_directory_bucket" { + description = "Control the creation of the S3 directory bucket. Set to true to create the bucket, false to skip." + type = bool + default = false +} + +variable "availability_zone_id" { + description = "The ID of the availability zone." + type = string + default = "" +}