Skip to content

Commit fd7506b

Browse files
authored
fix(SA-603): cloudformation stack for AWS Config mgmt account (#37)
1 parent b64b389 commit fd7506b

File tree

9 files changed

+137
-66
lines changed

9 files changed

+137
-66
lines changed

config.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ module "config_rule_groups" {
1111
enabled_regions = try(each.value.enabled_regions, null)
1212
exclude_accounts = each.value.exclude_accounts
1313
organizational_units = each.value.associations
14-
accounts = [local.mgmt_account_id]
1514
permission_model = "SERVICE_MANAGED"
1615
tags = local.tags
1716

data.tf

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11

22
## Find the current region
33
data "aws_region" "current" {}
4-
5-
# Get the mgmt account id via the Organization
6-
data "aws_organizations_organization" "this" {}

examples/basic/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
11
<!-- BEGIN_TF_DOCS -->
2+
## Requirements
3+
4+
| Name | Version |
5+
|------|---------|
6+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
7+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.0.0 |
8+
29
## Providers
310

411
| Name | Version |
512
|------|---------|
613
| <a name="provider_aws.audit_eu_west_2"></a> [aws.audit\_eu\_west\_2](#provider\_aws.audit\_eu\_west\_2) | >= 5.0.0 |
714

15+
## Modules
16+
17+
| Name | Source | Version |
18+
|------|--------|---------|
19+
| <a name="module_compliance"></a> [compliance](#module\_compliance) | ../.. | n/a |
20+
| <a name="module_config_home"></a> [config\_home](#module\_config\_home) | ../../modules/config | n/a |
21+
| <a name="module_config_us_east_1"></a> [config\_us\_east\_1](#module\_config\_us\_east\_1) | ../../modules/config | n/a |
22+
| <a name="module_guardduty_home"></a> [guardduty\_home](#module\_guardduty\_home) | ../../modules/guardduty | n/a |
23+
| <a name="module_guardduty_us_east_1"></a> [guardduty\_us\_east\_1](#module\_guardduty\_us\_east\_1) | ../../modules/guardduty | n/a |
24+
25+
## Resources
26+
27+
| Name | Type |
28+
|------|------|
29+
| [aws_guardduty_detector.guardduty](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/guardduty_detector) | data source |
30+
831
## Inputs
932

1033
No inputs.

examples/basic/main.tf

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,60 @@ locals {
1717
Product = "LandingZone"
1818
Provisioner = "Terraform"
1919
}
20+
21+
config = {
22+
rule_groups = {
23+
root = {
24+
description = "Common managed rules distribued to all accounts"
25+
associations = [
26+
"r-h53v"
27+
]
28+
29+
rules = {
30+
"managed-resource-tagging" : {
31+
description = "Validate the resource tags"
32+
resource_types : [
33+
"AWS::ACM::Certificate",
34+
"AWS::CloudFront::Distribution",
35+
"AWS::CloudFront::StreamingDistribution",
36+
"AWS::DynamoDB::Table",
37+
"AWS::EC2::Instance",
38+
"AWS::EC2::VPC",
39+
"AWS::EC2::Volume",
40+
"AWS::ECR::PublicRepository",
41+
"AWS::EC2::NatGateway",
42+
"AWS::ECR::Repository",
43+
"AWS::ECS::Cluster",
44+
"AWS::EFS::FileSystem",
45+
"AWS::EKS::Cluster",
46+
"AWS::ElasticLoadBalancingV2::LoadBalancer",
47+
"AWS::Elasticsearch::Domain",
48+
"AWS::Kinesis::Stream",
49+
"AWS::Kinesis::StreamConsumer",
50+
"AWS::RDS::DBCluster",
51+
"AWS::RDS::DBInstance",
52+
"AWS::RDS::DBSnapshot",
53+
"AWS::Redshift::Cluster",
54+
"AWS::Route53::HostedZone",
55+
"AWS::S3::Bucket",
56+
]
57+
identifier : "REQUIRED_TAGS"
58+
inputParameters = {
59+
tag1Key = "Product"
60+
tag2Key = "Owner"
61+
tag3Key = "Environment"
62+
tag4Key = "GitRepo"
63+
}
64+
mode = "DETECTIVE"
65+
# One_Hour | Three_Hours | Six_Hours | Twelve_Hours | TwentyFour_Hours
66+
max_execution_frequency : 24
67+
}
68+
}
69+
}
70+
}
71+
}
72+
73+
home_region = "eu-west-2"
2074
}
2175

2276
## Find the guardduty detector if it exists
@@ -55,7 +109,8 @@ module "config_home" {
55109
control_tower_sns_topic_arn = "arn:aws:sns:eu-west-1:123456789033:aws-controltower-AllConfigNotifications"
56110
logarchive_account_id = "987654321012"
57111
tags = local.tags
58-
home_region = "eu-west-2"
112+
home_region = local.home_region
113+
config = local.config
59114
}
60115

61116
module "config_us_east_1" {
@@ -65,7 +120,8 @@ module "config_us_east_1" {
65120
logarchive_account_id = "987654321012"
66121
config_retention_in_days = 90
67122
tags = local.tags
68-
home_region = "eu-west-2"
123+
home_region = local.home_region
124+
config = local.config
69125
}
70126

71127
module "compliance" {
@@ -79,57 +135,7 @@ module "compliance" {
79135
}
80136
}
81137

82-
config = {
83-
rule_groups = {
84-
root = {
85-
description = "Common managed rules distribued to all accounts"
86-
associations = [
87-
"r-h53v"
88-
]
89-
90-
rules = {
91-
"managed-resource-tagging" : {
92-
description = "Validate the resource tags"
93-
resource_types : [
94-
"AWS::ACM::Certificate",
95-
"AWS::CloudFront::Distribution",
96-
"AWS::CloudFront::StreamingDistribution",
97-
"AWS::DynamoDB::Table",
98-
"AWS::EC2::Instance",
99-
"AWS::EC2::VPC",
100-
"AWS::EC2::Volume",
101-
"AWS::ECR::PublicRepository",
102-
"AWS::EC2::NatGateway",
103-
"AWS::ECR::Repository",
104-
"AWS::ECS::Cluster",
105-
"AWS::EFS::FileSystem",
106-
"AWS::EKS::Cluster",
107-
"AWS::ElasticLoadBalancingV2::LoadBalancer",
108-
"AWS::Elasticsearch::Domain",
109-
"AWS::Kinesis::Stream",
110-
"AWS::Kinesis::StreamConsumer",
111-
"AWS::RDS::DBCluster",
112-
"AWS::RDS::DBInstance",
113-
"AWS::RDS::DBSnapshot",
114-
"AWS::Redshift::Cluster",
115-
"AWS::Route53::HostedZone",
116-
"AWS::S3::Bucket",
117-
]
118-
identifier : "REQUIRED_TAGS"
119-
inputParameters = {
120-
tag1Key = "Product"
121-
tag2Key = "Owner"
122-
tag3Key = "Environment"
123-
tag4Key = "GitRepo"
124-
}
125-
mode = "DETECTIVE"
126-
# One_Hour | Three_Hours | Six_Hours | Twelve_Hours | TwentyFour_Hours
127-
max_execution_frequency : 24
128-
}
129-
}
130-
}
131-
}
132-
}
138+
config = local.config
133139

134140
tags = local.tags
135141

locals.tf

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,4 @@ locals {
55

66
## Tag applied to all resources
77
tags = merge(var.tags, {})
8-
9-
# using Organization - resolve the mgmt account id (it's only ever the one account in the Management OU)
10-
mgmt_account_id = data.aws_organizations_organization.this.master_account_id
118
}

modules/config/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ No modules.
2020

2121
| Name | Type |
2222
|------|------|
23+
| [aws_cloudformation_stack.mgmt_config_rules_cloudformation_stack](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack) | resource |
2324
| [aws_config_configuration_recorder.mgmt_config_recorder](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/config_configuration_recorder) | resource |
25+
| [aws_config_configuration_recorder_status.mgmt_config_recorder_status](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/config_configuration_recorder_status) | resource |
2426
| [aws_config_delivery_channel.mgmt_config_delivery_channel](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/config_delivery_channel) | resource |
2527
| [aws_config_retention_configuration.mgmt_config_retention](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/config_retention_configuration) | resource |
2628
| [aws_iam_role.mgmt_config_recorder_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
@@ -32,6 +34,7 @@ No modules.
3234

3335
| Name | Description | Type | Default | Required |
3436
|------|-------------|------|---------|:--------:|
37+
| <a name="input_config"></a> [config](#input\_config) | Configuration for the securityhub organization managed rules | <pre>object({<br/> stackset_name_prefix = optional(string, "lza-config-")<br/><br/> # The prefix added to the stacksets<br/> rule_groups = optional(map(object({<br/> associations = list(string)<br/> # List of organizational units to deploy the managed rules<br/> description = string<br/> # Description for the rule group<br/> enabled_regions = optional(list(string), null)<br/> # List of regions to enable these rules<br/> exclude_accounts = optional(list(string), null)<br/> # The list of accounts to exclude from the organization managed rule<br/> rules = map(object({<br/> description = string<br/> # The description of the organization managed rules<br/> identifier = string<br/> # The identifier of the organization managed rule<br/> inputs = optional(map(string), {})<br/> # The identifier of the organization managed rule scope<br/> resource_types = list(string)<br/> # The list of resource types to scope the organization managed rule<br/> max_execution_frequency = optional(string, null)<br/> # The max_execution_frequency of the rule<br/> }))<br/> })), {})<br/> # The configuration for the securityhub organization managed rules<br/> })</pre> | n/a | yes |
3538
| <a name="input_config_retention_in_days"></a> [config\_retention\_in\_days](#input\_config\_retention\_in\_days) | The number of days to store config historical data (defaults to one year) | `number` | `366` | no |
3639
| <a name="input_control_tower_sns_topic_arn"></a> [control\_tower\_sns\_topic\_arn](#input\_control\_tower\_sns\_topic\_arn) | The ARN of the SNS topic created by Control Tower for AWS notifications | `string` | n/a | yes |
3740
| <a name="input_home_region"></a> [home\_region](#input\_home\_region) | The home Region in which Control Tower created the Config S3 buckiet (namely, in logarchive account | `string` | n/a | yes |

modules/config/main.tf

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@ resource "aws_config_delivery_channel" "mgmt_config_delivery_channel" {
6161
depends_on = [aws_config_configuration_recorder.mgmt_config_recorder]
6262
}
6363

64+
resource "aws_config_configuration_recorder_status" "mgmt_config_recorder_status" {
65+
name = aws_config_configuration_recorder.mgmt_config_recorder.name
66+
is_enabled = true
67+
depends_on = [aws_config_delivery_channel.mgmt_config_delivery_channel]
68+
}
69+
6470
resource "aws_config_retention_configuration" "mgmt_config_retention" {
6571
retention_period_in_days = var.config_retention_in_days
6672
}
73+
74+
resource "aws_cloudformation_stack" "mgmt_config_rules_cloudformation_stack" {
75+
for_each = var.config.rule_groups
76+
77+
name = format("%s%s", var.config.stackset_name_prefix, lower(each.key))
78+
region = local.region
79+
template_body = templatefile("${path.module}/../../assets/cloudformation/config.yaml", {
80+
"description" = each.value.description
81+
"rule_group_name" = each.key
82+
"rules" = each.value.rules
83+
})
84+
85+
depends_on = [aws_config_configuration_recorder_status.mgmt_config_recorder_status]
86+
}

modules/config/variables.tf

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,35 @@ variable "home_region" {
2929
error_message = "Region must be in the form xx-xxxx-x, e.g., eu-west-1"
3030
}
3131
}
32+
33+
variable "config" {
34+
description = "Configuration for the securityhub organization managed rules"
35+
type = object({
36+
stackset_name_prefix = optional(string, "lza-config-")
37+
38+
# The prefix added to the stacksets
39+
rule_groups = optional(map(object({
40+
associations = list(string)
41+
# List of organizational units to deploy the managed rules
42+
description = string
43+
# Description for the rule group
44+
enabled_regions = optional(list(string), null)
45+
# List of regions to enable these rules
46+
exclude_accounts = optional(list(string), null)
47+
# The list of accounts to exclude from the organization managed rule
48+
rules = map(object({
49+
description = string
50+
# The description of the organization managed rules
51+
identifier = string
52+
# The identifier of the organization managed rule
53+
inputs = optional(map(string), {})
54+
# The identifier of the organization managed rule scope
55+
resource_types = list(string)
56+
# The list of resource types to scope the organization managed rule
57+
max_execution_frequency = optional(string, null)
58+
# The max_execution_frequency of the rule
59+
}))
60+
})), {})
61+
# The configuration for the securityhub organization managed rules
62+
})
63+
}

tests/module.tftest.hcl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,6 @@ mock_provider "aws" {
198198
region = "eu-west-2"
199199
}
200200
}
201-
202-
mock_data "aws_organizations_organization" {
203-
defaults = {
204-
master_account_id = "123456789012"
205-
}
206-
}
207201
}
208202

209203
override_module {

0 commit comments

Comments
 (0)