generate-aws-config is a single, self-contained, statically compiled binary written in Go. The easiest way to get it onto your servers is to use the Gruntwork
Installer (make sure to replace <VERSION> below with the latest
version from the releases page):
Alternatively, you can download the binary from the Releases
Page.
Usage
This command should be run in your infrastructure-modules repository, or any repository where you store your Terraform
modules. This command will output a Terraform module named aws-config that you can then deploy with various input
parameters to enable AWS Config on all regions. In each region, an SNS topic and S3 bucket will be created for config
notifications and storage respectively.
For example, suppose you had an infrastructure-modules repository that mimics the Gruntwork Reference Architecture,
and has the following structure:
Suppose that you now want to add a module aws-config as generated by this script in the security folder. To do so,
first install the binary so that it is available in your PATH as described in the Installation section of this
docs.
Next, run the generator in the infrastructure-modules directory, passing in the target directory and main region. Note
that you will need to be authenticated to your AWS account. Refer to the Comprehensive Guide to Authenticating to AWS
on the Command
Line for
recommended ways to authenticate on the command line.
Note that one region must be marked as the one to store the global recorder, which includes resources that don't have
regions in AWS such as IAM.
The combination of these limitations makes it impossible to natively write Terraform code that invokes the aws-config
module across all regions.
Manually generating the code
If this tool didn't exist, users will have to manually create the module with each of the enabled regions replicated.
This involves a lot of copy paste and with 10+ regions, it becomes prone to operator error. Additionally, there are
several manual steps required:
The user will have to use the aws CLI to look up all enabled regions.
For each enabled region, the user will have to add in the provider config and module call.
One of the regions need to be designated the global recorder and have the input is_global_recorder = true.
This is especially painful if the module needs to be updated, as all references need to be replaced. When the config is
almost exactly the same (except for the region and the global recorder), this can be unnecessarily painful to replicate
the changes in each block.
Generating Terragrunt live config
Instead of generating a single module that manages all the configs, we could also have generated Terragrunt live config
files for each region in the Terragrunt folder structure. Ultimately we decided to generate the module calls in
Terraform for the following reasons:
We don't want to be opinionated to Terragrunt and support a wide range of possible use cases including Terraform
Enterprise.
Removing a region requires running terragrunt destroy. If you forget to run terragrunt destroy on the removed
region, then you may never remove that Config until you manually remove it from the console. In contrast, the current
approach will eventually ensure the Config is removed when terraform apply is run after the code for the region is
removed.
Additionally, replicating the Terraform module blocks in a single module has a natural progression to migrate to using
for_each on modules once that is ready to be implemented.
Supporting iteration in Terragrunt
This ended up being too complex to justify supporting the feature. See the RFC for Terragrunt
iteration for more information.
Questions? Ask away.
We're here to talk about our services, answer any questions, give advice, or just to chat.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"fc95141f6ec0e279e90cd92e80df5eb6f2a22dbc"}]},{"name":".gitignore","path":".gitignore","sha":"03aff38511349fa3b4441e2b0157b707218aa7ef"},{"name":".pre-commit-config.yaml","path":".pre-commit-config.yaml","sha":"b9fd389c37a0872a9d838269b406c0f8186acfcc"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"47ca720c554dc4a85a502b796941512d019f6046"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","sha":"87892060317568e38fb3673e6c974c548b5a3b49"},{"name":"README.adoc","path":"README.adoc","sha":"0de0bdcdefcddce617974b9d32b52dcc957a0532"},{"name":"_docs","children":[{"name":"aws-cloudtrail.png","path":"_docs/aws-cloudtrail.png","sha":"c5482ed9b343509b76ce9678c5d6fcc07902a664"},{"name":"aws-cloudwatch.png","path":"_docs/aws-cloudwatch.png","sha":"5211cf11b76d724d86ffe022a314c443afef74cf"},{"name":"aws-config.png","path":"_docs/aws-config.png","sha":"bfa3bd7f86edfb2d914b2fad0c608b8120cb13cd"},{"name":"aws-iam.png","path":"_docs/aws-iam.png","sha":"9c0ebb4b5543199462b52282d86617db471ec48a"},{"name":"cis-account-architecture.png","path":"_docs/cis-account-architecture.png","sha":"86113f679c13fb529ceed5596fecec41d5204f54"},{"name":"cis-logo.png","path":"_docs/cis-logo.png","sha":"e75a052f28ac1e4d1d2292fa6cdc1ccd6a904885"}]},{"name":"codegen","children":[{"name":"generate-aws-config","children":[{"name":".gitignore","path":"codegen/generate-aws-config/.gitignore","sha":"b488f31b176e8da6501add7ce148074af2337d91"},{"name":"README.adoc","path":"codegen/generate-aws-config/README.adoc","sha":"997b340c7ffe1acac40861358c07674614c72c81"},{"name":"core-concepts.md","path":"codegen/generate-aws-config/core-concepts.md","sha":"8d2f9154541e1476df457348260fd29eda7e6150","toggled":true},{"name":"images","children":[{"name":"aws-config-architecture.png","path":"codegen/generate-aws-config/images/aws-config-architecture.png","sha":"721458048d5e539468c438498863a91fa96e0a85"}]},{"name":"main.go","path":"codegen/generate-aws-config/main.go","sha":"3b0134a62ce1c94bc9f633eec8364813f231771f"},{"name":"templates","children":[{"name":"aws-config","children":[{"name":"README.adoc.tpl","path":"codegen/generate-aws-config/templates/aws-config/README.adoc.tpl","sha":"82e6b7d445e1354f6772205ff9cbb112a3fecefb"},{"name":"main.tf.tpl","path":"codegen/generate-aws-config/templates/aws-config/main.tf.tpl","sha":"9a3e6c44b6c71c69543b471ee8d4ca0f8a4e6029"},{"name":"outputs.tf.tpl","path":"codegen/generate-aws-config/templates/aws-config/outputs.tf.tpl","sha":"78fa3b2ce4cb2d02f4e3c0e193012c341cab2042"},{"name":"variables.tf.tpl","path":"codegen/generate-aws-config/templates/aws-config/variables.tf.tpl","sha":"a26a0a86040e5824185c15a2e27a269886b23bbe"}]}]}],"toggled":true},{"name":"generate-securityhub","children":[{"name":".gitignore","path":"codegen/generate-securityhub/.gitignore","sha":"61f44f130bdff8fcac8058495bd28ffd9062de25"},{"name":"README.md","path":"codegen/generate-securityhub/README.md","sha":"2ca7ca586fbe7a8ff77bdc9a435c2843caf25204"},{"name":"data","children":[{"name":"static","children":[{"name":"core-concepts.md","path":"codegen/generate-securityhub/data/static/core-concepts.md","sha":"6307ca9d06fb54f2d0061a81290ffead6bf5e7fa"},{"name":"invite-external-accounts","children":[{"name":"build_scripts","children":[{"name":"build.sh","path":"codegen/generate-securityhub/data/static/invite-external-accounts/build_scripts/build.sh","sha":"d88b72cd2e82f5156a50a35fb8cfa238159c6f82"}]},{"name":"dev_requirements.txt","path":"codegen/generate-securityhub/data/static/invite-external-accounts/dev_requirements.txt","sha":"ff7dfc3a64633aa716313a6adc39a95412bb9da8"},{"name":"invite_external_accounts","children":[{"name":"__init__.py","path":"codegen/generate-securityhub/data/static/invite-external-accounts/invite_external_accounts/__init__.py","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"name":"errors.py","path":"codegen/generate-securityhub/data/static/invite-external-accounts/invite_external_accounts/errors.py","sha":"7dc0edfd882b693d431c6fc8c345bdc1be70e520"},{"name":"main.py","path":"codegen/generate-securityhub/data/static/invite-external-accounts/invite_external_accounts/main.py","sha":"3cbba395f54591fd4d13750a5c07fccc061236bb"},{"name":"project_logging.py","path":"codegen/generate-securityhub/data/static/invite-external-accounts/invite_external_accounts/project_logging.py","sha":"82c5fecd96fc2531417d0ac09f4adedd39fc169b"},{"name":"securityhub.py","path":"codegen/generate-securityhub/data/static/invite-external-accounts/invite_external_accounts/securityhub.py","sha":"d40b61026878f522afebc9172d1d4b8bba7074e2"}]},{"name":"invite_external_accounts_pex.tar","path":"codegen/generate-securityhub/data/static/invite-external-accounts/invite_external_accounts_pex.tar","sha":"35d9ea3ff4b964125095d80d49276b86ed38558c"},{"name":"requirements.txt","path":"codegen/generate-securityhub/data/static/invite-external-accounts/requirements.txt","sha":"a40be0ee80ae138ac17fe8e4015ecfc5115b29c0"}]}]},{"name":"templates","children":[{"name":"aws-securityhub","children":[{"name":"README.adoc.tpl","path":"codegen/generate-securityhub/data/templates/aws-securityhub/README.adoc.tpl","sha":"dbf4a695948e2db28d99c9f0fff3221d4572031b"},{"name":"main.tf.tpl","path":"codegen/generate-securityhub/data/templates/aws-securityhub/main.tf.tpl","sha":"f9116a89bb53f226677608beb0605a06cf983a20"},{"name":"outputs.tf.tpl","path":"codegen/generate-securityhub/data/templates/aws-securityhub/outputs.tf.tpl","sha":"baf227f4683cc8dbcb3d5b3feec978b6c6b063fa"},{"name":"variables.tf.tpl","path":"codegen/generate-securityhub/data/templates/aws-securityhub/variables.tf.tpl","sha":"e9a017e5f5ed0d238b6faf2af9915013e5aa35e3"}]}]}]},{"name":"main.go","path":"codegen/generate-securityhub/main.go","sha":"271d00b9b29290c1a598b7abafabd25cd1d1c6df"}]},{"name":"generator","children":[{"name":"generator.go","path":"codegen/generator/generator.go","sha":"1eba5f52c04c33f25c6140abffe9a192b560a30b"}]},{"name":"go.mod","path":"codegen/go.mod","sha":"782b3eaf70bfa03f695e6d9b3bfead5caebf22b3"},{"name":"go.sum","path":"codegen/go.sum","sha":"f34e0b7d560cd4e5a06c7f2a476da5dcdc7e7633"},{"name":"logging","children":[{"name":"logging.go","path":"codegen/logging/logging.go","sha":"d4fb9da710acb21567b4e0581cb7bd7692baca04"}]}],"toggled":true},{"name":"examples","children":[{"name":"cloudtrail","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/cloudtrail/terraform/README.md","sha":"9b9ff0b6c9e117d046c6ceecda94479e33b79d72"},{"name":"main.tf","path":"examples/cloudtrail/terraform/main.tf","sha":"b4fbcdc0812484e50d6a5a85f7e0a01a5554f220"},{"name":"outputs.tf","path":"examples/cloudtrail/terraform/outputs.tf","sha":"d761e149fa2b1a22c74727b0f7ef1329f3063037"},{"name":"variables.tf","path":"examples/cloudtrail/terraform/variables.tf","sha":"81d4f4bb2ea1131763003f85de7b2e88f800f241"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/cloudtrail/terragrunt/README.md","sha":"5b2d50aab0541ccc335021e95fe22b56bd034dbf"},{"name":"terragrunt.hcl","path":"examples/cloudtrail/terragrunt/terragrunt.hcl","sha":"64a8047867d9b341b3d11ea07a492e8fcd4367cb"}]}]},{"name":"cloudwatch-logs-metric-filters","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/cloudwatch-logs-metric-filters/terraform/README.md","sha":"a60c455a1d42b0fb3801af970753c5c43977207e"},{"name":"main.tf","path":"examples/cloudwatch-logs-metric-filters/terraform/main.tf","sha":"31eb9aa9cc32f7725459169aa0ff3aa01668efc1"},{"name":"outputs.tf","path":"examples/cloudwatch-logs-metric-filters/terraform/outputs.tf","sha":"074e6118f58a6fd89d339ee3561c241b5de3583e"},{"name":"variables.tf","path":"examples/cloudwatch-logs-metric-filters/terraform/variables.tf","sha":"5ae2bdd5e8dce41b2885250b254426ba6fc06b39"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/cloudwatch-logs-metric-filters/terragrunt/README.md","sha":"5428ae138344bcb31a29bf653de47adbacf65976"},{"name":"terragrunt.hcl","path":"examples/cloudwatch-logs-metric-filters/terragrunt/terragrunt.hcl","sha":"4782ce6b03c26c43f2d0849d1baa0298edc5e13b"}]}]},{"name":"cross-account-iam-roles","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/cross-account-iam-roles/terraform/README.md","sha":"f3eadc1484eba090fd6e80006c14441e0fb2485c"},{"name":"main.tf","path":"examples/cross-account-iam-roles/terraform/main.tf","sha":"26aca4cd77367b7424078fd4cfe042ce6f37b447"},{"name":"outputs.tf","path":"examples/cross-account-iam-roles/terraform/outputs.tf","sha":"4635d74afd5ba0289decfaabe9e57266621866e2"},{"name":"variables.tf","path":"examples/cross-account-iam-roles/terraform/variables.tf","sha":"1c80da1943250d2c40180963c0a2f89fb2df9175"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/cross-account-iam-roles/terragrunt/README.md","sha":"d052127555ef25f2dfc7b878e664835414430615"},{"name":"terragrunt.hcl","path":"examples/cross-account-iam-roles/terragrunt/terragrunt.hcl","sha":"eb5224cea7b8e53a085045e490a79005e7814cf4"}]}]},{"name":"custom-iam-entity","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/custom-iam-entity/terraform/README.md","sha":"a44b701a7cdc4d03b1fba8857a71df5b4cdf6672"},{"name":"main.tf","path":"examples/custom-iam-entity/terraform/main.tf","sha":"33a2fc66826b737702aef28787ab83d9545b58c2"},{"name":"outputs.tf","path":"examples/custom-iam-entity/terraform/outputs.tf","sha":"835eb64f431386925438cb2f63e48e413faee90c"},{"name":"variables.tf","path":"examples/custom-iam-entity/terraform/variables.tf","sha":"7539c565d899f88078983f2232c550361a0ee502"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/custom-iam-entity/terragrunt/README.md","sha":"d9ea947f74c5518550d9cb34263b0236a955c5d2"},{"name":"terragrunt.hcl","path":"examples/custom-iam-entity/terragrunt/terragrunt.hcl","sha":"99bdccc50f04f2efb82ba424e86926066fddacff"}]}]},{"name":"iam-groups","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/iam-groups/terraform/README.md","sha":"2027c01edcc6d5125b71657e32520cc48f1c4f02"},{"name":"main.tf","path":"examples/iam-groups/terraform/main.tf","sha":"852d3e363fa4aab098cfcb7b382f145a246f7e5e"},{"name":"outputs.tf","path":"examples/iam-groups/terraform/outputs.tf","sha":"f386fa2f8b93fddfc8a04cb067220e4297c03ada"},{"name":"variables.tf","path":"examples/iam-groups/terraform/variables.tf","sha":"154f5a51e416bec433824942c65199bc74f28321"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/iam-groups/terragrunt/README.md","sha":"f12a36abf1602bf3fa19b42a1eecd3a95499631f"},{"name":"terragrunt.hcl","path":"examples/iam-groups/terragrunt/terragrunt.hcl","sha":"de01124a0a417059d5b62bf1cbb1352f4063ba24"}]}]},{"name":"iam-password-policy","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/iam-password-policy/terraform/README.md","sha":"29edc975ebec6423e42b789b02ee9ed2db0f521e"},{"name":"main.tf","path":"examples/iam-password-policy/terraform/main.tf","sha":"6cfd3decf581247ab410c1a6966b52c8d6f3d2da"},{"name":"variables.tf","path":"examples/iam-password-policy/terraform/variables.tf","sha":"ee9fe6604ee7b34c3a59b42cb9bcc503e5707abc"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/iam-password-policy/terragrunt/README.md","sha":"207bb1ad3e44c64e0e70c73de185e1f42b68756b"},{"name":"terragrunt.hcl","path":"examples/iam-password-policy/terragrunt/terragrunt.hcl","sha":"9a5abfb7982ee98aace97a1ea691a948aab5929e"}]}]},{"name":"saml-iam-roles","children":[{"name":"terraform","children":[{"name":"README.md","path":"examples/saml-iam-roles/terraform/README.md","sha":"431cef7141fde3a292df1626ed707d4b55c7a25d"},{"name":"main.tf","path":"examples/saml-iam-roles/terraform/main.tf","sha":"f669a1c4418c2249b5f850ac1614d64439db542b"},{"name":"outputs.tf","path":"examples/saml-iam-roles/terraform/outputs.tf","sha":"6e69339e781035cc29323a9dda927bea8a3d115b"},{"name":"saml-metadata.xml","path":"examples/saml-iam-roles/terraform/saml-metadata.xml","sha":"88596cfde52242a43559c79216a1c60b2ea12903"},{"name":"variables.tf","path":"examples/saml-iam-roles/terraform/variables.tf","sha":"7e552ab7a080ca8b9f4d0fd2b2058cda4b75c0c3"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"examples/saml-iam-roles/terragrunt/README.md","sha":"2cd3c7bdde337bee726b29d4a3e49c761b0ba3e0"},{"name":"terragrunt.hcl","path":"examples/saml-iam-roles/terragrunt/terragrunt.hcl","sha":"68c50d324603caa08181d1744b315c75e3697df8"}]}]},{"name":"securityhub","children":[{"name":"terragrunt","children":[{"name":"README.md","path":"examples/securityhub/terragrunt/README.md","sha":"e37eac4f45aab63a46d5b04d08ed53a6ac2471fe"},{"name":"master","children":[{"name":"terragrunt.hcl","path":"examples/securityhub/terragrunt/master/terragrunt.hcl","sha":"43f9e1834d0ccde7de6ebd01657078e73cba7574"}]},{"name":"member","children":[{"name":"terragrunt.hcl","path":"examples/securityhub/terragrunt/member/terragrunt.hcl","sha":"e27e078840046a1fff817ff84ba47a9a26c2fac9"}]}]}]}]},{"name":"modules","children":[{"name":"aws-config","children":[{"name":"README.adoc","path":"modules/aws-config/README.adoc","sha":"82e6b7d445e1354f6772205ff9cbb112a3fecefb"},{"name":"main.tf","path":"modules/aws-config/main.tf","sha":"6d5cb2a7ebe119efc435eb598a185d50be1223de"},{"name":"outputs.tf","path":"modules/aws-config/outputs.tf","sha":"480ad0ffa8dbe3410f19dbe89c0fbb277b715b87"},{"name":"variables.tf","path":"modules/aws-config/variables.tf","sha":"a58168bf7ea381ca7b83d1fd278f1cf5682aec0d"}]},{"name":"aws-securityhub","children":[{"name":"README.adoc","path":"modules/aws-securityhub/README.adoc","sha":"dbf4a695948e2db28d99c9f0fff3221d4572031b"},{"name":"core-concepts.md","path":"modules/aws-securityhub/core-concepts.md","sha":"6307ca9d06fb54f2d0061a81290ffead6bf5e7fa"},{"name":"invite-external-accounts","children":[{"name":"bin","children":[{"name":"invite_external_accounts_py27_env.pex","path":"modules/aws-securityhub/invite-external-accounts/bin/invite_external_accounts_py27_env.pex","sha":"a61d838d1fd681fd56760c4ab3c9b8ef7750e051"},{"name":"invite_external_accounts_py3_env.pex","path":"modules/aws-securityhub/invite-external-accounts/bin/invite_external_accounts_py3_env.pex","sha":"d1afb0ae6efe358dd053458799367c0bb29e0614"}]},{"name":"invite_external_accounts","children":[{"name":"__init__.py","path":"modules/aws-securityhub/invite-external-accounts/invite_external_accounts/__init__.py","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"name":"errors.py","path":"modules/aws-securityhub/invite-external-accounts/invite_external_accounts/errors.py","sha":"7dc0edfd882b693d431c6fc8c345bdc1be70e520"},{"name":"main.py","path":"modules/aws-securityhub/invite-external-accounts/invite_external_accounts/main.py","sha":"3cbba395f54591fd4d13750a5c07fccc061236bb"},{"name":"project_logging.py","path":"modules/aws-securityhub/invite-external-accounts/invite_external_accounts/project_logging.py","sha":"82c5fecd96fc2531417d0ac09f4adedd39fc169b"},{"name":"securityhub.py","path":"modules/aws-securityhub/invite-external-accounts/invite_external_accounts/securityhub.py","sha":"d40b61026878f522afebc9172d1d4b8bba7074e2"}]}]},{"name":"main.tf","path":"modules/aws-securityhub/main.tf","sha":"2841415e84457fdcc0f44754fbb61614a1f2d18c"},{"name":"outputs.tf","path":"modules/aws-securityhub/outputs.tf","sha":"6725581233df013f765f7031ac2fba93b79a37fc"},{"name":"variables.tf","path":"modules/aws-securityhub/variables.tf","sha":"ad2d8eb8928d9e5fd43d0051a84359c2fe1f4f26"}]},{"name":"cloudtrail","children":[{"name":"README.adoc","path":"modules/cloudtrail/README.adoc","sha":"5e7f7a35ae88be0c3a1f8e89fb61305677e5db21"},{"name":"images","children":[{"name":"cloudtrail-cis-architecture.png","path":"modules/cloudtrail/images/cloudtrail-cis-architecture.png","sha":"70b296eb99f2c2da1bcc73fbb8d4528eb4743204"}]},{"name":"main.tf","path":"modules/cloudtrail/main.tf","sha":"fd18724fb2b15e5b199382eb5371e9cb2b8d3031"},{"name":"outputs.tf","path":"modules/cloudtrail/outputs.tf","sha":"33c67afdc73569394d1b43c182355156938d9b11"},{"name":"variables.tf","path":"modules/cloudtrail/variables.tf","sha":"e6509a8cface50a1cd1d6bdb9a43f7ed26953d48"}]},{"name":"cloudwatch-logs-metric-filters","children":[{"name":"README.adoc","path":"modules/cloudwatch-logs-metric-filters/README.adoc","sha":"1bfa7134c7e3dc2f020205c20d98642414c92c10"},{"name":"core-concepts.md","path":"modules/cloudwatch-logs-metric-filters/core-concepts.md","sha":"75301bd203c74458fc05857510fdf89188ef3921"},{"name":"images","children":[{"name":"cloudwatch-alarm.png","path":"modules/cloudwatch-logs-metric-filters/images/cloudwatch-alarm.png","sha":"b9fa4a893e9a4c402f117d4fa3922b4e5fdc0b4f"},{"name":"cloudwatch-logs-architecture.png","path":"modules/cloudwatch-logs-metric-filters/images/cloudwatch-logs-architecture.png","sha":"65a8d960553521dbcb5d2342609b648fc1397f91"}]},{"name":"main.tf","path":"modules/cloudwatch-logs-metric-filters/main.tf","sha":"e41f82aab91278898135440450bd78933e185b14"},{"name":"outputs.tf","path":"modules/cloudwatch-logs-metric-filters/outputs.tf","sha":"1d0237d1e1bf5ba6d9e2136ecf1f2bf047ec7063"},{"name":"variables.tf","path":"modules/cloudwatch-logs-metric-filters/variables.tf","sha":"e45f808527dd3bdf14368a7a404ffa16a0de8509"}]},{"name":"cross-account-iam-roles","children":[{"name":"README.adoc","path":"modules/cross-account-iam-roles/README.adoc","sha":"9b36582f166539f09617a16f386d1f6678880874"},{"name":"images","children":[{"name":"iam-roles-architecture.png","path":"modules/cross-account-iam-roles/images/iam-roles-architecture.png","sha":"5b7c1e935fac59214299e224eb8425c8c9b246b8"}]},{"name":"main.tf","path":"modules/cross-account-iam-roles/main.tf","sha":"ced23a20d145023b87a22a9cf90ce9841500b757"},{"name":"outputs.tf","path":"modules/cross-account-iam-roles/outputs.tf","sha":"4635d74afd5ba0289decfaabe9e57266621866e2"},{"name":"variables.tf","path":"modules/cross-account-iam-roles/variables.tf","sha":"d7835df3cc93a9a0d858ac824f213144e419168b"}]},{"name":"custom-iam-entity","children":[{"name":"README.adoc","path":"modules/custom-iam-entity/README.adoc","sha":"7b49cabfe0da64d4398fb64581da7b810b79f9bc"},{"name":"main.tf","path":"modules/custom-iam-entity/main.tf","sha":"4b0a1e7443048694d727d5a64015e12dce4026e3"},{"name":"outputs.tf","path":"modules/custom-iam-entity/outputs.tf","sha":"157e624e8e8610fbeaf54f603dce2516806c332f"},{"name":"variables.tf","path":"modules/custom-iam-entity/variables.tf","sha":"9a4e12646a30d1bfee9ce18b28e134dad19983da"}]},{"name":"iam-groups","children":[{"name":"README.adoc","path":"modules/iam-groups/README.adoc","sha":"bd97d27b0878c3db0f1fdc03fae7278390260456"},{"name":"core-concepts.md","path":"modules/iam-groups/core-concepts.md","sha":"02dc8472d42c7ae6497417b378f31e8bd9882bd9"},{"name":"images","children":[{"name":"iam-groups-architecture.png","path":"modules/iam-groups/images/iam-groups-architecture.png","sha":"c95384f4ee5e543cda1b39bbfe6239f9581609f0"}]},{"name":"main.tf","path":"modules/iam-groups/main.tf","sha":"0540e498e623a11d60316cfbc6949b3767f65ba3"},{"name":"outputs.tf","path":"modules/iam-groups/outputs.tf","sha":"0919bcae3e51cadad70355a2c52fd15b45434287"},{"name":"variables.tf","path":"modules/iam-groups/variables.tf","sha":"a24e2fb4548de52da24e1c7eb8b3a2078b44c552"}]},{"name":"iam-password-policy","children":[{"name":"README.adoc","path":"modules/iam-password-policy/README.adoc","sha":"56d1516af9c03d91cff5484387096e782e44ba7e"},{"name":"main.tf","path":"modules/iam-password-policy/main.tf","sha":"7438c6148e697e1ec28537b86f1e3f4a3111393d"},{"name":"variables.tf","path":"modules/iam-password-policy/variables.tf","sha":"e8c3867f0ef9eb1a1d253ef6d5dffe6c902a4221"}]},{"name":"saml-iam-roles","children":[{"name":"README.adoc","path":"modules/saml-iam-roles/README.adoc","sha":"70bcb8fb3f59b169e84ad36af525cb72a5d1482d"},{"name":"images","children":[{"name":"saml-iam-roles.png","path":"modules/saml-iam-roles/images/saml-iam-roles.png","sha":"d8bb2b15ad1fbcb4cb0f823663735edc469d0c14"}]},{"name":"main.tf","path":"modules/saml-iam-roles/main.tf","sha":"1bcacf255b990ba9ea71d8a90cf363af7cac4020"},{"name":"outputs.tf","path":"modules/saml-iam-roles/outputs.tf","sha":"6e69339e781035cc29323a9dda927bea8a3d115b"},{"name":"variables.tf","path":"modules/saml-iam-roles/variables.tf","sha":"4319d117656b5a6945009dd15d62083af779852e"}]}]},{"name":"rfcs","children":[{"name":"flexible-backends.md","path":"rfcs/flexible-backends.md","sha":"8c308f20484932b9773c07f127d498de14c76bae"}]},{"name":"setup.cfg","path":"setup.cfg","sha":"981bc2bfd0b35029438d56c6d862a7f1519b8fe6"},{"name":"test","children":[{"name":"cloudtrail_test.go","path":"test/cloudtrail_test.go","sha":"46669ddd1b32aeb3f959a8dac9000d599bcbb03a"},{"name":"cloudwatch_logs_metric_filters_test.go","path":"test/cloudwatch_logs_metric_filters_test.go","sha":"2596d3619f9334f07af9054dd427aa510da364c7"},{"name":"cross_account_iam_roles_test.go","path":"test/cross_account_iam_roles_test.go","sha":"aa6d75cf953722a65edd0f623fe76a142c9aa02a"},{"name":"custom_iam_entity_test.go","path":"test/custom_iam_entity_test.go","sha":"4c95a46959349aeba26e80131a35af96ab16955a"},{"name":"generate_aws_config_test.go","path":"test/generate_aws_config_test.go","sha":"a1421114d28634b7c32131f67bf324a9742387cb"},{"name":"generate_securityhub_test.go","path":"test/generate_securityhub_test.go","sha":"492a4a86011210beb598ad1fdeb73736fec1a27e"},{"name":"go.mod","path":"test/go.mod","sha":"ae654fc7163a2df0241010e098b6456fe1dc965e"},{"name":"go.sum","path":"test/go.sum","sha":"3e43d17a39b86941caf74aa75e470cb35ced4ddd"},{"name":"iam_groups_test.go","path":"test/iam_groups_test.go","sha":"a361792deea45a980ed7ceae6f7a759c20c5ae3a"},{"name":"iam_password_policy_test.go","path":"test/iam_password_policy_test.go","sha":"0402874302c76da6e7fdf035a6b688e39ef33d8c"},{"name":"saml_iam_roles_test.go","path":"test/saml_iam_roles_test.go","sha":"7fc7ae5a4a268b6b78e90830ac150a98c92bfd82"},{"name":"test_helpers.go","path":"test/test_helpers.go","sha":"f0614e492133b9e9b9bbaec4b34251493d31f4cd"}]}]},"detailsContent":"<h1 class=\"preview__body--title\" id=\"generate-aws-config-core-concepts\">Generate AWS Config Core Concepts</h1><div class=\"preview__body--border\"></div><h2 class=\"preview__body--subtitle\" id=\"installation\">Installation</h2>\n<p><code>generate-aws-config</code> is a single, self-contained, statically compiled binary written in Go. The easiest way to get it onto your servers is to use the <a href=\"/repos/gruntwork-installer\" class=\"preview__body--description--blue\">Gruntwork\nInstaller</a> (make sure to replace <code><VERSION></code> below with the latest\nversion from the <a href=\"#open_modal\" class=\"preview__body--description--blue\">releases page</a>):</p>\n<pre>gruntwork-install --binary-name <span class=\"hljs-keyword\">generate</span>-aws-<span class=\"hljs-keyword\">config</span> --repo https:<span class=\"hljs-comment\">//github.com/gruntwork-io/cis-compliance-aws --tag <VERSION></span>\n</pre>\n<p>Alternatively, you can download the binary from the <a href=\"#open_modal\" class=\"preview__body--description--blue\">Releases\nPage</a>.</p>\n<h2 class=\"preview__body--subtitle\" id=\"usage\">Usage</h2>\n<p>This command should be run in your <code>infrastructure-modules</code> repository, or any repository where you store your Terraform\nmodules. This command will output a Terraform module named <code>aws-config</code> that you can then deploy with various input\nparameters to enable AWS Config on all regions. In each region, an SNS topic and S3 bucket will be created for config\nnotifications and storage respectively.</p>\n<p>For example, suppose you had an <code>infrastructure-modules</code> repository that mimics the Gruntwork Reference Architecture,\nand has the following structure:</p>\n<pre><span class=\"hljs-selector-tag\">infrastructure-modules</span>\n├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n├── <span class=\"hljs-selector-tag\">data-stores</span>\n│ └── <span class=\"hljs-selector-tag\">rds</span>\n│ ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n│ ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n│ ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n│ └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n└── <span class=\"hljs-selector-tag\">security</span>\n ├── <span class=\"hljs-selector-tag\">iam-groups</span>\n │ ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n │ ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n │ ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n │ └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n └── <span class=\"hljs-selector-tag\">cloudtrail</span>\n ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n</pre>\n<p>Suppose that you now want to add a module <code>aws-config</code> as generated by this script in the <code>security</code> folder. To do so,\nfirst install the binary so that it is available in your <code>PATH</code> as described in the <a href=\"#installation\" class=\"preview__body--description--blue\">Installation section of this\ndocs</a>.</p>\n<p>Next, run the generator in the <code>infrastructure-modules</code> directory, passing in the target directory and main region. Note\nthat you will need to be authenticated to your AWS account. Refer to the <a href=\"https://blog.gruntwork.io/a-comprehensive-guide-to-authenticating-to-aws-on-the-command-line-63656a686799\" class=\"preview__body--description--blue\" target=\"_blank\">Comprehensive Guide to Authenticating to AWS\non the Command\nLine</a> for\nrecommended ways to authenticate on the command line.</p>\n<p>Note that one region must be marked as the one to store the global recorder, which includes resources that don't have\nregions in AWS such as IAM.</p>\n<pre><span class=\"hljs-keyword\">generate</span>-aws-<span class=\"hljs-keyword\">config</span> --target-directory ./security/aws-<span class=\"hljs-keyword\">config</span> --<span class=\"hljs-keyword\">global</span>-recorder-region us-east-<span class=\"hljs-number\">1</span>\n</pre>\n<p>This will:</p>\n<ul>\n<li>Look up all the available regions for the authenticated account.</li>\n<li>Generate a terraform module in the folder <code>security/aws-config</code> that will deploy AWS Config on each enabled region.</li>\n<li>Set the us-east-1 as the one to store the global recorder.</li>\n</ul>\n<p>At the end of this command, you should see the <code>aws-config</code> module generated in your <code>infrastructure-modules</code>\nrepository:</p>\n<pre><span class=\"hljs-selector-tag\">infrastructure-modules</span>\n├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n├── <span class=\"hljs-selector-tag\">data-stores</span>\n│ └── <span class=\"hljs-selector-tag\">rds</span>\n│ ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n│ ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n│ ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n│ └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n└── <span class=\"hljs-selector-tag\">security</span>\n ├── <span class=\"hljs-selector-tag\">aws-config</span>\n │ ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n │ ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n │ ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n │ └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n ├── <span class=\"hljs-selector-tag\">iam-groups</span>\n │ ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n │ ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n │ ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n │ └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n └── <span class=\"hljs-selector-tag\">cloudtrail</span>\n ├── <span class=\"hljs-selector-tag\">README</span><span class=\"hljs-selector-class\">.md</span>\n ├── <span class=\"hljs-selector-tag\">main</span><span class=\"hljs-selector-class\">.tf</span>\n ├── <span class=\"hljs-selector-tag\">outputs</span><span class=\"hljs-selector-class\">.tf</span>\n └── <span class=\"hljs-selector-tag\">vars</span><span class=\"hljs-selector-class\">.tf</span>\n\n</pre>\n<p>You can now invoke the module using Terragrunt, or any other production Terraform frontend that you are currently using.</p>\n<h2 class=\"preview__body--subtitle\" id=\"building-the-binary\">Building the Binary</h2>\n<p>We use <a href=\"https://github.com/gobuffalo/packr\" class=\"preview__body--description--blue\" target=\"_blank\">packr</a> to compile the templates into the binary so that it is portable. To\ndo so, we need to run <code>packr2</code> prior to building the binaries.</p>\n<p>Here are the steps for compiling from source:</p>\n<ul>\n<li>Install the <code>packr2</code> binary: <code>go get -u github.com/gobuffalo/packr/v2/packr2</code></li>\n<li>Run <code>$GOPATH/bin/packr2</code>. This will convert the template files into go files so that they are available in the go\nbinary.</li>\n<li>Pull vendor dependencies: <code>dep ensure -v</code></li>\n<li>Build the <code>generate-aws-config</code> binary: <code>go build -o $BIN_PATH .</code></li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"alternatives-considered\">Alternatives considered</h2>\n<h3 class=\"preview__body--subtitle\" id=\"native-terraform\">Native Terraform</h3>\n<p>As of 0.12.16, Terraform still does not support:</p>\n<ul>\n<li><a href=\"https://github.com/hashicorp/terraform/issues/17519\" class=\"preview__body--description--blue\" target=\"_blank\">for_each or counts with modules</a></li>\n<li><a href=\"https://github.com/hashicorp/terraform/issues/19932\" class=\"preview__body--description--blue\" target=\"_blank\">for_each or counts with providers</a></li>\n<li><a href=\"https://github.com/hashicorp/terraform/issues/18682\" class=\"preview__body--description--blue\" target=\"_blank\">interpolating variables on the provider parameter of a resource</a></li>\n</ul>\n<p>The combination of these limitations makes it impossible to natively write Terraform code that invokes the <a href=\"/repos/module-security/modules/aws-config\" class=\"preview__body--description--blue\">aws-config\nmodule</a> across all regions.</p>\n<h3 class=\"preview__body--subtitle\" id=\"manually-generating-the-code\">Manually generating the code</h3>\n<p>If this tool didn't exist, users will have to manually create the module with each of the enabled regions replicated.\nThis involves a lot of copy paste and with 10+ regions, it becomes prone to operator error. Additionally, there are\nseveral manual steps required:</p>\n<ol>\n<li>The user will have to use the aws CLI to look up all enabled regions.</li>\n<li>For each enabled region, the user will have to add in the provider config and module call.</li>\n<li>One of the regions need to be designated the global recorder and have the input <code>is_global_recorder = true</code>.</li>\n</ol>\n<p>This is especially painful if the module needs to be updated, as all references need to be replaced. When the config is\nalmost exactly the same (except for the region and the global recorder), this can be unnecessarily painful to replicate\nthe changes in each block.</p>\n<h3 class=\"preview__body--subtitle\" id=\"generating-terragrunt-live-config\">Generating Terragrunt live config</h3>\n<p>Instead of generating a single module that manages all the configs, we could also have generated Terragrunt live config\nfiles for each region in the Terragrunt folder structure. Ultimately we decided to generate the module calls in\nTerraform for the following reasons:</p>\n<ul>\n<li>We don't want to be opinionated to Terragrunt and support a wide range of possible use cases including Terraform\nEnterprise.</li>\n<li>Removing a region requires running <code>terragrunt destroy</code>. If you forget to run <code>terragrunt destroy</code> on the removed\nregion, then you may never remove that Config until you manually remove it from the console. In contrast, the current\napproach will eventually ensure the Config is removed when <code>terraform apply</code> is run after the code for the region is\nremoved.</li>\n</ul>\n<p>Additionally, replicating the Terraform module blocks in a single module has a natural progression to migrate to using\n<code>for_each</code> on modules once that is ready to be implemented.</p>\n<h3 class=\"preview__body--subtitle\" id=\"supporting-iteration-in-terragrunt\">Supporting iteration in Terragrunt</h3>\n<p>This ended up being too complex to justify supporting the feature. See the <a href=\"/repos/terragrunt\" class=\"preview__body--description--blue\">RFC for Terragrunt\niteration</a> for more information.</p>\n","repoName":"cis-compliance-aws","repoRef":"v0.3.0","serviceDescriptor":{"serviceName":"CIS Foundations Benchmark","serviceRepoName":"cis-compliance-aws","serviceRepoOrg":"gruntwork-io","cloudProviders":["aws"],"description":"Modules and utilities certified by Gruntwork and CIS to comply with the CIS AWS Foundations Benchmark","imageUrl":"cis-logo.png","licenseType":"subscriber","technologies":["Terraform","Go","Python"],"compliance":["CIS"],"tags":[""]},"serviceCategoryName":"Compliance","fileName":"core-concepts.md","filePath":"/codegen/generate-aws-config/core-concepts.md","title":"Repo Browser: CIS Foundations Benchmark","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}