diff --git a/modules/cloudtrail-event-data-store/README.md b/modules/cloudtrail-event-data-store/README.md index 1ab98b7..3d08c7f 100644 --- a/modules/cloudtrail-event-data-store/README.md +++ b/modules/cloudtrail-event-data-store/README.md @@ -12,14 +12,14 @@ This module creates following resources. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.5 | -| [aws](#requirement\_aws) | >= 4.53 | +| [terraform](#requirement\_terraform) | >= 1.6 | +| [aws](#requirement\_aws) | >= 5.25 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.19.0 | +| [aws](#provider\_aws) | 5.48.0 | ## Modules @@ -40,9 +40,10 @@ This module creates following resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [management\_event\_selector](#input\_management\_event\_selector) | (Optional) A configuration of management event selector to use to select the events for the event data store. Only used if `event_type` is `CLOUDTRAIL_EVENTS`. `management_event_selector` block as defined below.
(Optional) `enabled` - Whether to capture management events. Defaults to `false`.
(Optional) `scope` - The type of events to log. Valid values are `ALL`, `READ` and `WRITE`. Defaults to `ALL`.
(Optional) `exclude_event_sources` - A set of event sources to exclude. Valid values are `kms.amazonaws.com` and `rdsdata.amazonaws.com`. `management_event_selector.enabled` must be set to true to allow this. |
object({
enabled = optional(bool, false)
scope = optional(string, "ALL")
exclude_event_sources = optional(set(string), [])
})
| n/a | yes | | [name](#input\_name) | (Required) The name of the event data store. | `string` | n/a | yes | +| [data\_event\_selectors](#input\_data\_event\_selectors) | (Optional) A configuration of event selectors to use to select the data events for the event data store. Each item of `data_event_selectors` block as defined below.
(Optional) `name` - A name of the advanced event selector.
(Optional) `resource_type` - A resource type to log data events to log. Valid values are one of the following:
- `AWS::DynamoDB::Table`
- `AWS::Lambda::Function`
- `AWS::S3::Object`
- `AWS::AppConfig::Configuration`
- `AWS::B2BI::Transformer`
- `AWS::Bedrock::AgentAlias`
- `AWS::Bedrock::KnowledgeBase`
- `AWS::Cassandra::Table`
- `AWS::CloudFront::KeyValueStore`
- `AWS::CloudTrail::Channel`
- `AWS::CodeWhisperer::Customization`
- `AWS::CodeWhisperer::Profile`
- `AWS::Cognito::IdentityPool`
- `AWS::DynamoDB::Stream`
- `AWS::EC2::Snapshot`
- `AWS::EMRWAL::Workspace`
- `AWS::FinSpace::Environment`
- `AWS::Glue::Table`
- `AWS::GreengrassV2::ComponentVersion`
- `AWS::GreengrassV2::Deployment`
- `AWS::GuardDuty::Detector`
- `AWS::IoT::Certificate`
- `AWS::IoT::Thing`
- `AWS::IoTSiteWise::Asset`
- `AWS::IoTSiteWise::TimeSeries`
- `AWS::IoTTwinMaker::Entity`
- `AWS::IoTTwinMaker::Workspace`
- `AWS::KendraRanking::ExecutionPlan`
- `AWS::KinesisVideo::Stream`
- `AWS::ManagedBlockchain::Network`
- `AWS::ManagedBlockchain::Node`
- `AWS::MedicalImaging::Datastore`
- `AWS::NeptuneGraph::Graph`
- `AWS::PCAConnectorAD::Connector`
- `AWS::QBusiness::Application`
- `AWS::QBusiness::DataSource`
- `AWS::QBusiness::Index`
- `AWS::QBusiness::WebExperience`
- `AWS::RDS::DBCluster`
- `AWS::S3::AccessPoint`
- `AWS::S3ObjectLambda::AccessPoint`
- `AWS::S3Outposts::Object`
- `AWS::SageMaker::Endpoint`
- `AWS::SageMaker::ExperimentTrialComponent`
- `AWS::SageMaker::FeatureGroup`
- `AWS::ServiceDiscovery::Namespace`
- `AWS::ServiceDiscovery::Service`
- `AWS::SCN::Instance`
- `AWS::SNS::PlatformEndpoint`
- `AWS::SNS::Topic`
- `AWS::SWF::Domain`
- `AWS::SQS::Queue`
- `AWS::SSMMessages::ControlChannel`
- `AWS::ThinClient::Device`
- `AWS::ThinClient::Environment`
- `AWS::Timestream::Database`
- `AWS::Timestream::Table`
- `AWS::VerifiedPermissions::PolicyStore`
(Optional) `scope` - The type of events to log. Valid values are `ALL`, `READ` and `WRITE`. Defaults to `WRITE`.
(Optional) `conditions` - A configuration of field conditions to filter events by the ARN of resource and the event name. Each item of `conditions` as defined below.
(Required) `field` - A field to compare by the field condition. Valid values are `event_name` and `resource_arn`.
(Required) `operator` - An operator of the field condition. Valid values are `equals`, `not_equals`, `starts_with`, `not_starts_with`, `ends_with`, `not_ends_with`.
(Required) `values` - A set of values of the field condition to compare. |
list(object({
name = optional(string)
resource_type = string
scope = optional(string, "WRITE")
conditions = optional(list(object({
field = string
operator = string
values = set(string)
})), [])
}))
| `[]` | no | | [encryption\_kms\_key](#input\_encryption\_kms\_key) | (Optional) Specify the KMS key ID to use to encrypt the events delivered by CloudTrail. The value can be an alias name prefixed by 'alias/', a fully specified ARN to an alias, a fully specified ARN to a key, or a globally unique identifier. By default, the event data store is encrypted with a KMS key that AWS owns and manages. | `string` | `null` | no | -| [event\_selectors](#input\_event\_selectors) | (Optional) A configuration of event selectors to use to select the events for the event data store. Only used if `event_type` is `CLOUDTRAIL_EVENTS`. Each item of `event_selectors` as defined below.
(Required) `category` - A category of the event. Valid values are `DATA` and `MANAGEMENT`.
- `DATA`: Log the resource operations performed on or within a resource.
- `MANAGEMENT`: Capture management operations performed on your AWS resources.
(Optional) `scope` - A scope of events to log. Valid values are `ALL`, `READ` and `WRITE`. Defaults to `ALL`.
(Optional) `exclude_sources` - A set of event sources to exclude. Valid values are `kms.amazonaws.com` and `rdsdata.amazonaws.com`. Only used if `category` is `MANAGEMENT`.
(Optional) `resource_type` - The resource type to log data events to log. Required if `category` is `DATA`. Valid values are one of the following:
- `AWS::S3::Object`
- `AWS::Lambda::Function`
- `AWS::DynamoDB::Table`
- `AWS::S3Outposts::Object`
- `AWS::ManagedBlockchain::Node`
- `AWS::S3ObjectLambda::AccessPoint`
- `AWS::EC2::Snapshot`
- `AWS::S3::AccessPoint`
- `AWS::CloudTrail::Channe`l
- `AWS::DynamoDB::Stream`
- `AWS::Glue::Table`
- `AWS::FinSpace::Environmen`t
- `AWS::SageMaker::ExperimentTrialComponen`t
- `AWS::SageMaker::FeatureGrou`p
(Optional) `selectors` - A configuration of field selectors to filter events by the ARN of resource and the event name. Each item of `selectors` as defined below.
(Required) `field` - A field to compare by the field selector. Valid values are `event_name` and `resource_arn`.
(Required) `operator` - An operator of the field selector. Valid values are `equals`, `not_equals`, `starts_with`, `not_starts_with`, `ends_with`, `not_ends_with`.
(Required) `values` - A set of values of the field selector to compare. |
list(object({
category = string
scope = optional(string, "ALL")
exclude_sources = optional(set(string), [])
resource_type = optional(string)
selectors = optional(list(object({
field = string
operator = string
values = set(string)
})), [])
}))
|
[
{
"category": "MANAGEMENT"
}
]
| no | | [event\_type](#input\_event\_type) | (Required) A type of event to be collected by the event data store. Valid values are `CLOUDTRAIL_EVENTS`, `CONFIG_CONFIGURATION_ITEMS`. Defaults to `CLOUDTRAIL_EVENTS`. | `string` | `"CLOUDTRAIL_EVENTS"` | no | | [import\_trail\_events\_iam\_role](#input\_import\_trail\_events\_iam\_role) | (Optional) A configuration of IAM Role for importing CloudTrail events from S3 Bucket. `import_trail_events_iam_role` as defined below.
(Optional) `enabled` - Indicates whether you want to create IAM Role to import trail events. Defaults to `true`.
(Optional) `source_s3_buckets` - A list of source S3 buckets to import events from. Each item of `source_s3_buckets` as defined below.
(Required) `name` - A name of source S3 bucket.
(Optional) `key_prefix` - A key prefix of source S3 bucket. |
object({
enabled = optional(bool, true)
source_s3_buckets = optional(list(object({
name = string
key_prefix = optional(string, "/")
})), [])
})
| `{}` | no | | [level](#input\_level) | (Optional) The level of the event data store to decide whether the event data store collects events logged for an organization in AWS Organizations. Can be created in the management account or delegated administrator account. Valid values are `ACCOUNT` and `ORGANIZATION`. Defaults to `ACCOUNT`. | `string` | `"ACCOUNT"` | no | @@ -60,12 +61,13 @@ This module creates following resources. | Name | Description | |------|-------------| | [arn](#output\_arn) | The Amazon Resource Name (ARN) of the event data store. | +| [data\_event\_selectors](#output\_data\_event\_selectors) | The event selectors to use to select the data events for the event data store. | | [encryption](#output\_encryption) | The configuration for the encryption of the event data store. | -| [event\_selectors](#output\_event\_selectors) | The event selectors to use to select the events for the event data store. | | [event\_type](#output\_event\_type) | The type of event to be collected by the event data store. | | [id](#output\_id) | The ID of the event data store. | | [import\_trail\_events\_iam\_role](#output\_import\_trail\_events\_iam\_role) | A configuration of IAM Role for importing CloudTrail events from S3 Bucket. | | [level](#output\_level) | The level of the event data store to decide whether the event data store collects events logged for an organization in AWS Organizations. | +| [management\_event\_selector](#output\_management\_event\_selector) | The event selector to use to select the management events for the event data store. | | [name](#output\_name) | The name of the event data store. | | [retention\_in\_days](#output\_retention\_in\_days) | The retention period of the event data store, in days. | | [scope](#output\_scope) | The scope of the event data store to decide whether the event data store includes events from all regions, or only from the region in which the event data store is created. | diff --git a/modules/cloudtrail-event-data-store/main.tf b/modules/cloudtrail-event-data-store/main.tf index 7d855da..63d3b6a 100644 --- a/modules/cloudtrail-event-data-store/main.tf +++ b/modules/cloudtrail-event-data-store/main.tf @@ -24,7 +24,7 @@ locals { "READ" = "ReadOnly" "WRITE" = "WriteOnly" } - event_selector_fields = { + condition_fields = { "event_name" = "eventName" "resource_arn" = "resources.ARN" } @@ -47,62 +47,86 @@ resource "aws_cloudtrail_event_data_store" "this" { # kms_key_id = var.encryption_kms_key - ## Event Selector - AWS CloudTrail Events + ## Event Selector - AWS CloudTrail Events (Management) dynamic "advanced_event_selector" { - for_each = var.event_type == "CLOUDTRAIL_EVENTS" ? var.event_selectors : [] - iterator = event + for_each = var.event_type == "CLOUDTRAIL_EVENTS" && var.management_event_selector.enabled ? [var.management_event_selector] : [] + iterator = selector content { - name = "AWS CloudTrail Events - ${local.event_categories[event.value.category]}" + name = "AWS CloudTrail Events - Management" field_selector { field = "eventCategory" - equals = [local.event_categories[event.value.category]] + equals = ["Management"] } dynamic "field_selector" { - for_each = event.value.scope != "ALL" ? ["go"] : [] + for_each = selector.value.scope != "ALL" ? ["go"] : [] content { field = "readOnly" equals = [{ "READ" = "true" "WRITE" = "false" - }[event.value.scope]] + }[selector.value.scope]] } } dynamic "field_selector" { - for_each = (event.value.category == "MANAGEMENT" && length(event.value.exclude_sources) > 0) ? ["go"] : [] + for_each = (length(selector.value.exclude_event_sources) > 0) ? ["go"] : [] content { field = "eventSource" - not_equals = event.value.exclude_sources + not_equals = selector.value.exclude_event_sources } } + } + } + + + ## Event Selector - AWS CloudTrail Events (Data) + dynamic "advanced_event_selector" { + for_each = var.event_type == "CLOUDTRAIL_EVENTS" ? var.data_event_selectors : [] + iterator = selector + + content { + name = coalesce(selector.value.name, "AWS CloudTrail Events - Data ${selector.key}") + + field_selector { + field = "eventCategory" + equals = ["Data"] + } + + field_selector { + field = "resources.type" + equals = [selector.value.resource_type] + } dynamic "field_selector" { - for_each = event.value.category == "DATA" ? ["go"] : [] + for_each = selector.value.scope != "ALL" ? ["go"] : [] content { - field = "resources.type" - equals = [event.value.resource_type] + field = "readOnly" + equals = [{ + "READ" = "true" + "WRITE" = "false" + }[selector.value.scope]] } } dynamic "field_selector" { - for_each = length(event.value.selectors) > 0 ? event.value.selectors : [] - iterator = selector + for_each = length(selector.value.conditions) > 0 ? selector.value.conditions : [] + iterator = condition content { - field = local.event_selector_fields[selector.value.field] - - equals = selector.value.operator == "equals" ? selector.value.values : null - not_equals = selector.value.operator == "not_equals" ? selector.value.values : null - starts_with = selector.value.operator == "starts_with" ? selector.value.values : null - not_starts_with = selector.value.operator == "not_starts_with" ? selector.value.values : null - ends_with = selector.value.operator == "ends_with" ? selector.value.values : null - not_ends_with = selector.value.operator == "not_ends_with" ? selector.value.values : null + field = local.condition_fields[condition.value.field] + + equals = condition.value.operator == "equals" ? condition.value.values : null + not_equals = condition.value.operator == "not_equals" ? condition.value.values : null + starts_with = condition.value.operator == "starts_with" ? condition.value.values : null + not_starts_with = condition.value.operator == "not_starts_with" ? condition.value.values : null + ends_with = condition.value.operator == "ends_with" ? condition.value.values : null + not_ends_with = condition.value.operator == "not_ends_with" ? condition.value.values : null } } } diff --git a/modules/cloudtrail-event-data-store/outputs.tf b/modules/cloudtrail-event-data-store/outputs.tf index 1c7c000..6bdd9e1 100644 --- a/modules/cloudtrail-event-data-store/outputs.tf +++ b/modules/cloudtrail-event-data-store/outputs.tf @@ -27,9 +27,14 @@ output "event_type" { value = var.event_type } -output "event_selectors" { - description = "The event selectors to use to select the events for the event data store." - value = var.event_selectors +output "management_event_selector" { + description = "The event selector to use to select the management events for the event data store." + value = var.management_event_selector +} + +output "data_event_selectors" { + description = "The event selectors to use to select the data events for the event data store." + value = var.data_event_selectors } output "encryption" { diff --git a/modules/cloudtrail-event-data-store/variables.tf b/modules/cloudtrail-event-data-store/variables.tf index 518719b..7026da0 100644 --- a/modules/cloudtrail-event-data-store/variables.tf +++ b/modules/cloudtrail-event-data-store/variables.tf @@ -40,109 +40,142 @@ variable "event_type" { } } -variable "event_selectors" { +variable "management_event_selector" { description = < [terraform](#requirement\_terraform) | >= 1.5 | -| [aws](#requirement\_aws) | >= 4.14 | +| [terraform](#requirement\_terraform) | >= 1.6 | +| [aws](#requirement\_aws) | >= 5.25 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.19.0 | +| [aws](#provider\_aws) | 5.48.0 | ## Modules | Name | Source | Version | |------|--------|---------| | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | -| [role](#module\_role) | tedilabs/account/aws//modules/iam-role | ~> 0.23.0 | +| [role](#module\_role) | tedilabs/account/aws//modules/iam-role | ~> 0.29.0 | ## Resources @@ -34,6 +34,7 @@ This module creates following resources. |------|------| | [aws_cloudtrail.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudtrail) | resource | | [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudwatch_log_group) | data source | | [aws_iam_policy_document.cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_organizations_organization.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | | [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | @@ -43,16 +44,13 @@ This module creates following resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [delivery\_s3\_bucket](#input\_delivery\_s3\_bucket) | (Required) The name of the S3 bucket designated for publishing log files. | `string` | n/a | yes | +| [delivery\_channels](#input\_delivery\_channels) | (Required) A configuration for the delivery channels of the trail. `delivery_channels` as defined below.
(Required) `s3_bucket` - A configuration for the S3 Bucket delivery channel. `s3_bucket` as defined below.
(Required) `name` - The name of the S3 bucket used to publish log files.
(Optional) `key_prefix` - The key prefix for the specified S3 bucket.
(Optional) `integrity_validation_enabled` - To determine whether a log file was modified, deleted, or unchanged after AWS CloudTrail delivered it, use CloudTrail log file integrity validation. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing. Defaults to `true`.
(Optional) `sse_kms_key` - The ARN of the AWS KMS key used to encrypt objects delivered by AWS Config. Must belong to the same Region as the destination S3 bucket.
(Optional) `sns_topic` - A configuration for the SNS Topic notifications for log file delivery. CloudTrail stores multiple events in a log file. When you enable this option, Amazon SNS notifications are sent for every log file delivery to your S3 bucket, not for every event. `sns_topic` as defined below.
(Optional) `enabled` - Whether to enable the SNS Topic notifications for log file delivery. Defaults to `false`.
(Optional) `name` - The name of the SNS topic for notification of log file delivery.
(Optional) `cloudwatch_log_group` - A configuration for the log group of CloudWatch Logs to send events to CloudWatch Logs. `cloudwatch_log_group` as defined below.
(Optional) `enabled` - Whether to send CloudTrail events to CloudWatch Logs. Defaults to `false`.
(Optional) `name` - The name of the log group of CloudWatch Logs. |
object({
s3_bucket = object({
name = string
key_prefix = optional(string, "")
integrity_validation_enabled = optional(bool, true)
sse_kms_key = optional(string)
})
sns_topic = optional(object({
enabled = optional(bool, false)
name = optional(string)
}), {})
cloudwatch_log_group = optional(object({
enabled = optional(bool, false)
name = optional(string)
# iam_role = optional(string)
}), {})
})
| n/a | yes | +| [management\_event\_selector](#input\_management\_event\_selector) | (Required) A configuration block for management events logging to identify API activity for individual resources, or for all current and future resources in AWS account. `management_event_selector` block as defined below.
(Required) `enabled` - Whether the trail to log management events.
(Optional) `scope` - The type of events to log. Valid values are `ALL`, `READ` and `WRITE`. Defaults to `ALL`.
(Optional) `exclude_event_sources` - A set of event sources to exclude. Valid values are `kms.amazonaws.com` and `rdsdata.amazonaws.com`. `management_event_selector.enabled` must be set to true to allow this. |
object({
enabled = bool
scope = optional(string, "ALL")
exclude_event_sources = optional(set(string), [])
})
| n/a | yes | | [name](#input\_name) | (Required) The name of the trail. The name can only contain uppercase letters, lowercase letters, numbers, periods (.), hyphens (-), and underscores (\_). | `string` | n/a | yes | -| [delivery\_cloudwatch\_logs\_log\_group](#input\_delivery\_cloudwatch\_logs\_log\_group) | (Optional) The name of the log group of CloudWatch Logs for log file delivery. | `string` | `null` | no | -| [delivery\_s3\_integrity\_validation\_enabled](#input\_delivery\_s3\_integrity\_validation\_enabled) | (Optional) To determine whether a log file was modified, deleted, or unchanged after AWS CloudTrail delivered it, use CloudTrail log file integrity validation. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing. | `bool` | `true` | no | -| [delivery\_s3\_key\_prefix](#input\_delivery\_s3\_key\_prefix) | (Optional) The key prefix for the specified S3 bucket. | `string` | `null` | no | -| [delivery\_sns\_topic](#input\_delivery\_sns\_topic) | (Optional) The name of the SNS topic for notification of log file delivery. | `string` | `null` | no | +| [data\_event\_selectors](#input\_data\_event\_selectors) | (Optional) A list of configurations for data events logging the resource operations performed on or within a resource. Each item of `data_event_selectors` block as defined below.
(Optional) `name` - A name of the advanced event selector.
(Optional) `resource_type` - A resource type to log data events to log. Valid values are one of the following:
- `AWS::DynamoDB::Table`
- `AWS::Lambda::Function`
- `AWS::S3::Object`
- `AWS::AppConfig::Configuration`
- `AWS::B2BI::Transformer`
- `AWS::Bedrock::AgentAlias`
- `AWS::Bedrock::KnowledgeBase`
- `AWS::Cassandra::Table`
- `AWS::CloudFront::KeyValueStore`
- `AWS::CloudTrail::Channel`
- `AWS::CodeWhisperer::Customization`
- `AWS::CodeWhisperer::Profile`
- `AWS::Cognito::IdentityPool`
- `AWS::DynamoDB::Stream`
- `AWS::EC2::Snapshot`
- `AWS::EMRWAL::Workspace`
- `AWS::FinSpace::Environment`
- `AWS::Glue::Table`
- `AWS::GreengrassV2::ComponentVersion`
- `AWS::GreengrassV2::Deployment`
- `AWS::GuardDuty::Detector`
- `AWS::IoT::Certificate`
- `AWS::IoT::Thing`
- `AWS::IoTSiteWise::Asset`
- `AWS::IoTSiteWise::TimeSeries`
- `AWS::IoTTwinMaker::Entity`
- `AWS::IoTTwinMaker::Workspace`
- `AWS::KendraRanking::ExecutionPlan`
- `AWS::KinesisVideo::Stream`
- `AWS::ManagedBlockchain::Network`
- `AWS::ManagedBlockchain::Node`
- `AWS::MedicalImaging::Datastore`
- `AWS::NeptuneGraph::Graph`
- `AWS::PCAConnectorAD::Connector`
- `AWS::QBusiness::Application`
- `AWS::QBusiness::DataSource`
- `AWS::QBusiness::Index`
- `AWS::QBusiness::WebExperience`
- `AWS::RDS::DBCluster`
- `AWS::S3::AccessPoint`
- `AWS::S3ObjectLambda::AccessPoint`
- `AWS::S3Outposts::Object`
- `AWS::SageMaker::Endpoint`
- `AWS::SageMaker::ExperimentTrialComponent`
- `AWS::SageMaker::FeatureGroup`
- `AWS::ServiceDiscovery::Namespace`
- `AWS::ServiceDiscovery::Service`
- `AWS::SCN::Instance`
- `AWS::SNS::PlatformEndpoint`
- `AWS::SNS::Topic`
- `AWS::SWF::Domain`
- `AWS::SQS::Queue`
- `AWS::SSMMessages::ControlChannel`
- `AWS::ThinClient::Device`
- `AWS::ThinClient::Environment`
- `AWS::Timestream::Database`
- `AWS::Timestream::Table`
- `AWS::VerifiedPermissions::PolicyStore`
(Optional) `scope` - The type of events to log. Valid values are `ALL`, `READ` and `WRITE`. Defaults to `WRITE`.
(Optional) `conditions` - A configuration of field conditions to filter events by the ARN of resource and the event name. Each item of `conditions` as defined below.
(Required) `field` - A field to compare by the field condition. Valid values are `event_name` and `resource_arn`.
(Required) `operator` - An operator of the field condition. Valid values are `equals`, `not_equals`, `starts_with`, `not_starts_with`, `ends_with`, `not_ends_with`.
(Required) `values` - A set of values of the field condition to compare. |
list(object({
name = optional(string)
resource_type = string
scope = optional(string, "WRITE")
conditions = optional(list(object({
field = string
operator = string
values = set(string)
})), [])
}))
| `[]` | no | | [enabled](#input\_enabled) | (Optional) Whether the trail starts the recording of AWS API calls and log file delivery. Defaults to `true`. | `bool` | `true` | no | -| [insight\_event](#input\_insight\_event) | (Optional) A configuration block for insight events logging to identify unusual operational activity. `insight_event` block as defined below.
(Required) `enabled` - Whether the trail to log insight events.
(Optional) `scopes` - A set of insight types to log on the trail. Valid values are `API_CALL_RATE` and `API_ERROR_RATE`. |
object({
enabled = optional(bool, false)
scopes = optional(set(string), [])
})
| `{}` | no | +| [insight\_event\_selector](#input\_insight\_event\_selector) | (Optional) A configuration block for insight events logging to identify unusual operational activity. `insight_event_selector` block as defined below.
(Optional) `enabled` - Whether the trail to log insight events. Defaults to `false`.
(Optional) `scopes` - A set of insight types to log on the trail. Valid values are `API_CALL_RATE` and `API_ERROR_RATE`. |
object({
enabled = optional(bool, false)
scopes = optional(set(string), [])
})
| `{}` | no | | [level](#input\_level) | (Optional) The level of the trail to decide whether the trail is an AWS Organizations trail. Organization trails log events for the master account and all member accounts. Can only be created in the organization master account. Valid values are `ACCOUNT` and `ORGANIZATION`. Use `ORGANIZATION` level in Organization master account. Defaults to `ACCOUNT`. | `string` | `"ACCOUNT"` | no | -| [management\_event](#input\_management\_event) | (Optional) A configuration block for management events logging to identify API activity for individual resources, or for all current and future resources in AWS account. `management_event` block as defined below.
(Required) `enabled` - Whether the trail to log management events.
(Optional) `scope` - The type of events to log. Valid values are `ALL`, `READ` and `WRITE`. Defaults to `ALL`.
(Optional) `exclude_event_sources` - A set of event sources to exclude. Valid values are `kms.amazonaws.com` and `rdsdata.amazonaws.com`. `management_event.enabled` must be set to true to allow this. |
object({
enabled = bool
scope = string
exclude_event_sources = list(string)
})
|
{
"enabled": true,
"exclude_event_sources": [],
"scope": "ALL"
}
| no | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | @@ -65,14 +63,15 @@ This module creates following resources. | Name | Description | |------|-------------| | [arn](#output\_arn) | The Amazon Resource Name (ARN) of the trail. | -| [delivery\_channels](#output\_delivery\_channels) | Delivery channels of the trail. | +| [data\_event](#output\_data\_event) | A list of selectors for data events of the trail. | +| [delivery\_channels](#output\_delivery\_channels) | The configurations for the delivery channels of the trail. | | [enabled](#output\_enabled) | Whether the trail is enabled. | | [home\_region](#output\_home\_region) | The region in which the trail was created. | | [iam\_role](#output\_iam\_role) | The IAM Role for the CloudTrail trail. | | [id](#output\_id) | The ID of the trail. | -| [insight\_event](#output\_insight\_event) | A configuration for insight events logging of the trail. | +| [insight\_event](#output\_insight\_event) | A selector for insight events of the trail. | | [level](#output\_level) | The level of the trail to decide whether the trail is an AWS Organizations trail. | -| [management\_event](#output\_management\_event) | A configuration for management events logging of the trail. | +| [management\_event](#output\_management\_event) | A selector for management events of the trail. | | [name](#output\_name) | The name of the trail. | | [scope](#output\_scope) | The scope of the trail to decide whether the trail is multi-region trail. | diff --git a/modules/cloudtrail-trail/iam.tf b/modules/cloudtrail-trail/iam.tf index 22d963a..f12e0fc 100644 --- a/modules/cloudtrail-trail/iam.tf +++ b/modules/cloudtrail-trail/iam.tf @@ -9,21 +9,26 @@ data "aws_organizations_organization" "this" {} ################################################### module "role" { - count = var.delivery_cloudwatch_logs_log_group != null ? 1 : 0 + count = var.delivery_channels.cloudwatch_log_group.enabled ? 1 : 0 source = "tedilabs/account/aws//modules/iam-role" - version = "~> 0.23.0" + version = "~> 0.29.0" name = "cloudtrail-${local.metadata.name}" path = "/" description = "Role for the CloudTrail trail(${local.metadata.name})" - trusted_services = ["cloudtrail.amazonaws.com"] + trusted_service_policies = [ + { + services = ["cloudtrail.amazonaws.com"] + } + ] inline_policies = { "cloudwatch" = one(data.aws_iam_policy_document.cloudwatch[*].json) } + force_detach_policies = true resource_group_enabled = false module_tags_enabled = false @@ -44,12 +49,12 @@ locals { account_id = data.aws_caller_identity.this.account_id org_id = data.aws_organizations_organization.this.id - cloudwatch_log_group_arn = var.delivery_cloudwatch_logs_log_group != null ? "arn:${local.partition}:logs:${local.region}:${local.account_id}:log-group:${var.delivery_cloudwatch_logs_log_group}" : null + cloudwatch_log_group_arn = var.delivery_channels.cloudwatch_log_group.enabled ? "arn:${local.partition}:logs:${local.region}:${local.account_id}:log-group:${var.delivery_channels.cloudwatch_log_group.name}" : null } data "aws_iam_policy_document" "cloudwatch" { - count = var.delivery_cloudwatch_logs_log_group != null ? 1 : 0 + count = var.delivery_channels.cloudwatch_log_group.enabled ? 1 : 0 statement { sid = "CreateLogStream" diff --git a/modules/cloudtrail-trail/main.tf b/modules/cloudtrail-trail/main.tf index 616f3e5..ff47305 100644 --- a/modules/cloudtrail-trail/main.tf +++ b/modules/cloudtrail-trail/main.tf @@ -14,6 +14,12 @@ locals { } : {} } +data "aws_cloudwatch_log_group" "this" { + count = (var.delivery_channels.cloudwatch_log_group.enabled ? 1 : 0) + + name = var.delivery_channels.cloudwatch_log_group.name +} + locals { management_types = { "ALL" = "All" @@ -24,6 +30,10 @@ locals { "API_CALL_RATE" = "ApiCallRateInsight" "API_ERROR_RATE" = "ApiErrorRateInsight" } + condition_fields = { + "event_name" = "eventName" + "resource_arn" = "resources.ARN" + } } @@ -31,6 +41,8 @@ locals { # Trail on CloudTrail ################################################### +# INFO: Not supported attributes +# - `event_selector` resource "aws_cloudtrail" "this" { name = var.name enable_logging = var.enabled @@ -39,37 +51,125 @@ resource "aws_cloudtrail" "this" { is_organization_trail = var.level == "ORGANIZATION" include_global_service_events = var.scope != "REGIONAL" - ## Encryption - # kms_key_id ## Delivery - S3 - s3_bucket_name = var.delivery_s3_bucket - s3_key_prefix = var.delivery_s3_key_prefix - enable_log_file_validation = var.delivery_s3_integrity_validation_enabled + s3_bucket_name = var.delivery_channels.s3_bucket.name + s3_key_prefix = var.delivery_channels.s3_bucket.key_prefix + enable_log_file_validation = var.delivery_channels.s3_bucket.integrity_validation_enabled + kms_key_id = var.delivery_channels.s3_bucket.sse_kms_key + ## Delivery - SNS - sns_topic_name = var.delivery_sns_topic + sns_topic_name = (var.delivery_channels.sns_topic.enabled + ? var.delivery_channels.sns_topic.name + : null + ) + ## Delivery - CloudWatch Logs - cloud_watch_logs_group_arn = var.delivery_cloudwatch_logs_log_group != null ? "${local.cloudwatch_log_group_arn}:*" : null - cloud_watch_logs_role_arn = var.delivery_cloudwatch_logs_log_group != null ? one(module.role[*].arn) : null + cloud_watch_logs_group_arn = (var.delivery_channels.cloudwatch_log_group.enabled + ? data.aws_cloudwatch_log_group.this[0].arn + : null + ) + cloud_watch_logs_role_arn = (var.delivery_channels.cloudwatch_log_group.enabled + ? one(module.role[*].arn) + : null + ) + ## Event Selector - Management Events - event_selector { - include_management_events = var.management_event.enabled - read_write_type = local.management_types[var.management_event.scope] - exclude_management_event_sources = var.management_event.exclude_event_sources + dynamic "advanced_event_selector" { + for_each = var.management_event_selector.enabled ? [var.management_event_selector] : [] + iterator = selector + + content { + name = "AWS CloudTrail Management Events" + + field_selector { + field = "eventCategory" + equals = ["Management"] + } + + dynamic "field_selector" { + for_each = selector.value.scope != "ALL" ? ["go"] : [] + + content { + field = "readOnly" + equals = [{ + "READ" = "true" + "WRITE" = "false" + }[selector.value.scope]] + } + } + + dynamic "field_selector" { + for_each = (length(selector.value.exclude_event_sources) > 0) ? ["go"] : [] + + content { + field = "eventSource" + not_equals = selector.value.exclude_event_sources + } + } + } } + ## Event Selector - Data Events - # advanced_event_selector + dynamic "advanced_event_selector" { + for_each = var.data_event_selectors + iterator = selector + + content { + name = coalesce(selector.value.name, "AWS CloudTrail Data Events ${selector.key}") + + field_selector { + field = "eventCategory" + equals = ["Data"] + } + + field_selector { + field = "resources.type" + equals = [selector.value.resource_type] + } + + dynamic "field_selector" { + for_each = selector.value.scope != "ALL" ? ["go"] : [] + + content { + field = "readOnly" + equals = [{ + "READ" = "true" + "WRITE" = "false" + }[selector.value.scope]] + } + } + + dynamic "field_selector" { + for_each = length(selector.value.conditions) > 0 ? selector.value.conditions : [] + iterator = condition + + content { + field = local.condition_fields[condition.value.field] + + equals = condition.value.operator == "equals" ? condition.value.values : null + not_equals = condition.value.operator == "not_equals" ? condition.value.values : null + starts_with = condition.value.operator == "starts_with" ? condition.value.values : null + not_starts_with = condition.value.operator == "not_starts_with" ? condition.value.values : null + ends_with = condition.value.operator == "ends_with" ? condition.value.values : null + not_ends_with = condition.value.operator == "not_ends_with" ? condition.value.values : null + } + } + } + } + ## Event Selector - Insight Events dynamic "insight_selector" { - for_each = var.insight_event.enabled ? var.insight_event.scopes : [] + for_each = var.insight_event_selector.enabled ? var.insight_event_selector.scopes : [] + iterator = selector content { - insight_type = local.insight_types[insight_selector.value] + insight_type = local.insight_types[selector.value] } } diff --git a/modules/cloudtrail-trail/outputs.tf b/modules/cloudtrail-trail/outputs.tf index c007423..0fa4ecc 100644 --- a/modules/cloudtrail-trail/outputs.tf +++ b/modules/cloudtrail-trail/outputs.tf @@ -41,29 +41,45 @@ output "iam_role" { } output "delivery_channels" { - description = "Delivery channels of the trail." + description = "The configurations for the delivery channels of the trail." value = { - s3 = { - bucket = var.delivery_s3_bucket - key_prefix = var.delivery_s3_key_prefix - - integrity_validation_enabled = var.delivery_s3_integrity_validation_enabled + s3_bucket = { + name = aws_cloudtrail.this.s3_bucket_name + key_prefix = aws_cloudtrail.this.s3_key_prefix + integrity_validation_enabled = aws_cloudtrail.this.enable_log_file_validation + sse_kms_key = var.delivery_channels.s3_bucket.sse_kms_key } - sns = { - topic = var.delivery_sns_topic + sns_topic = { + enabled = var.delivery_channels.sns_topic.enabled + name = var.delivery_channels.sns_topic.name } - cloudwatch_logs = { - log_group = var.delivery_cloudwatch_logs_log_group + cloudwatch_log_group = { + enabled = var.delivery_channels.cloudwatch_log_group.enabled + arn = aws_cloudtrail.this.cloud_watch_logs_group_arn + name = var.delivery_channels.cloudwatch_log_group.name } } } output "management_event" { - description = "A configuration for management events logging of the trail." - value = var.management_event + description = "A selector for management events of the trail." + value = var.management_event_selector +} + +output "data_event" { + description = "A list of selectors for data events of the trail." + value = var.data_event_selectors } output "insight_event" { - description = "A configuration for insight events logging of the trail." - value = var.insight_event + description = "A selector for insight events of the trail." + value = var.insight_event_selector } + +# output "debug" { +# value = { +# for k, v in aws_cloudtrail.this : +# k => v +# if !contains(["id", "arn", "name", "enable_logging", "home_region", "s3_bucket_name", "s3_key_prefix", "enable_log_file_validation", "kms_key_id", "sns_topic_name", "cloud_watch_logs_group_arn", "tags", "tags_all", "is_multi_region_trail", "is_organization_trail", "include_global_service_events", "insight_selector", "event_selector", "advanced_event_selector"], k) +# } +# } diff --git a/modules/cloudtrail-trail/variables.tf b/modules/cloudtrail-trail/variables.tf index 0a8abff..f8c9067 100644 --- a/modules/cloudtrail-trail/variables.tf +++ b/modules/cloudtrail-trail/variables.tf @@ -40,73 +40,199 @@ variable "scope" { } } -variable "delivery_s3_bucket" { - description = "(Required) The name of the S3 bucket designated for publishing log files." - type = string -} - -variable "delivery_s3_key_prefix" { - description = "(Optional) The key prefix for the specified S3 bucket." - type = string - default = null -} - -variable "delivery_s3_integrity_validation_enabled" { - description = "(Optional) To determine whether a log file was modified, deleted, or unchanged after AWS CloudTrail delivered it, use CloudTrail log file integrity validation. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing." - type = bool - default = true - nullable = false -} - -variable "delivery_sns_topic" { - description = "(Optional) The name of the SNS topic for notification of log file delivery." - type = string - default = null -} +variable "delivery_channels" { + description = < [aws](#provider\_aws) | 5.46.0 | +| [aws](#provider\_aws) | 5.48.0 | ## Modules diff --git a/modules/config-recorder/variables.tf b/modules/config-recorder/variables.tf index 7399d3c..3a2360a 100644 --- a/modules/config-recorder/variables.tf +++ b/modules/config-recorder/variables.tf @@ -194,7 +194,7 @@ variable "delivery_channels" { !var.delivery_channels.sns_topic.enabled, var.delivery_channels.sns_topic.enabled && var.delivery_channels.sns_topic.arn != null, ]) - error_message = "`delivery_channels.sns_topic.arn` must be provided when `delivery_channels.sns_topic.enableds` is `true`." + error_message = "`delivery_channels.sns_topic.arn` must be provided when `delivery_channels.sns_topic.enabled` is `true`." } }