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" + } + } }