From 71b954fe5730adb6f402ea48a237693b0a37c5ef Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Tue, 26 Dec 2023 15:35:49 -0800 Subject: [PATCH 1/4] Refactors config module for modern aws/terraform and all resource options --- all_resource_types.tf | 108 ----------------------------------- main.tf | 130 +++++++++++++----------------------------- outputs.tf | 15 ----- variables.tf | 62 +++++++++----------- versions.tf | 7 +++ 5 files changed, 74 insertions(+), 248 deletions(-) delete mode 100644 all_resource_types.tf diff --git a/all_resource_types.tf b/all_resource_types.tf deleted file mode 100644 index 60b0251..0000000 --- a/all_resource_types.tf +++ /dev/null @@ -1,108 +0,0 @@ -locals { - # To update this list: - # 1. Copy the Valid Values from the AWS Docs: https://docs.aws.amazon.com/config/latest/APIReference/API_ResourceIdentifier.html#config-Type-ResourceIdentifier-resourceType - # 2. In a python interpreter, paste the string into a new variable, and use - # split/sort/dump/print to get it into terraform syntax. - # > f = "" - # > print(json.dumps(sorted(f.split(" | ")), indent=2)) - - all_resource_types = [ - "AWS::ACM::Certificate", - "AWS::ApiGateway::RestApi", - "AWS::ApiGateway::Stage", - "AWS::ApiGatewayV2::Api", - "AWS::ApiGatewayV2::Stage", - "AWS::AutoScaling::AutoScalingGroup", - "AWS::AutoScaling::LaunchConfiguration", - "AWS::AutoScaling::ScalingPolicy", - "AWS::AutoScaling::ScheduledAction", - "AWS::CloudFormation::Stack", - "AWS::CloudFront::Distribution", - "AWS::CloudFront::StreamingDistribution", - "AWS::CloudTrail::Trail", - "AWS::CloudWatch::Alarm", - "AWS::CodeBuild::Project", - "AWS::CodePipeline::Pipeline", - "AWS::Config::ConformancePackCompliance", - "AWS::Config::ResourceCompliance", - "AWS::DynamoDB::Table", - "AWS::EC2::CustomerGateway", - "AWS::EC2::EIP", - "AWS::EC2::EgressOnlyInternetGateway", - "AWS::EC2::FlowLog", - "AWS::EC2::Host", - "AWS::EC2::Instance", - "AWS::EC2::InternetGateway", - "AWS::EC2::NatGateway", - "AWS::EC2::NetworkAcl", - "AWS::EC2::NetworkInterface", - "AWS::EC2::RegisteredHAInstance", - "AWS::EC2::RouteTable", - "AWS::EC2::SecurityGroup", - "AWS::EC2::Subnet", - "AWS::EC2::VPC", - "AWS::EC2::VPCEndpoint", - "AWS::EC2::VPCEndpointService", - "AWS::EC2::VPCPeeringConnection", - "AWS::EC2::VPNConnection", - "AWS::EC2::VPNGateway", - "AWS::EC2::Volume", - "AWS::ElasticBeanstalk::Application", - "AWS::ElasticBeanstalk::ApplicationVersion", - "AWS::ElasticBeanstalk::Environment", - "AWS::ElasticLoadBalancing::LoadBalancer", - "AWS::ElasticLoadBalancingV2::LoadBalancer", - "AWS::Elasticsearch::Domain", - "AWS::IAM::Group", - "AWS::IAM::Policy", - "AWS::IAM::Role", - "AWS::IAM::User", - "AWS::KMS::Key", - "AWS::Lambda::Function", - "AWS::NetworkFirewall::Firewall", - "AWS::NetworkFirewall::FirewallPolicy", - "AWS::NetworkFirewall::RuleGroup", - "AWS::QLDB::Ledger", - "AWS::RDS::DBCluster", - "AWS::RDS::DBClusterSnapshot", - "AWS::RDS::DBInstance", - "AWS::RDS::DBSecurityGroup", - "AWS::RDS::DBSnapshot", - "AWS::RDS::DBSubnetGroup", - "AWS::RDS::EventSubscription", - "AWS::Redshift::Cluster", - "AWS::Redshift::ClusterParameterGroup", - "AWS::Redshift::ClusterSecurityGroup", - "AWS::Redshift::ClusterSnapshot", - "AWS::Redshift::ClusterSubnetGroup", - "AWS::Redshift::EventSubscription", - "AWS::S3::AccountPublicAccessBlock", - "AWS::S3::Bucket", - "AWS::SNS::Topic", - "AWS::SQS::Queue", - "AWS::SSM::AssociationCompliance", - "AWS::SSM::FileData", - "AWS::SSM::ManagedInstanceInventory", - "AWS::SSM::PatchCompliance", - "AWS::SecretsManager::Secret", - "AWS::ServiceCatalog::CloudFormationProduct", - "AWS::ServiceCatalog::CloudFormationProvisionedProduct", - "AWS::ServiceCatalog::Portfolio", - "AWS::Shield::Protection", - "AWS::ShieldRegional::Protection", - "AWS::WAF::RateBasedRule", - "AWS::WAF::Rule", - "AWS::WAF::RuleGroup", - "AWS::WAF::WebACL", - "AWS::WAFRegional::RateBasedRule", - "AWS::WAFRegional::Rule", - "AWS::WAFRegional::RuleGroup", - "AWS::WAFRegional::WebACL", - "AWS::WAFv2::IPSet", - "AWS::WAFv2::ManagedRuleSet", - "AWS::WAFv2::RegexPatternSet", - "AWS::WAFv2::RuleGroup", - "AWS::WAFv2::WebACL", - "AWS::XRay::EncryptionConfig" - ] -} diff --git a/main.tf b/main.tf index 5664d59..ada9565 100644 --- a/main.tf +++ b/main.tf @@ -1,107 +1,55 @@ resource "aws_config_configuration_recorder" "this" { - name = var.name - role_arn = local.create_iam_role ? aws_iam_role.this[0].arn : var.iam_role_arn - - recording_group { - all_supported = local.record_all - include_global_resource_types = local.record_all - resource_types = local.record_all ? [] : local.resource_types + name = var.config.configuration_recorder.name + role_arn = aws_iam_service_linked_role.config.arn + + dynamic "recording_group" { + for_each = var.config.configuration_recorder.recording_group != null ? [var.config.configuration_recorder.recording_group] : [] + content { + all_supported = recording_group.value.all_supported + include_global_resource_types = recording_group.value.include_global_resource_types + resource_types = recording_group.value.resource_types + + dynamic "exclusion_by_resource_types" { + for_each = recording_group.value.exclusion_by_resource_types != null ? [recording_group.value.exclusion_by_resource_types] : [] + content { + resource_types = exclusion_by_resource_types.value.resource_types + } + } + + dynamic "recording_strategy" { + for_each = recording_group.value.recording_strategy != null ? [recording_group.value.recording_strategy] : [] + content { + use_only = recording_strategy.value.use_only + } + } + } } - - depends_on = [ - aws_iam_role_policy.this, - aws_iam_role_policy_attachment.this, - ] } resource "aws_config_delivery_channel" "this" { - name = var.name - s3_bucket_name = var.config_bucket - sns_topic_arn = aws_sns_topic.this.arn - - snapshot_delivery_properties { - delivery_frequency = var.snapshot_delivery_frequency + name = aws_config_configuration_recorder.this.name + s3_bucket_name = var.config.delivery_channel.s3_bucket_name + s3_key_prefix = var.config.delivery_channel.s3_key_prefix + s3_kms_key_arn = var.config.delivery_channel.s3_kms_key_arn + sns_topic_arn = var.config.delivery_channel.sns_topic_arn + + dynamic "snapshot_delivery_properties" { + for_each = var.config.delivery_channel.snapshot_delivery_properties != null ? [var.config.delivery_channel.snapshot_delivery_properties] : [] + content { + delivery_frequency = snapshot_delivery_properties.delivery_frequency + } } - - depends_on = [ - aws_config_configuration_recorder.this, - ] } resource "aws_config_configuration_recorder_status" "this" { name = aws_config_configuration_recorder.this.name - is_enabled = true + is_enabled = var.config.configuration_recorder.is_enabled + depends_on = [ aws_config_delivery_channel.this, ] } -resource "aws_iam_role" "this" { - count = local.create_iam_role ? 1 : 0 - - name = "config-continuous-monitoring" - assume_role_policy = data.aws_iam_policy_document.config_assume_role[0].json - tags = var.tags -} - -resource "aws_iam_role_policy" "this" { - count = local.create_iam_role ? 1 : 0 - - name = "config-continuous-monitoring" - role = aws_iam_role.this[0].id - policy = data.aws_iam_policy_document.config[0].json -} - -resource "aws_iam_role_policy_attachment" "this" { - count = local.create_iam_role ? 1 : 0 - - role = aws_iam_role.this[0].name - policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWS_ConfigRole" -} - -resource "aws_sns_topic" "this" { - name = "config-topic" -} - -locals { - create_iam_role = var.iam_role_arn == null - record_all = length(var.include_resource_types) == 0 && length(var.exclude_resource_types) == 0 - resource_types = length(var.include_resource_types) > 0 ? var.include_resource_types : setsubtract(local.all_resource_types, var.exclude_resource_types) -} - -data "aws_partition" "current" {} - -data "aws_caller_identity" "current" {} - -data "aws_iam_policy_document" "config_assume_role" { - count = local.create_iam_role ? 1 : 0 - - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["config.amazonaws.com"] - } - } -} - -data "aws_iam_policy_document" "config" { - count = local.create_iam_role ? 1 : 0 - - statement { - actions = ["s3:PutObject*"] - resources = ["arn:${data.aws_partition.current.partition}:s3:::${var.config_bucket}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"] - - condition { - test = "StringLike" - variable = "s3:x-amz-acl" - values = ["bucket-owner-full-control"] - } - } - - statement { - actions = ["s3:GetBucketAcl"] - resources = ["arn:${data.aws_partition.current.partition}:s3:::${var.config_bucket}"] - } +resource "aws_iam_service_linked_role" "config" { + aws_service_name = "config.amazonaws.com" } diff --git a/outputs.tf b/outputs.tf index e40169c..63f1c71 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,13 +1,3 @@ -output "config_iam_role_arn" { - description = "The Amazon Resource Name (ARN) of the config service role" - value = local.create_iam_role ? aws_iam_role.this[0].arn : "" -} - -output "config_iam_role_name" { - description = "The name of the config service role" - value = local.create_iam_role ? aws_iam_role.this[0].name : "" -} - output "config_recorder_id" { description = "The name of the AWS Config recorder" value = aws_config_configuration_recorder.this.id @@ -17,8 +7,3 @@ output "config_delivery_channel_id" { description = "The name of the AWS Config delivery channel" value = aws_config_delivery_channel.this.id } - -output "config_sns_topic_arn" { - description = "The Amazon Resource Name (ARN) of the config SNS topic" - value = aws_sns_topic.this.arn -} diff --git a/variables.tf b/variables.tf index 927abfc..9da9df0 100644 --- a/variables.tf +++ b/variables.tf @@ -1,40 +1,34 @@ -variable "config_bucket" { - description = "Name of S3 bucket for AWS Config inventory; bucket must already exist" - type = string -} +variable "config" { + description = "Object of inputs for AWS Config service" + type = object({ + configuration_recorder = object({ + name = string + is_enabled = optional(bool, true) -variable "name" { - description = "Name of the AWS Config recorder" - type = string - default = "default" -} + recording_group = optional(object({ + all_supported = optional(bool, true) + include_global_resource_types = optional(bool) + resource_types = optional(list(string)) -variable "include_resource_types" { - description = "A list of specific resource types for AWS Config to records changes to. See AWS documenation for types https://docs.aws.amazon.com/config/latest/APIReference/API_ResourceIdentifier.html#config-Type-ResourceIdentifier-resourceType" - type = list(string) - default = [] -} + exclusion_by_resource_types = optional(object({ + resource_types = list(string) + })) -variable "exclude_resource_types" { - description = "A list of specific resource types for AWS Config to not records changes to. This variable is mutually exclusive from `include_resource_types` and if both are set, `include_resource_types` will take priority. See AWS documenation for types https://docs.aws.amazon.com/config/latest/APIReference/API_ResourceIdentifier.html#config-Type-ResourceIdentifier-resourceType" - type = list(string) - default = [] -} + recording_strategy = optional(object({ + use_only = string + })) + })) + }) -variable "snapshot_delivery_frequency" { - description = "Frequency with which AWS Config recurringly delivers configuration snapshots, see " - type = string - default = "TwentyFour_Hours" -} - -variable "iam_role_arn" { - description = "ARN for the IAM role to attach to the config recorder. If blank, a minimal role will be created" - type = string - default = null -} + delivery_channel = object({ + s3_bucket_name = string + s3_key_prefix = optional(string) + s3_kms_key_arn = optional(string) + sns_topic_arn = optional(string) -variable "tags" { - description = "Map of tags to apply to the resources" - type = map(string) - default = {} + snapshot_delivery_properties = optional(object({ + delivery_frequency = string + })) + }) + }) } diff --git a/versions.tf b/versions.tf index d9b6f79..8e38dc2 100644 --- a/versions.tf +++ b/versions.tf @@ -1,3 +1,10 @@ terraform { required_version = ">= 0.12" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.5.0" + } + } } From e46dad3d65515dcac9048264aa064f5b8e28810d Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Tue, 26 Dec 2023 15:36:14 -0800 Subject: [PATCH 2/4] Updates test for refactored module --- tests/basic_create/main.tf | 20 ----- tests/defaults/main.tf | 80 ++++++++++++++++++++ tests/exclude_specific_resources/main.tf | 94 ++++++++++++++++++++---- tests/include_and_exclude/main.tf | 30 -------- tests/include_specific_resources/main.tf | 93 +++++++++++++++++++---- 5 files changed, 241 insertions(+), 76 deletions(-) delete mode 100644 tests/basic_create/main.tf create mode 100644 tests/defaults/main.tf delete mode 100644 tests/include_and_exclude/main.tf diff --git a/tests/basic_create/main.tf b/tests/basic_create/main.tf deleted file mode 100644 index 16a4551..0000000 --- a/tests/basic_create/main.tf +++ /dev/null @@ -1,20 +0,0 @@ -module "basic_create" { - source = "../../" - - name = "tardigrade-config-${random_string.this.result}" - config_bucket = aws_s3_bucket.this.id -} - -resource "random_string" "this" { - length = 6 - number = false - upper = false - special = false -} - -resource "aws_s3_bucket" "this" { - bucket = "tardigrade-config-${random_string.this.result}" - force_destroy = true -} - -data "aws_caller_identity" "current" {} diff --git a/tests/defaults/main.tf b/tests/defaults/main.tf new file mode 100644 index 0000000..e80c488 --- /dev/null +++ b/tests/defaults/main.tf @@ -0,0 +1,80 @@ +module "config" { + source = "../../" + + config = { + configuration_recorder = { + name = "tardigrade-config-${random_string.this.result}" + } + + delivery_channel = { + s3_bucket_name = aws_s3_bucket_policy.this.id + } + } +} + +resource "aws_s3_bucket" "this" { + bucket = "tardigrade-config-${random_string.this.result}" + force_destroy = true +} + +resource "aws_s3_bucket_policy" "this" { + bucket = aws_s3_bucket.this.id + + policy = jsonencode({ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AWSConfigBucketPermissionsCheck", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:GetBucketAcl", + "Resource": aws_s3_bucket.this.arn, + "Condition": { + "StringEquals": { + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + }, + { + "Sid": "AWSConfigBucketExistenceCheck", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:ListBucket", + "Resource": aws_s3_bucket.this.arn, + "Condition": { + "StringEquals": { + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + }, + { + "Sid": "AWSConfigBucketDelivery", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:PutObject", + "Resource": "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", + "Condition": { + "StringEquals": { + "s3:x-amz-acl": "bucket-owner-full-control", + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + } + ] + }) +} + +resource "random_string" "this" { + length = 6 + numeric = false + upper = false + special = false +} + +data "aws_caller_identity" "current" {} diff --git a/tests/exclude_specific_resources/main.tf b/tests/exclude_specific_resources/main.tf index 0da506d..e66e6b2 100644 --- a/tests/exclude_specific_resources/main.tf +++ b/tests/exclude_specific_resources/main.tf @@ -1,20 +1,28 @@ -module "exclude_specific_resources" { +module "config" { source = "../../" - name = "tardigrade-config-${random_string.this.result}" - config_bucket = aws_s3_bucket.this.id + config = { + configuration_recorder = { + name = "tardigrade-config-${random_string.this.result}" + recording_group = { + all_supported = false - exclude_resource_types = [ - "AWS::EC2::Instance", - "AWS::CloudTrail::Trail", - ] -} + exclusion_by_resource_types = { + resource_types = [ + "AWS::SSM::ManagedInstanceInventory", + ] + } -resource "random_string" "this" { - length = 6 - number = false - upper = false - special = false + recording_strategy = { + use_only = "EXCLUSION_BY_RESOURCE_TYPES" + } + } + } + + delivery_channel = { + s3_bucket_name = aws_s3_bucket_policy.this.id + } + } } resource "aws_s3_bucket" "this" { @@ -22,4 +30,64 @@ resource "aws_s3_bucket" "this" { force_destroy = true } +resource "aws_s3_bucket_policy" "this" { + bucket = aws_s3_bucket.this.id + + policy = jsonencode({ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AWSConfigBucketPermissionsCheck", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:GetBucketAcl", + "Resource": aws_s3_bucket.this.arn, + "Condition": { + "StringEquals": { + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + }, + { + "Sid": "AWSConfigBucketExistenceCheck", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:ListBucket", + "Resource": aws_s3_bucket.this.arn, + "Condition": { + "StringEquals": { + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + }, + { + "Sid": "AWSConfigBucketDelivery", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:PutObject", + "Resource": "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", + "Condition": { + "StringEquals": { + "s3:x-amz-acl": "bucket-owner-full-control", + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + } + ] + }) +} + +resource "random_string" "this" { + length = 6 + numeric = false + upper = false + special = false +} + data "aws_caller_identity" "current" {} diff --git a/tests/include_and_exclude/main.tf b/tests/include_and_exclude/main.tf deleted file mode 100644 index 9c69a15..0000000 --- a/tests/include_and_exclude/main.tf +++ /dev/null @@ -1,30 +0,0 @@ -module "include_and_exclude" { - source = "../../" - - name = "tardigrade-config-${random_string.this.result}" - config_bucket = aws_s3_bucket.this.id - - include_resource_types = [ - "AWS::EC2::Instance", - "AWS::CloudTrail::Trail", - ] - - exclude_resource_types = [ - "AWS::EC2::Instance", - "AWS::CloudTrail::Trail", - ] -} - -resource "random_string" "this" { - length = 6 - number = false - upper = false - special = false -} - -resource "aws_s3_bucket" "this" { - bucket = "tardigrade-config-${random_string.this.result}" - force_destroy = true -} - -data "aws_caller_identity" "current" {} diff --git a/tests/include_specific_resources/main.tf b/tests/include_specific_resources/main.tf index 41261dd..0c7649e 100644 --- a/tests/include_specific_resources/main.tf +++ b/tests/include_specific_resources/main.tf @@ -1,20 +1,27 @@ -module "include_specific_resources" { +module "config" { source = "../../" - name = "tardigrade-config-${random_string.this.result}" - config_bucket = aws_s3_bucket.this.id + config = { + configuration_recorder = { + name = "tardigrade-config-${random_string.this.result}" + recording_group = { + all_supported = false - include_resource_types = [ - "AWS::EC2::Instance", - "AWS::CloudTrail::Trail", - ] -} + recording_strategy = { + use_only = "INCLUSION_BY_RESOURCE_TYPES" + } -resource "random_string" "this" { - length = 6 - number = false - upper = false - special = false + resource_types = [ + "AWS::EC2::Instance", + "AWS::CloudTrail::Trail", + ] + } + } + + delivery_channel = { + s3_bucket_name = aws_s3_bucket_policy.this.id + } + } } resource "aws_s3_bucket" "this" { @@ -22,4 +29,64 @@ resource "aws_s3_bucket" "this" { force_destroy = true } +resource "aws_s3_bucket_policy" "this" { + bucket = aws_s3_bucket.this.id + + policy = jsonencode({ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AWSConfigBucketPermissionsCheck", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:GetBucketAcl", + "Resource": aws_s3_bucket.this.arn, + "Condition": { + "StringEquals": { + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + }, + { + "Sid": "AWSConfigBucketExistenceCheck", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:ListBucket", + "Resource": aws_s3_bucket.this.arn, + "Condition": { + "StringEquals": { + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + }, + { + "Sid": "AWSConfigBucketDelivery", + "Effect": "Allow", + "Principal": { + "Service": "config.amazonaws.com" + }, + "Action": "s3:PutObject", + "Resource": "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", + "Condition": { + "StringEquals": { + "s3:x-amz-acl": "bucket-owner-full-control", + "AWS:SourceAccount": data.aws_caller_identity.current.account_id + } + } + } + ] + }) +} + +resource "random_string" "this" { + length = 6 + numeric = false + upper = false + special = false +} + data "aws_caller_identity" "current" {} From d22a45ccdf1c986c4f31fdf835c8dbcad475c2c3 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Tue, 26 Dec 2023 15:37:17 -0800 Subject: [PATCH 3/4] Regenerates readme with terraform-docs --- README.md | 18 ++----- tests/defaults/main.tf | 60 +++++++++++------------ tests/exclude_specific_resources/main.tf | 62 ++++++++++++------------ tests/include_specific_resources/main.tf | 62 ++++++++++++------------ 4 files changed, 95 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 7edc230..4670149 100644 --- a/README.md +++ b/README.md @@ -26,42 +26,30 @@ make mockstack/clean | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.12 | +| [aws](#requirement\_aws) | >= 5.5.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | n/a | +| [aws](#provider\_aws) | >= 5.5.0 | ## Resources | Name | Type | |------|------| -| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | -| [aws_iam_policy_document.config](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.config_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [config\_bucket](#input\_config\_bucket) | Name of S3 bucket for AWS Config inventory; bucket must already exist | `string` | n/a | yes | -| [exclude\_resource\_types](#input\_exclude\_resource\_types) | A list of specific resource types for AWS Config to not records changes to. This variable is mutually exclusive from `include_resource_types` and if both are set, `include_resource_types` will take priority. See AWS documenation for types https://docs.aws.amazon.com/config/latest/APIReference/API_ResourceIdentifier.html#config-Type-ResourceIdentifier-resourceType | `list(string)` | `[]` | no | -| [iam\_role\_arn](#input\_iam\_role\_arn) | ARN for the IAM role to attach to the config recorder. If blank, a minimal role will be created | `string` | `null` | no | -| [include\_resource\_types](#input\_include\_resource\_types) | A list of specific resource types for AWS Config to records changes to. See AWS documenation for types https://docs.aws.amazon.com/config/latest/APIReference/API_ResourceIdentifier.html#config-Type-ResourceIdentifier-resourceType | `list(string)` | `[]` | no | -| [name](#input\_name) | Name of the AWS Config recorder | `string` | `"default"` | no | -| [snapshot\_delivery\_frequency](#input\_snapshot\_delivery\_frequency) | Frequency with which AWS Config recurringly delivers configuration snapshots, see | `string` | `"TwentyFour_Hours"` | no | -| [tags](#input\_tags) | Map of tags to apply to the resources | `map(string)` | `{}` | no | +| [config](#input\_config) | Object of inputs for AWS Config service |
object({
configuration_recorder = object({
name = string
is_enabled = optional(bool, true)

recording_group = optional(object({
all_supported = optional(bool, true)
include_global_resource_types = optional(bool)
resource_types = optional(list(string))

exclusion_by_resource_types = optional(object({
resource_types = list(string)
}))

recording_strategy = optional(object({
use_only = string
}))
}))
})

delivery_channel = object({
s3_bucket_name = string
s3_key_prefix = optional(string)
s3_kms_key_arn = optional(string)
sns_topic_arn = optional(string)

snapshot_delivery_properties = optional(object({
delivery_frequency = string
}))
})
})
| n/a | yes | ## Outputs | Name | Description | |------|-------------| | [config\_delivery\_channel\_id](#output\_config\_delivery\_channel\_id) | The name of the AWS Config delivery channel | -| [config\_iam\_role\_arn](#output\_config\_iam\_role\_arn) | The Amazon Resource Name (ARN) of the config service role | -| [config\_iam\_role\_name](#output\_config\_iam\_role\_name) | The name of the config service role | | [config\_recorder\_id](#output\_config\_recorder\_id) | The name of the AWS Config recorder | -| [config\_sns\_topic\_arn](#output\_config\_sns\_topic\_arn) | The Amazon Resource Name (ARN) of the config SNS topic | diff --git a/tests/defaults/main.tf b/tests/defaults/main.tf index e80c488..2be7a69 100644 --- a/tests/defaults/main.tf +++ b/tests/defaults/main.tf @@ -21,48 +21,48 @@ resource "aws_s3_bucket_policy" "this" { bucket = aws_s3_bucket.this.id policy = jsonencode({ - "Version": "2012-10-17", - "Statement": [ + "Version" : "2012-10-17", + "Statement" : [ { - "Sid": "AWSConfigBucketPermissionsCheck", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketPermissionsCheck", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:GetBucketAcl", - "Resource": aws_s3_bucket.this.arn, - "Condition": { - "StringEquals": { - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:GetBucketAcl", + "Resource" : aws_s3_bucket.this.arn, + "Condition" : { + "StringEquals" : { + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } }, { - "Sid": "AWSConfigBucketExistenceCheck", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketExistenceCheck", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:ListBucket", - "Resource": aws_s3_bucket.this.arn, - "Condition": { - "StringEquals": { - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:ListBucket", + "Resource" : aws_s3_bucket.this.arn, + "Condition" : { + "StringEquals" : { + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } }, { - "Sid": "AWSConfigBucketDelivery", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketDelivery", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:PutObject", - "Resource": "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control", - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:PutObject", + "Resource" : "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", + "Condition" : { + "StringEquals" : { + "s3:x-amz-acl" : "bucket-owner-full-control", + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } } diff --git a/tests/exclude_specific_resources/main.tf b/tests/exclude_specific_resources/main.tf index e66e6b2..f46b178 100644 --- a/tests/exclude_specific_resources/main.tf +++ b/tests/exclude_specific_resources/main.tf @@ -3,7 +3,7 @@ module "config" { config = { configuration_recorder = { - name = "tardigrade-config-${random_string.this.result}" + name = "tardigrade-config-${random_string.this.result}" recording_group = { all_supported = false @@ -34,48 +34,48 @@ resource "aws_s3_bucket_policy" "this" { bucket = aws_s3_bucket.this.id policy = jsonencode({ - "Version": "2012-10-17", - "Statement": [ + "Version" : "2012-10-17", + "Statement" : [ { - "Sid": "AWSConfigBucketPermissionsCheck", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketPermissionsCheck", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:GetBucketAcl", - "Resource": aws_s3_bucket.this.arn, - "Condition": { - "StringEquals": { - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:GetBucketAcl", + "Resource" : aws_s3_bucket.this.arn, + "Condition" : { + "StringEquals" : { + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } }, { - "Sid": "AWSConfigBucketExistenceCheck", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketExistenceCheck", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:ListBucket", - "Resource": aws_s3_bucket.this.arn, - "Condition": { - "StringEquals": { - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:ListBucket", + "Resource" : aws_s3_bucket.this.arn, + "Condition" : { + "StringEquals" : { + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } }, { - "Sid": "AWSConfigBucketDelivery", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketDelivery", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:PutObject", - "Resource": "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control", - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:PutObject", + "Resource" : "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", + "Condition" : { + "StringEquals" : { + "s3:x-amz-acl" : "bucket-owner-full-control", + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } } diff --git a/tests/include_specific_resources/main.tf b/tests/include_specific_resources/main.tf index 0c7649e..be92044 100644 --- a/tests/include_specific_resources/main.tf +++ b/tests/include_specific_resources/main.tf @@ -3,7 +3,7 @@ module "config" { config = { configuration_recorder = { - name = "tardigrade-config-${random_string.this.result}" + name = "tardigrade-config-${random_string.this.result}" recording_group = { all_supported = false @@ -33,48 +33,48 @@ resource "aws_s3_bucket_policy" "this" { bucket = aws_s3_bucket.this.id policy = jsonencode({ - "Version": "2012-10-17", - "Statement": [ + "Version" : "2012-10-17", + "Statement" : [ { - "Sid": "AWSConfigBucketPermissionsCheck", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketPermissionsCheck", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:GetBucketAcl", - "Resource": aws_s3_bucket.this.arn, - "Condition": { - "StringEquals": { - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:GetBucketAcl", + "Resource" : aws_s3_bucket.this.arn, + "Condition" : { + "StringEquals" : { + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } }, { - "Sid": "AWSConfigBucketExistenceCheck", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketExistenceCheck", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:ListBucket", - "Resource": aws_s3_bucket.this.arn, - "Condition": { - "StringEquals": { - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:ListBucket", + "Resource" : aws_s3_bucket.this.arn, + "Condition" : { + "StringEquals" : { + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } }, { - "Sid": "AWSConfigBucketDelivery", - "Effect": "Allow", - "Principal": { - "Service": "config.amazonaws.com" + "Sid" : "AWSConfigBucketDelivery", + "Effect" : "Allow", + "Principal" : { + "Service" : "config.amazonaws.com" }, - "Action": "s3:PutObject", - "Resource": "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control", - "AWS:SourceAccount": data.aws_caller_identity.current.account_id + "Action" : "s3:PutObject", + "Resource" : "${aws_s3_bucket.this.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*", + "Condition" : { + "StringEquals" : { + "s3:x-amz-acl" : "bucket-owner-full-control", + "AWS:SourceAccount" : data.aws_caller_identity.current.account_id } } } From d052dc0192139e6a80d6b8f61943612b33625424 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Tue, 26 Dec 2023 15:37:20 -0800 Subject: [PATCH 4/4] Bumps version to 4.0.0 --- .bumpversion.cfg | 2 +- CHANGELOG.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index cbe3057..0e34519 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.0.2 +current_version = 4.0.0 commit = True message = Bumps version to {new_version} tag = False diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ede57..6ae2330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +### [4.0.0](https://github.com/plus3it/terraform-aws-tardigrade-config/releases/tag/4.0.0) + +**Released**: 2023.12.26 + +**Summary**: + +* Adds native support for excluded or included resource types +* Supports all features available as of terraform-provider-aws v5.31.0 +* Uses service-linked-role exclusively, removing custom IAM role + ### 3.0.2 **Released**: 2022.06.03