diff --git a/README.md b/README.md
index 846c50e..8311388 100644
--- a/README.md
+++ b/README.md
@@ -120,6 +120,36 @@ module "cis_alarms" {
AWS CloudTrail normally publishes logs into AWS CloudWatch Logs. This module creates log metric filters together with metric alarms according to [CIS AWS Foundations Benchmark v1.4.0 (05-28-2021)](https://www.cisecurity.org/benchmark/amazon_web_services/). Read more about [CIS AWS Foundations Controls](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cis-controls.html).
+### Log Group Data Protection Policy
+
+```hcl
+module "log_group_data_protection" {
+ source = "terraform-aws-modules/cloudwatch/aws//modules/log-data-protection-policy"
+ version = "~> 4.0"
+
+ log_group_name = "my-log-group"
+ create_log_data_protection_policy = true
+ log_data_protection_policy_name = "RedactAddress"
+
+ data_identifiers = ["arn:aws:dataprotection::aws:data-identifier/Address"]
+ findings_destination_cloudwatch_log_group = "audit-log-group"
+}
+```
+
+### Log Subscription Filter
+
+```hcl
+module "log_subscription_filter" {
+ source = "terraform-aws-modules/cloudwatch/aws//modules/log-subscription-filter"
+
+ name = "my-filter"
+ destination_arn = "arn:aws:firehose:eu-west-1:835367859852:deliverystream/cw-logs"
+ filter_pattern = "%test%"
+ log_group_name = "my-log-group"
+ role_arn = "arn:aws:iam::835367859852:role/cw-logs-to-firehose"
+}
+```
+
### Metric Stream
```hcl
@@ -234,6 +264,8 @@ module "log_account_policy" {
- [Cloudwatch query definition](https://github.com/terraform-aws-modules/terraform-aws-cloudwatch/tree/master/examples/query-definition)
- [Cloudwatch Metric Stream](https://github.com/terraform-aws-modules/terraform-aws-cloudwatch/tree/master/examples/metric-stream)
- [Cloudwatch Composite Alarm](https://github.com/terraform-aws-modules/terraform-aws-cloudwatch/tree/master/examples/composite-alarm)
+- [Cloudwatch log subscription filter](https://github.com/terraform-aws-modules/terraform-aws-cloudwatch/tree/master/examples/log-subscription-filter)
+- [Cloudwatch log data protection policy](https://github.com/terraform-aws-modules/terraform-aws-cloudwatch/tree/master/examples/log-group-with-data-protection-policy)
- [Cloudwatch Log Account Policy](https://github.com/terraform-aws-modules/terraform-aws-cloudwatch/tree/master/examples/log-account-policy)
diff --git a/examples/log-group-with-data-protection-policy/README.md b/examples/log-group-with-data-protection-policy/README.md
new file mode 100644
index 0000000..6417fbe
--- /dev/null
+++ b/examples/log-group-with-data-protection-policy/README.md
@@ -0,0 +1,39 @@
+# Complete Cloudwatch log group and data protection policy
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.0 |
+| [aws](#requirement\_aws) | >= 5.0 |
+
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [audit\_destination\_group](#module\_audit\_destination\_group) | ../../modules/log-group | n/a |
+| [custom\_data\_protection\_policy\_log\_group](#module\_custom\_data\_protection\_policy\_log\_group) | ../../modules/log-group | n/a |
+| [custom\_log\_data\_protection\_policy](#module\_custom\_log\_data\_protection\_policy) | ../../modules/log-data-protection-policy | n/a |
+| [log\_data\_protection\_policy](#module\_log\_data\_protection\_policy) | ../../modules/log-data-protection-policy | n/a |
+| [log\_group](#module\_log\_group) | ../../modules/log-group | n/a |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+No inputs.
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [cloudwatch\_log\_group\_arn](#output\_cloudwatch\_log\_group\_arn) | ARN of Cloudwatch log group |
+| [cloudwatch\_log\_group\_name](#output\_cloudwatch\_log\_group\_name) | Name of Cloudwatch log group |
+
diff --git a/examples/log-group-with-data-protection-policy/main.tf b/examples/log-group-with-data-protection-policy/main.tf
new file mode 100644
index 0000000..dd43255
--- /dev/null
+++ b/examples/log-group-with-data-protection-policy/main.tf
@@ -0,0 +1,84 @@
+provider "aws" {
+ region = "eu-west-1"
+}
+
+module "log_group" {
+ source = "../../modules/log-group"
+
+ name_prefix = "my-log-group-"
+ retention_in_days = 7
+}
+
+module "custom_data_protection_policy_log_group" {
+ source = "../../modules/log-group"
+
+ name_prefix = "my-custom-policy-log-group-"
+ retention_in_days = 7
+}
+
+
+module "audit_destination_group" {
+ source = "../../modules/log-group"
+
+ name_prefix = "audit-destination-log-group-"
+ retention_in_days = 7
+}
+
+module "log_data_protection_policy" {
+ source = "../../modules/log-data-protection-policy"
+
+ log_group_name = module.log_group.cloudwatch_log_group_name
+ create_log_data_protection_policy = true
+ log_data_protection_policy_name = "RedactAddress"
+
+ data_identifiers = ["arn:aws:dataprotection::aws:data-identifier/Address"]
+ findings_destination_cloudwatch_log_group = module.audit_destination_group.cloudwatch_log_group_name
+}
+
+module "custom_log_data_protection_policy" {
+ source = "../../modules/log-data-protection-policy"
+
+ log_group_name = module.custom_data_protection_policy_log_group.cloudwatch_log_group_name
+
+ # custom data identifier not yet supported by the data source for aws_cloudwatch_log_data_protection_policy within the module
+ # specify your own json policy document if this is needed
+ # https://github.com/hashicorp/terraform-provider-aws/issues/35682
+ policy_document = jsonencode({
+ Name = "RedactCustomerId"
+ Version = "2021-06-01"
+
+ Configuration = {
+ CustomDataIdentifier = [
+ {
+ Name = "CustomerId",
+ Regex = "CustomerId-\\d{5}"
+ }
+ ]
+ }
+
+ Statement = [
+ {
+ Sid = "Audit"
+ DataIdentifier = ["CustomerId"]
+ Operation = {
+ Audit = {
+ FindingsDestination = {
+ CloudWatchLogs = {
+ LogGroup = module.audit_destination_group.cloudwatch_log_group_name
+ }
+ }
+ }
+ }
+ },
+ {
+ Sid = "Redact"
+ DataIdentifier = ["CustomerId"]
+ Operation = {
+ Deidentify = {
+ MaskConfig = {}
+ }
+ }
+ }
+ ]
+ })
+}
diff --git a/examples/log-group-with-data-protection-policy/outputs.tf b/examples/log-group-with-data-protection-policy/outputs.tf
new file mode 100644
index 0000000..e11eab4
--- /dev/null
+++ b/examples/log-group-with-data-protection-policy/outputs.tf
@@ -0,0 +1,9 @@
+output "cloudwatch_log_group_name" {
+ description = "Name of Cloudwatch log group"
+ value = module.log_group.cloudwatch_log_group_name
+}
+
+output "cloudwatch_log_group_arn" {
+ description = "ARN of Cloudwatch log group"
+ value = module.log_group.cloudwatch_log_group_arn
+}
diff --git a/examples/log-group-with-data-protection-policy/variables.tf b/examples/log-group-with-data-protection-policy/variables.tf
new file mode 100644
index 0000000..e69de29
diff --git a/examples/log-group-with-data-protection-policy/versions.tf b/examples/log-group-with-data-protection-policy/versions.tf
new file mode 100644
index 0000000..ddfcb0e
--- /dev/null
+++ b/examples/log-group-with-data-protection-policy/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 5.0"
+ }
+ }
+}
diff --git a/modules/log-data-protection-policy/README.md b/modules/log-data-protection-policy/README.md
new file mode 100644
index 0000000..65d8994
--- /dev/null
+++ b/modules/log-data-protection-policy/README.md
@@ -0,0 +1,50 @@
+# log-data-protection-policy
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.0 |
+| [aws](#requirement\_aws) | >= 5.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 5.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_cloudwatch_log_data_protection_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_data_protection_policy) | resource |
+| [aws_cloudwatch_log_data_protection_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudwatch_log_data_protection_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [audit\_statement\_sid](#input\_audit\_statement\_sid) | Name of the audit statement. | `string` | `"audit-policy"` | no |
+| [create](#input\_create) | Whether to create the cloudwatch log data protection policy. | `bool` | `true` | no |
+| [create\_log\_data\_protection\_policy](#input\_create\_log\_data\_protection\_policy) | Whether to create the cloudwatch log data protection policy. | `bool` | `false` | no |
+| [data\_identifiers](#input\_data\_identifiers) | Set of at least 1 sensitive data identifiers that you want to mask. | `list(string)` | `null` | no |
+| [deidentify\_statement\_sid](#input\_deidentify\_statement\_sid) | Name of the deidentify statement. | `string` | `"redact-policy"` | no |
+| [findings\_destination\_cloudwatch\_log\_group](#input\_findings\_destination\_cloudwatch\_log\_group) | Configures CloudWatch Logs as a findings destination. | `string` | `null` | no |
+| [findings\_destination\_firehose\_delivery\_stream](#input\_findings\_destination\_firehose\_delivery\_stream) | Configures Kinesis Firehose as a findings destination. | `string` | `null` | no |
+| [findings\_destination\_s3\_bucket](#input\_findings\_destination\_s3\_bucket) | Configures S3 as a findings destination. | `string` | `null` | no |
+| [log\_data\_protection\_description](#input\_log\_data\_protection\_description) | The description of the data protection policy document. | `string` | `null` | no |
+| [log\_data\_protection\_policy\_name](#input\_log\_data\_protection\_policy\_name) | The name of the data protection policy document. | `string` | `null` | no |
+| [log\_group\_name](#input\_log\_group\_name) | The name of the log group under which the log stream is to be created. | `string` | `null` | no |
+| [policy\_document](#input\_policy\_document) | Specifies the data protection policy in JSON. | `string` | `null` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [log\_group\_name](#output\_log\_group\_name) | Name of Cloudwatch log group |
+
diff --git a/modules/log-data-protection-policy/main.tf b/modules/log-data-protection-policy/main.tf
new file mode 100644
index 0000000..8360a10
--- /dev/null
+++ b/modules/log-data-protection-policy/main.tf
@@ -0,0 +1,60 @@
+resource "aws_cloudwatch_log_data_protection_policy" "this" {
+ count = var.create ? 1 : 0
+
+ log_group_name = var.log_group_name
+ policy_document = var.create_log_data_protection_policy ? data.aws_cloudwatch_log_data_protection_policy_document.this[0].json : var.policy_document
+}
+
+data "aws_cloudwatch_log_data_protection_policy_document" "this" {
+ count = var.create && var.create_log_data_protection_policy ? 1 : 0
+
+ name = var.log_data_protection_policy_name
+ description = var.log_data_protection_description
+
+ statement {
+ sid = var.audit_statement_sid
+ data_identifiers = var.data_identifiers
+
+ operation {
+ audit {
+ findings_destination {
+
+ dynamic "cloudwatch_logs" {
+ for_each = var.findings_destination_cloudwatch_log_group != null ? [true] : []
+
+ content {
+ log_group = var.findings_destination_cloudwatch_log_group
+ }
+ }
+
+ dynamic "firehose" {
+ for_each = var.findings_destination_firehose_delivery_stream != null ? [true] : []
+
+ content {
+ delivery_stream = var.findings_destination_firehose_delivery_stream
+ }
+ }
+
+ dynamic "s3" {
+ for_each = var.findings_destination_s3_bucket != null ? [true] : []
+
+ content {
+ bucket = var.findings_destination_s3_bucket
+ }
+ }
+ }
+ }
+ }
+ }
+
+ statement {
+ sid = var.deidentify_statement_sid
+ data_identifiers = var.data_identifiers
+
+ operation {
+ deidentify {
+ mask_config {}
+ }
+ }
+ }
+}
diff --git a/modules/log-data-protection-policy/outputs.tf b/modules/log-data-protection-policy/outputs.tf
new file mode 100644
index 0000000..dda9933
--- /dev/null
+++ b/modules/log-data-protection-policy/outputs.tf
@@ -0,0 +1,4 @@
+output "log_group_name" {
+ description = "Name of Cloudwatch log group"
+ value = var.log_group_name
+}
diff --git a/modules/log-data-protection-policy/variables.tf b/modules/log-data-protection-policy/variables.tf
new file mode 100644
index 0000000..0e1a65c
--- /dev/null
+++ b/modules/log-data-protection-policy/variables.tf
@@ -0,0 +1,71 @@
+variable "create" {
+ description = "Whether to create the cloudwatch log data protection policy."
+ type = bool
+ default = true
+}
+
+variable "create_log_data_protection_policy" {
+ description = "Whether to create the cloudwatch log data protection policy."
+ type = bool
+ default = false
+}
+
+variable "log_group_name" {
+ description = "The name of the log group under which the log stream is to be created."
+ type = string
+ default = null
+}
+
+variable "policy_document" {
+ description = "Specifies the data protection policy in JSON."
+ type = string
+ default = null
+}
+
+variable "log_data_protection_policy_name" {
+ description = "The name of the data protection policy document."
+ type = string
+ default = null
+}
+
+variable "log_data_protection_description" {
+ description = "The description of the data protection policy document."
+ type = string
+ default = null
+}
+
+variable "audit_statement_sid" {
+ description = "Name of the audit statement."
+ type = string
+ default = "audit-policy"
+}
+
+variable "deidentify_statement_sid" {
+ description = "Name of the deidentify statement."
+ type = string
+ default = "redact-policy"
+}
+
+variable "data_identifiers" {
+ description = "Set of at least 1 sensitive data identifiers that you want to mask."
+ type = list(string)
+ default = null
+}
+
+variable "findings_destination_cloudwatch_log_group" {
+ description = "Configures CloudWatch Logs as a findings destination."
+ type = string
+ default = null
+}
+
+variable "findings_destination_firehose_delivery_stream" {
+ description = "Configures Kinesis Firehose as a findings destination."
+ type = string
+ default = null
+}
+
+variable "findings_destination_s3_bucket" {
+ description = "Configures S3 as a findings destination."
+ type = string
+ default = null
+}
diff --git a/modules/log-data-protection-policy/versions.tf b/modules/log-data-protection-policy/versions.tf
new file mode 100644
index 0000000..ddfcb0e
--- /dev/null
+++ b/modules/log-data-protection-policy/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 5.0"
+ }
+ }
+}
diff --git a/wrappers/log-data-protection-policy/README.md b/wrappers/log-data-protection-policy/README.md
new file mode 100644
index 0000000..0d9a0d0
--- /dev/null
+++ b/wrappers/log-data-protection-policy/README.md
@@ -0,0 +1,100 @@
+# Wrapper for module: `modules/log-data-protection-policy`
+
+The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt).
+
+You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module.
+
+This wrapper does not implement any extra functionality.
+
+## Usage with Terragrunt
+
+`terragrunt.hcl`:
+
+```hcl
+terraform {
+ source = "tfr:///terraform-aws-modules/cloudwatch/aws//wrappers/log-data-protection-policy"
+ # Alternative source:
+ # source = "git::git@github.com:terraform-aws-modules/terraform-aws-cloudwatch.git//wrappers/log-data-protection-policy?ref=master"
+}
+
+inputs = {
+ defaults = { # Default values
+ create = true
+ tags = {
+ Terraform = "true"
+ Environment = "dev"
+ }
+ }
+
+ items = {
+ my-item = {
+ # omitted... can be any argument supported by the module
+ }
+ my-second-item = {
+ # omitted... can be any argument supported by the module
+ }
+ # omitted...
+ }
+}
+```
+
+## Usage with Terraform
+
+```hcl
+module "wrapper" {
+ source = "terraform-aws-modules/cloudwatch/aws//wrappers/log-data-protection-policy"
+
+ defaults = { # Default values
+ create = true
+ tags = {
+ Terraform = "true"
+ Environment = "dev"
+ }
+ }
+
+ items = {
+ my-item = {
+ # omitted... can be any argument supported by the module
+ }
+ my-second-item = {
+ # omitted... can be any argument supported by the module
+ }
+ # omitted...
+ }
+}
+```
+
+## Example: Manage multiple S3 buckets in one Terragrunt layer
+
+`eu-west-1/s3-buckets/terragrunt.hcl`:
+
+```hcl
+terraform {
+ source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers"
+ # Alternative source:
+ # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master"
+}
+
+inputs = {
+ defaults = {
+ force_destroy = true
+
+ attach_elb_log_delivery_policy = true
+ attach_lb_log_delivery_policy = true
+ attach_deny_insecure_transport_policy = true
+ attach_require_latest_tls_policy = true
+ }
+
+ items = {
+ bucket1 = {
+ bucket = "my-random-bucket-1"
+ }
+ bucket2 = {
+ bucket = "my-random-bucket-2"
+ tags = {
+ Secure = "probably"
+ }
+ }
+ }
+}
+```
diff --git a/wrappers/log-data-protection-policy/main.tf b/wrappers/log-data-protection-policy/main.tf
new file mode 100644
index 0000000..61bdb98
--- /dev/null
+++ b/wrappers/log-data-protection-policy/main.tf
@@ -0,0 +1,18 @@
+module "wrapper" {
+ source = "../../modules/log-data-protection-policy"
+
+ for_each = var.items
+
+ audit_statement_sid = try(each.value.audit_statement_sid, var.defaults.audit_statement_sid, "audit-policy")
+ create = try(each.value.create, var.defaults.create, true)
+ create_log_data_protection_policy = try(each.value.create_log_data_protection_policy, var.defaults.create_log_data_protection_policy, false)
+ data_identifiers = try(each.value.data_identifiers, var.defaults.data_identifiers, null)
+ deidentify_statement_sid = try(each.value.deidentify_statement_sid, var.defaults.deidentify_statement_sid, "redact-policy")
+ findings_destination_cloudwatch_log_group = try(each.value.findings_destination_cloudwatch_log_group, var.defaults.findings_destination_cloudwatch_log_group, null)
+ findings_destination_firehose_delivery_stream = try(each.value.findings_destination_firehose_delivery_stream, var.defaults.findings_destination_firehose_delivery_stream, null)
+ findings_destination_s3_bucket = try(each.value.findings_destination_s3_bucket, var.defaults.findings_destination_s3_bucket, null)
+ log_data_protection_description = try(each.value.log_data_protection_description, var.defaults.log_data_protection_description, null)
+ log_data_protection_policy_name = try(each.value.log_data_protection_policy_name, var.defaults.log_data_protection_policy_name, null)
+ log_group_name = try(each.value.log_group_name, var.defaults.log_group_name, null)
+ policy_document = try(each.value.policy_document, var.defaults.policy_document, null)
+}
diff --git a/wrappers/log-data-protection-policy/outputs.tf b/wrappers/log-data-protection-policy/outputs.tf
new file mode 100644
index 0000000..ec6da5f
--- /dev/null
+++ b/wrappers/log-data-protection-policy/outputs.tf
@@ -0,0 +1,5 @@
+output "wrapper" {
+ description = "Map of outputs of a wrapper."
+ value = module.wrapper
+ # sensitive = false # No sensitive module output found
+}
diff --git a/wrappers/log-data-protection-policy/variables.tf b/wrappers/log-data-protection-policy/variables.tf
new file mode 100644
index 0000000..a6ea096
--- /dev/null
+++ b/wrappers/log-data-protection-policy/variables.tf
@@ -0,0 +1,11 @@
+variable "defaults" {
+ description = "Map of default values which will be used for each item."
+ type = any
+ default = {}
+}
+
+variable "items" {
+ description = "Maps of items to create a wrapper from. Values are passed through to the module."
+ type = any
+ default = {}
+}
diff --git a/wrappers/log-data-protection-policy/versions.tf b/wrappers/log-data-protection-policy/versions.tf
new file mode 100644
index 0000000..51cad10
--- /dev/null
+++ b/wrappers/log-data-protection-policy/versions.tf
@@ -0,0 +1,3 @@
+terraform {
+ required_version = ">= 0.13.1"
+}