├── .chglog ├── CHANGELOG.tpl.md └── config.yml ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── main.yml │ └── release-please.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .terraform-docs.yml ├── .tflint.hcl ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analyzer_baselines.tf ├── bucket.tf ├── compliance.md ├── config_baselines.tf ├── docs └── upgrade-1.0.md ├── ebs_baselines.tf ├── examples ├── external-bucket │ ├── bucket.tf │ ├── main.tf │ ├── outputs.tf │ ├── regions.tf │ └── variables.tf ├── organization │ ├── README.md │ ├── master │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── regions.tf │ │ └── variables.tf │ └── member │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── regions.tf │ │ └── variables.tf ├── select-region │ ├── main.tf │ ├── outputs.tf │ ├── regions.tf │ └── variables.tf └── simple │ ├── main.tf │ ├── outputs.tf │ ├── regions.tf │ └── variables.tf ├── guardduty_baselines.tf ├── main.tf ├── migrations.tf ├── modules ├── alarm-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── analyzer-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── cloudtrail-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── config-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── ebs-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── guardduty-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── iam-baseline │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── s3-baseline │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── secure-bucket │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── securityhub-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── vpc-baseline │ ├── README.md │ ├── main.tf │ ├── migrations.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── outputs.tf ├── securityhub_baselines.tf ├── variables.tf └── vpc_baselines.tf /.chglog/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | {{ if .Versions -}} 2 | 3 | ## [Unreleased] 4 | 5 | {{ if .Unreleased.CommitGroups -}} 6 | {{ range .Unreleased.CommitGroups -}} 7 | ### {{ .Title }} 8 | {{ range .Commits -}} 9 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} 10 | {{ end }} 11 | {{ end -}} 12 | {{ end -}} 13 | {{ end -}} 14 | 15 | {{ range .Versions }} 16 | 17 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} 18 | {{ range .CommitGroups -}} 19 | ### {{ .Title }} 20 | {{ range .Commits -}} 21 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} 22 | {{ end }} 23 | {{ end -}} 24 | 25 | {{- if .NoteGroups -}} 26 | {{ range .NoteGroups -}} 27 | ### {{ .Title }} 28 | {{ range .Notes }} 29 | {{ .Body }} 30 | {{ end }} 31 | {{ end -}} 32 | {{ end -}} 33 | {{ end -}} 34 | 35 | {{- if .Versions }} 36 | [Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD 37 | {{ range .Versions -}} 38 | {{ if .Tag.Previous -}} 39 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} 40 | {{ end -}} 41 | {{ end -}} 42 | {{ end -}} 43 | -------------------------------------------------------------------------------- /.chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/nozaq/terraform-aws-secure-baseline 6 | options: 7 | commits: 8 | filters: 9 | Type: 10 | - feat 11 | - fix 12 | - perf 13 | - refactor 14 | commit_groups: 15 | # title_maps: 16 | # feat: Features 17 | # fix: Bug Fixes 18 | # perf: Performance Improvements 19 | # refactor: Code Refactoring 20 | header: 21 | pattern: "^(\\w*)\\:\\s(.*)$" 22 | pattern_maps: 23 | - Type 24 | - Subject 25 | notes: 26 | keywords: 27 | - BREAKING CHANGE 28 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/base:bullseye 2 | 3 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 4 | && apt-get -y install --no-install-recommends python3-pip \ 5 | && pip install --no-input pre-commit 6 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Terraform", 3 | "build": { 4 | "dockerfile": "./Dockerfile", 5 | "context": "." 6 | }, 7 | "features": { 8 | "ghcr.io/devcontainers/features/terraform:1": { 9 | "version": "latest", 10 | "installTerraformDocs": true 11 | } 12 | }, 13 | "customizations": { 14 | "vscode": { 15 | "extensions": [ 16 | "EditorConfig.EditorConfig" 17 | ] 18 | } 19 | }, 20 | "postCreateCommand": "pre-commit install" 21 | } 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | max_line_length = 80 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | max_line_length = 0 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Describe the bug 11 | 12 | 13 | 14 | ## Versions 15 | 16 | 17 | 18 | - Terraform: 19 | - Provider: 20 | - Module: 21 | 22 | ## Reproduction 23 | 24 | 25 | 26 | ## Expected behavior 27 | 28 | 29 | 30 | ## Actual behavior 31 | 32 | 33 | 34 | ## Additional context 35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Is your feature request related to a problem? Please describe. 11 | 12 | 13 | 14 | ## Describe the solution you'd like 15 | 16 | 17 | 18 | ## Describe alternatives you've considered 19 | 20 | 21 | 22 | ## Additional context 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | jobs: 8 | pre-commit-checks: 9 | name: Pre-commit checks 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | - name: Terraform min/max versions 15 | id: minMax 16 | uses: clowdhaus/terraform-min-max@v1.0.4 17 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} 18 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.4.1 19 | with: 20 | terraform-version: ${{ steps.minMax.outputs.maxVersion }} 21 | terraform-docs-version: v0.16.0 22 | validate-examples: 23 | name: Validate examples 24 | runs-on: ubuntu-latest 25 | defaults: 26 | run: 27 | shell: bash 28 | working-directory: examples 29 | steps: 30 | - uses: hashicorp/setup-terraform@v1 31 | - name: Checkout 32 | uses: actions/checkout@v2 33 | - name: Check examples 34 | env: 35 | EXAMPLES: simple external-bucket select-region organization/master organization/member 36 | run: | 37 | for EXAMPLE in ${EXAMPLES} 38 | do 39 | echo "Validating $EXAMPLE"... 40 | cd $EXAMPLE && terraform init && terraform validate && cd - 41 | done 42 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | name: release-please 6 | jobs: 7 | release-please: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: google-github-actions/release-please-action@v3 11 | with: 12 | release-type: terraform-module 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform.lock.hcl 2 | 3 | ##################### 4 | # Default gitignore # 5 | ##################### 6 | 7 | # Local .terraform directories 8 | **/.terraform/* 9 | 10 | # .tfstate files 11 | *.tfstate 12 | *.tfstate.* 13 | 14 | # Crash log files 15 | crash.log 16 | 17 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 18 | # password, private keys, and other secrets. These should not be part of version 19 | # control as they are data points which are potentially sensitive and subject 20 | # to change depending on the environment. 21 | # 22 | *.tfvars 23 | 24 | # Ignore override files as they are usually used to override resources locally and so 25 | # are not checked in 26 | override.tf 27 | override.tf.json 28 | *_override.tf 29 | *_override.tf.json 30 | 31 | # Include override files you do wish to add to version control using negated pattern 32 | # 33 | # !example_override.tf 34 | 35 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 36 | # example: *tfplan* 37 | 38 | # Ignore CLI configuration files 39 | .terraformrc 40 | terraform.rc 41 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.62.3 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_docs 7 | args: 8 | - --args=--config=.terraform-docs.yml 9 | - id: terraform_tflint 10 | exclude: "test/" 11 | args: 12 | - --args=--config=__GIT_WORKING_DIR__/.tflint.hcl 13 | -------------------------------------------------------------------------------- /.terraform-docs.yml: -------------------------------------------------------------------------------- 1 | formatter: "markdown table" 2 | 3 | sections: 4 | show: 5 | - requirements 6 | - providers 7 | - inputs 8 | - outputs 9 | 10 | sort: 11 | enabled: true 12 | by: required 13 | 14 | settings: 15 | default: false 16 | lockfile: false 17 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | module = false 3 | force = false 4 | disabled_by_default = false 5 | } 6 | 7 | rule "terraform_deprecated_interpolation" { 8 | enabled = true 9 | } 10 | 11 | rule "terraform_deprecated_index" { 12 | enabled = true 13 | } 14 | 15 | rule "terraform_unused_declarations" { 16 | enabled = true 17 | } 18 | 19 | rule "terraform_comment_syntax" { 20 | enabled = true 21 | } 22 | 23 | rule "terraform_documented_outputs" { 24 | enabled = true 25 | } 26 | 27 | rule "terraform_documented_variables" { 28 | enabled = true 29 | } 30 | 31 | rule "terraform_typed_variables" { 32 | enabled = true 33 | } 34 | 35 | rule "terraform_module_pinned_source" { 36 | enabled = true 37 | } 38 | 39 | rule "terraform_required_version" { 40 | enabled = true 41 | } 42 | 43 | rule "terraform_required_providers" { 44 | enabled = true 45 | } 46 | 47 | rule "terraform_standard_module_structure" { 48 | enabled = true 49 | } 50 | 51 | rule "terraform_workspace_remote" { 52 | enabled = true 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Takashi Nozawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /analyzer_baselines.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | is_analyzer_enabled = var.analyzer_baseline_enabled && (local.is_individual_account || local.is_master_account) 3 | } 4 | 5 | # -------------------------------------------------------------------------------------------------- 6 | # Analyzer Baseline 7 | # -------------------------------------------------------------------------------------------------- 8 | 9 | module "analyzer_baseline_ap-northeast-1" { 10 | count = local.is_analyzer_enabled && contains(var.target_regions, "ap-northeast-1") ? 1 : 0 11 | source = "./modules/analyzer-baseline" 12 | 13 | providers = { 14 | aws = aws.ap-northeast-1 15 | } 16 | 17 | analyzer_name = var.analyzer_name 18 | is_organization = local.is_master_account 19 | 20 | tags = var.tags 21 | } 22 | 23 | module "analyzer_baseline_ap-northeast-2" { 24 | count = local.is_analyzer_enabled && contains(var.target_regions, "ap-northeast-2") ? 1 : 0 25 | source = "./modules/analyzer-baseline" 26 | 27 | providers = { 28 | aws = aws.ap-northeast-2 29 | } 30 | 31 | analyzer_name = var.analyzer_name 32 | is_organization = local.is_master_account 33 | 34 | tags = var.tags 35 | } 36 | 37 | module "analyzer_baseline_ap-south-1" { 38 | count = local.is_analyzer_enabled && contains(var.target_regions, "ap-south-1") ? 1 : 0 39 | source = "./modules/analyzer-baseline" 40 | 41 | providers = { 42 | aws = aws.ap-south-1 43 | } 44 | 45 | analyzer_name = var.analyzer_name 46 | is_organization = local.is_master_account 47 | 48 | tags = var.tags 49 | } 50 | 51 | module "analyzer_baseline_ap-northeast-3" { 52 | count = local.is_analyzer_enabled && contains(var.target_regions, "ap-northeast-3") ? 1 : 0 53 | source = "./modules/analyzer-baseline" 54 | 55 | providers = { 56 | aws = aws.ap-northeast-3 57 | } 58 | 59 | analyzer_name = var.analyzer_name 60 | is_organization = local.is_master_account 61 | 62 | tags = var.tags 63 | } 64 | 65 | module "analyzer_baseline_ap-southeast-1" { 66 | count = local.is_analyzer_enabled && contains(var.target_regions, "ap-southeast-1") ? 1 : 0 67 | source = "./modules/analyzer-baseline" 68 | 69 | providers = { 70 | aws = aws.ap-southeast-1 71 | } 72 | 73 | analyzer_name = var.analyzer_name 74 | is_organization = local.is_master_account 75 | 76 | tags = var.tags 77 | } 78 | 79 | module "analyzer_baseline_ap-southeast-2" { 80 | count = local.is_analyzer_enabled && contains(var.target_regions, "ap-southeast-2") ? 1 : 0 81 | source = "./modules/analyzer-baseline" 82 | 83 | providers = { 84 | aws = aws.ap-southeast-2 85 | } 86 | 87 | analyzer_name = var.analyzer_name 88 | is_organization = local.is_master_account 89 | 90 | tags = var.tags 91 | } 92 | 93 | module "analyzer_baseline_ca-central-1" { 94 | count = local.is_analyzer_enabled && contains(var.target_regions, "ca-central-1") ? 1 : 0 95 | source = "./modules/analyzer-baseline" 96 | 97 | providers = { 98 | aws = aws.ca-central-1 99 | } 100 | 101 | analyzer_name = var.analyzer_name 102 | is_organization = local.is_master_account 103 | 104 | tags = var.tags 105 | } 106 | 107 | module "analyzer_baseline_eu-central-1" { 108 | count = local.is_analyzer_enabled && contains(var.target_regions, "eu-central-1") ? 1 : 0 109 | source = "./modules/analyzer-baseline" 110 | 111 | providers = { 112 | aws = aws.eu-central-1 113 | } 114 | 115 | analyzer_name = var.analyzer_name 116 | is_organization = local.is_master_account 117 | 118 | tags = var.tags 119 | } 120 | 121 | module "analyzer_baseline_eu-north-1" { 122 | count = local.is_analyzer_enabled && contains(var.target_regions, "eu-north-1") ? 1 : 0 123 | source = "./modules/analyzer-baseline" 124 | 125 | providers = { 126 | aws = aws.eu-north-1 127 | } 128 | 129 | analyzer_name = var.analyzer_name 130 | is_organization = local.is_master_account 131 | 132 | tags = var.tags 133 | } 134 | 135 | module "analyzer_baseline_eu-west-1" { 136 | count = local.is_analyzer_enabled && contains(var.target_regions, "eu-west-1") ? 1 : 0 137 | source = "./modules/analyzer-baseline" 138 | 139 | providers = { 140 | aws = aws.eu-west-1 141 | } 142 | 143 | analyzer_name = var.analyzer_name 144 | is_organization = local.is_master_account 145 | 146 | tags = var.tags 147 | } 148 | 149 | module "analyzer_baseline_eu-west-2" { 150 | count = local.is_analyzer_enabled && contains(var.target_regions, "eu-west-2") ? 1 : 0 151 | source = "./modules/analyzer-baseline" 152 | 153 | providers = { 154 | aws = aws.eu-west-2 155 | } 156 | 157 | analyzer_name = var.analyzer_name 158 | is_organization = local.is_master_account 159 | 160 | tags = var.tags 161 | } 162 | 163 | module "analyzer_baseline_eu-west-3" { 164 | count = local.is_analyzer_enabled && contains(var.target_regions, "eu-west-3") ? 1 : 0 165 | source = "./modules/analyzer-baseline" 166 | 167 | providers = { 168 | aws = aws.eu-west-3 169 | } 170 | 171 | analyzer_name = var.analyzer_name 172 | is_organization = local.is_master_account 173 | 174 | tags = var.tags 175 | } 176 | 177 | module "analyzer_baseline_sa-east-1" { 178 | count = local.is_analyzer_enabled && contains(var.target_regions, "sa-east-1") ? 1 : 0 179 | source = "./modules/analyzer-baseline" 180 | 181 | providers = { 182 | aws = aws.sa-east-1 183 | } 184 | 185 | analyzer_name = var.analyzer_name 186 | is_organization = local.is_master_account 187 | 188 | tags = var.tags 189 | } 190 | 191 | module "analyzer_baseline_us-east-1" { 192 | count = local.is_analyzer_enabled && contains(var.target_regions, "us-east-1") ? 1 : 0 193 | source = "./modules/analyzer-baseline" 194 | 195 | providers = { 196 | aws = aws.us-east-1 197 | } 198 | 199 | analyzer_name = var.analyzer_name 200 | is_organization = local.is_master_account 201 | 202 | tags = var.tags 203 | } 204 | 205 | module "analyzer_baseline_us-east-2" { 206 | count = local.is_analyzer_enabled && contains(var.target_regions, "us-east-2") ? 1 : 0 207 | source = "./modules/analyzer-baseline" 208 | 209 | providers = { 210 | aws = aws.us-east-2 211 | } 212 | 213 | analyzer_name = var.analyzer_name 214 | is_organization = local.is_master_account 215 | 216 | tags = var.tags 217 | } 218 | 219 | module "analyzer_baseline_us-west-1" { 220 | count = local.is_analyzer_enabled && contains(var.target_regions, "us-west-1") ? 1 : 0 221 | source = "./modules/analyzer-baseline" 222 | 223 | providers = { 224 | aws = aws.us-west-1 225 | } 226 | 227 | analyzer_name = var.analyzer_name 228 | is_organization = local.is_master_account 229 | 230 | tags = var.tags 231 | } 232 | 233 | module "analyzer_baseline_us-west-2" { 234 | count = local.is_analyzer_enabled && contains(var.target_regions, "us-west-2") ? 1 : 0 235 | source = "./modules/analyzer-baseline" 236 | 237 | providers = { 238 | aws = aws.us-west-2 239 | } 240 | 241 | analyzer_name = var.analyzer_name 242 | is_organization = local.is_master_account 243 | 244 | tags = var.tags 245 | } 246 | -------------------------------------------------------------------------------- /bucket.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Configure the S3 bucket to store audit logs. 3 | # -------------------------------------------------------------------------------------------------- 4 | 5 | locals { 6 | use_external_bucket = var.use_external_audit_log_bucket 7 | 8 | audit_log_bucket_id = local.use_external_bucket ? data.aws_s3_bucket.external[0].id : module.audit_log_bucket[0].this_bucket.id 9 | audit_log_bucket_arn = local.use_external_bucket ? data.aws_s3_bucket.external[0].arn : module.audit_log_bucket[0].this_bucket.arn 10 | 11 | audit_log_cloudtrail_destination = join("/", [local.audit_log_bucket_arn, trim(var.cloudtrail_s3_key_prefix, "/")]) 12 | audit_log_config_destination = join("/", [local.audit_log_bucket_arn, trim(var.config_s3_bucket_key_prefix, "/")]) 13 | audit_log_flow_logs_destination = join("/", [local.audit_log_bucket_arn, trim(var.vpc_flow_logs_s3_key_prefix, "/")]) 14 | } 15 | 16 | # -------------------------------------------------------------------------------------------------- 17 | # Case 1. Use the external S3 bucket. 18 | # -------------------------------------------------------------------------------------------------- 19 | 20 | data "aws_s3_bucket" "external" { 21 | count = local.use_external_bucket ? 1 : 0 22 | 23 | bucket = var.audit_log_bucket_name 24 | } 25 | 26 | # -------------------------------------------------------------------------------------------------- 27 | # Case 2. Create a new S3 bucket. 28 | # 29 | # Create a S3 bucket to store various audit logs. 30 | # Bucket policies are derived from the default bucket policy and official AWS documents. 31 | # -------------------------------------------------------------------------------------------------- 32 | 33 | module "audit_log_bucket" { 34 | count = local.use_external_bucket ? 0 : 1 35 | source = "./modules/secure-bucket" 36 | 37 | bucket_name = var.audit_log_bucket_name 38 | bucket_key_enabled = var.audit_log_bucket_key_enabled 39 | log_bucket_name = var.audit_log_bucket_access_logs_name != "" ? var.audit_log_bucket_access_logs_name : "${var.audit_log_bucket_name}-access-logs" 40 | lifecycle_glacier_transition_days = var.audit_log_lifecycle_glacier_transition_days 41 | force_destroy = var.audit_log_bucket_force_destroy 42 | 43 | tags = var.tags 44 | 45 | depends_on = [module.s3_baseline] 46 | } 47 | 48 | data "aws_organizations_organization" "org" { 49 | count = local.is_individual_account ? 0 : 1 50 | } 51 | 52 | # Apply policies to enforce SSL connections. 53 | # https://docs.aws.amazon.com/config/latest/developerguide/s3-bucket-ssl-requests-only.html 54 | data "aws_iam_policy_document" "audit_log_base" { 55 | count = local.use_external_bucket ? 0 : 1 56 | 57 | statement { 58 | actions = ["s3:*"] 59 | effect = "Deny" 60 | resources = [ 61 | module.audit_log_bucket[0].this_bucket.arn, 62 | "${module.audit_log_bucket[0].this_bucket.arn}/*" 63 | ] 64 | condition { 65 | test = "Bool" 66 | variable = "aws:SecureTransport" 67 | values = ["false"] 68 | } 69 | principals { 70 | type = "*" 71 | identifiers = ["*"] 72 | } 73 | } 74 | } 75 | 76 | # Apply policies for CloudTrail log delivery based on AWS CloudTrail User Guide. 77 | # https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create-s3-bucket-policy-for-cloudtrail.html 78 | data "aws_iam_policy_document" "audit_log_cloud_trail" { 79 | count = local.use_external_bucket ? 0 : 1 80 | 81 | source_policy_documents = [data.aws_iam_policy_document.audit_log_base[0].json] 82 | 83 | statement { 84 | sid = "AWSCloudTrailAclCheck20150319" 85 | actions = ["s3:GetBucketAcl"] 86 | principals { 87 | type = "Service" 88 | identifiers = ["cloudtrail.amazonaws.com"] 89 | } 90 | resources = [module.audit_log_bucket[0].this_bucket.arn] 91 | } 92 | 93 | statement { 94 | sid = "AWSCloudTrailWrite20150319" 95 | actions = ["s3:PutObject"] 96 | principals { 97 | type = "Service" 98 | identifiers = ["cloudtrail.amazonaws.com"] 99 | } 100 | resources = concat( 101 | ["${local.audit_log_cloudtrail_destination}/AWSLogs/${var.aws_account_id}/*"], 102 | local.is_master_account ? ["${local.audit_log_cloudtrail_destination}/AWSLogs/${data.aws_organizations_organization.org[0].id}/*"] : [] 103 | ) 104 | condition { 105 | test = "StringEquals" 106 | variable = "s3:x-amz-acl" 107 | values = ["bucket-owner-full-control"] 108 | } 109 | } 110 | } 111 | 112 | # Apply policies for AWS Config log delivery based on AWS Config Developer Guide. 113 | # https://docs.aws.amazon.com/config/latest/developerguide/s3-bucket-policy.html 114 | data "aws_iam_policy_document" "audit_log_config" { 115 | count = local.use_external_bucket ? 0 : 1 116 | 117 | source_policy_documents = [data.aws_iam_policy_document.audit_log_cloud_trail[0].json] 118 | 119 | statement { 120 | sid = "AWSConfigBucketPermissionsCheck" 121 | actions = ["s3:GetBucketAcl"] 122 | principals { 123 | type = "Service" 124 | identifiers = ["config.amazonaws.com"] 125 | } 126 | resources = [module.audit_log_bucket[0].this_bucket.arn] 127 | } 128 | 129 | statement { 130 | sid = "AWSConfigBucketExistenceCheck" 131 | actions = ["s3:ListBucket"] 132 | principals { 133 | type = "Service" 134 | identifiers = ["config.amazonaws.com"] 135 | } 136 | resources = [module.audit_log_bucket[0].this_bucket.arn] 137 | } 138 | 139 | statement { 140 | sid = "AWSConfigBucketDelivery" 141 | actions = ["s3:PutObject"] 142 | principals { 143 | type = "Service" 144 | identifiers = ["config.amazonaws.com"] 145 | } 146 | resources = concat( 147 | ["${local.audit_log_config_destination}/AWSLogs/${var.aws_account_id}/Config/*"], 148 | local.is_master_account ? [for account in var.member_accounts : "${local.audit_log_config_destination}/AWSLogs/${account.account_id}/Config/*"] : [] 149 | ) 150 | condition { 151 | test = "StringEquals" 152 | variable = "s3:x-amz-acl" 153 | values = ["bucket-owner-full-control"] 154 | } 155 | } 156 | 157 | dynamic "statement" { 158 | for_each = local.is_master_account && length(var.member_accounts) > 0 ? [var.member_accounts] : [] 159 | 160 | content { 161 | sid = "AWSConfigBucketPermissionsCheckForMemberAccounts" 162 | principals { 163 | type = "AWS" 164 | identifiers = [for account in statement.value : "arn:aws:iam::${account.account_id}:root"] 165 | } 166 | actions = ["s3:GetBucketAcl"] 167 | resources = [module.audit_log_bucket[0].this_bucket.arn] 168 | } 169 | } 170 | 171 | dynamic "statement" { 172 | for_each = local.is_master_account && length(var.member_accounts) > 0 ? [var.member_accounts] : [] 173 | 174 | content { 175 | sid = "AWSConfigBucketExistenceCheckForMemberAccounts" 176 | principals { 177 | type = "AWS" 178 | identifiers = [for account in statement.value : "arn:aws:iam::${account.account_id}:root"] 179 | } 180 | actions = ["s3:ListBucket", "s3:GetBucketLocation"] 181 | resources = [module.audit_log_bucket[0].this_bucket.arn] 182 | } 183 | } 184 | 185 | dynamic "statement" { 186 | for_each = local.is_master_account && length(var.member_accounts) > 0 ? [var.member_accounts] : [] 187 | 188 | content { 189 | sid = "AWSConfigBucketDeliveryForMemberAccounts" 190 | principals { 191 | type = "AWS" 192 | identifiers = [for account in statement.value : "arn:aws:iam::${account.account_id}:root"] 193 | } 194 | actions = ["s3:PutObject"] 195 | resources = [for account in statement.value : "${local.audit_log_config_destination}/AWSLogs/${account.account_id}/Config/*"] 196 | condition { 197 | test = "StringEquals" 198 | variable = "s3:x-amz-acl" 199 | values = ["bucket-owner-full-control"] 200 | } 201 | } 202 | } 203 | } 204 | 205 | # Apply policies for AWS Config log delivery based on Amazon Virtual Private Cloud User Guide. 206 | # This policy is necessary only when the log destination of VPC Flow Logs is set to S3. 207 | # https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-s3.html#flow-logs-s3-permissions 208 | data "aws_iam_policy_document" "audit_log_flow_logs" { 209 | count = !local.use_external_bucket && local.flow_logs_to_s3 ? 1 : 0 210 | 211 | source_policy_documents = [data.aws_iam_policy_document.audit_log_config[0].json] 212 | 213 | statement { 214 | sid = "AWSLogDeliveryAclCheck" 215 | actions = ["s3:GetBucketAcl"] 216 | principals { 217 | type = "Service" 218 | identifiers = ["delivery.logs.amazonaws.com"] 219 | } 220 | resources = [module.audit_log_bucket[0].this_bucket.arn] 221 | } 222 | 223 | statement { 224 | sid = "AWSLogDeliveryWrite" 225 | actions = ["s3:PutObject"] 226 | principals { 227 | type = "Service" 228 | identifiers = ["delivery.logs.amazonaws.com"] 229 | } 230 | resources = concat( 231 | ["${local.audit_log_flow_logs_destination}/AWSLogs/${var.aws_account_id}/*"], 232 | local.is_master_account ? [for account in var.member_accounts : "${local.audit_log_flow_logs_destination}/AWSLogs/${account.account_id}/*"] : [] 233 | ) 234 | condition { 235 | test = "StringEquals" 236 | variable = "s3:x-amz-acl" 237 | values = ["bucket-owner-full-control"] 238 | } 239 | } 240 | } 241 | 242 | 243 | data "aws_iam_policy_document" "audit_log" { 244 | count = local.use_external_bucket ? 0 : 1 245 | 246 | source_policy_documents = [local.flow_logs_to_s3 ? data.aws_iam_policy_document.audit_log_flow_logs[0].json : data.aws_iam_policy_document.audit_log_config[0].json] 247 | override_policy_documents = [var.audit_log_bucket_custom_policy_json] 248 | } 249 | 250 | resource "aws_s3_bucket_policy" "audit_log" { 251 | count = local.use_external_bucket ? 0 : 1 252 | 253 | bucket = module.audit_log_bucket[0].this_bucket.id 254 | policy = data.aws_iam_policy_document.audit_log[0].json 255 | } 256 | -------------------------------------------------------------------------------- /docs/upgrade-1.0.md: -------------------------------------------------------------------------------- 1 | # Version 1.0 Upgrade Guide 2 | 3 | This document outlines a way to upgrade this module from v0.x to v1.0 or later. 4 | The following guidance only applies if `var.use_external_audit_log_bucket` is set to `false`, which is a default behavior. 5 | 6 | Following the changes introduced in AWS provider v4.0, several configurations for S3 buckets were extracted from `aws_s3_bucket` resource to newly added resources. 7 | It is recommended to import these resources before running `terraform apply` to prevent data loss. 8 | 9 | See [the upgrade guide for AWS provider] for more detail. 10 | 11 | ## Audit log bucket migrations 12 | 13 | Following configurations from `module.audit_log_bucket[0].aws_s3_bucket.content` were extracted to separated resources. 14 | 15 | - `module.audit_log_bucket[0].aws_s3_bucket_acl.content` 16 | - `module.audit_log_bucket[0].aws_s3_bucket_lifecycle_configuration.content` 17 | - `module.audit_log_bucket[0].aws_s3_bucket_logging.content` 18 | - `module.audit_log_bucket[0].aws_s3_bucket_server_side_encryption_configuration.content` 19 | - `module.audit_log_bucket[0].aws_s3_bucket_versioning.content` 20 | 21 | To import the current configuration into these resources, use `terraform import` command as follows. 22 | 23 | ```sh 24 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_acl.content" "$AUDIT_LOG_BUCKET" 25 | 26 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_lifecycle_configuration.content" "$AUDIT_LOG_BUCKET" 27 | 28 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_logging.content" "$AUDIT_LOG_BUCKET" 29 | 30 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_server_side_encryption_configuration.content" "$AUDIT_LOG_BUCKET" 31 | 32 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_versioning.content" "$AUDIT_LOG_BUCKET" 33 | ``` 34 | 35 | ### Notes 36 | 37 | - `$MODULE_PATH` should be replaced the actual path of this module in your project, e.g. `module.secure_baseline`. 38 | - `$AUDIT_LOG_BUCKET` should be replaced with the state bucket name. The actual value in your state file as `module.audit_log_bucket.aws_s3_bucket[0].content.id`. 39 | 40 | ## Access logging bucket migrations 41 | 42 | Following configurations from `module.audit_log_bucket[0].aws_s3_bucket.access_log` were extracted to separated resources. 43 | 44 | - `module.audit_log_bucket[0].aws_s3_bucket.access_log` 45 | - `module.audit_log_bucket[0].aws_s3_bucket_acl.access_log` 46 | - `module.audit_log_bucket[0].aws_s3_bucket_lifecycle_configuration.access_log` 47 | - `module.audit_log_bucket[0].aws_s3_bucket_server_side_encryption_configuration.access_log` 48 | 49 | These resources can be imported by `terraform import` command as well. 50 | 51 | ```sh 52 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket.access_log" "$ACCESS_LOG_BUCKET" 53 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_acl.access_log" "$ACCESS_LOG_BUCKET" 54 | 55 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_lifecycle_configuration.access_log" "$ACCESS_LOG_BUCKET" 56 | 57 | $ terraform import "$MODULE_PATH.module.audit_log_bucket[0].aws_s3_bucket_server_side_encryption_configuration.access_log" "$ACCESS_LOG_BUCKET" 58 | 59 | ``` 60 | 61 | ### Notes 62 | 63 | - `$MODULE_PATH` should be replaced the actual path of this module in your project, e.g. `module.secure_baseline`. 64 | - `$ACCESS_LOG_BUCKET` should be replaced with the state bucket name. The actual value in your state file as `module.audit_log_bucket[0].aws_s3_bucket.access_log.id`. 65 | 66 | [aws provider]: https://github.com/hashicorp/terraform-provider-aws 67 | [the upgrade guide for aws provider]: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/version-4-upgrade 68 | -------------------------------------------------------------------------------- /ebs_baselines.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # EBS Baseline 3 | # -------------------------------------------------------------------------------------------------- 4 | 5 | module "ebs_baseline_ap-northeast-1" { 6 | count = contains(var.target_regions, "ap-northeast-1") ? 1 : 0 7 | source = "./modules/ebs-baseline" 8 | 9 | providers = { 10 | aws = aws.ap-northeast-1 11 | } 12 | } 13 | 14 | module "ebs_baseline_ap-northeast-2" { 15 | count = contains(var.target_regions, "ap-northeast-2") ? 1 : 0 16 | source = "./modules/ebs-baseline" 17 | 18 | providers = { 19 | aws = aws.ap-northeast-2 20 | } 21 | } 22 | 23 | module "ebs_baseline_ap-northeast-3" { 24 | count = contains(var.target_regions, "ap-northeast-3") ? 1 : 0 25 | source = "./modules/ebs-baseline" 26 | 27 | providers = { 28 | aws = aws.ap-northeast-3 29 | } 30 | } 31 | 32 | module "ebs_baseline_ap-south-1" { 33 | count = contains(var.target_regions, "ap-south-1") ? 1 : 0 34 | source = "./modules/ebs-baseline" 35 | 36 | providers = { 37 | aws = aws.ap-south-1 38 | } 39 | } 40 | 41 | module "ebs_baseline_ap-southeast-1" { 42 | count = contains(var.target_regions, "ap-southeast-1") ? 1 : 0 43 | source = "./modules/ebs-baseline" 44 | 45 | providers = { 46 | aws = aws.ap-southeast-1 47 | } 48 | } 49 | 50 | module "ebs_baseline_ap-southeast-2" { 51 | count = contains(var.target_regions, "ap-southeast-2") ? 1 : 0 52 | source = "./modules/ebs-baseline" 53 | 54 | providers = { 55 | aws = aws.ap-southeast-2 56 | } 57 | } 58 | 59 | module "ebs_baseline_ca-central-1" { 60 | count = contains(var.target_regions, "ca-central-1") ? 1 : 0 61 | source = "./modules/ebs-baseline" 62 | 63 | providers = { 64 | aws = aws.ca-central-1 65 | } 66 | } 67 | 68 | module "ebs_baseline_eu-central-1" { 69 | count = contains(var.target_regions, "eu-central-1") ? 1 : 0 70 | source = "./modules/ebs-baseline" 71 | 72 | providers = { 73 | aws = aws.eu-central-1 74 | } 75 | } 76 | 77 | module "ebs_baseline_eu-north-1" { 78 | count = contains(var.target_regions, "eu-north-1") ? 1 : 0 79 | source = "./modules/ebs-baseline" 80 | 81 | providers = { 82 | aws = aws.eu-north-1 83 | } 84 | } 85 | 86 | module "ebs_baseline_eu-west-1" { 87 | count = contains(var.target_regions, "eu-west-1") ? 1 : 0 88 | source = "./modules/ebs-baseline" 89 | 90 | providers = { 91 | aws = aws.eu-west-1 92 | } 93 | } 94 | 95 | module "ebs_baseline_eu-west-2" { 96 | count = contains(var.target_regions, "eu-west-2") ? 1 : 0 97 | source = "./modules/ebs-baseline" 98 | 99 | providers = { 100 | aws = aws.eu-west-2 101 | } 102 | } 103 | 104 | module "ebs_baseline_eu-west-3" { 105 | count = contains(var.target_regions, "eu-west-3") ? 1 : 0 106 | source = "./modules/ebs-baseline" 107 | 108 | providers = { 109 | aws = aws.eu-west-3 110 | } 111 | } 112 | 113 | module "ebs_baseline_sa-east-1" { 114 | count = contains(var.target_regions, "sa-east-1") ? 1 : 0 115 | source = "./modules/ebs-baseline" 116 | 117 | providers = { 118 | aws = aws.sa-east-1 119 | } 120 | } 121 | 122 | module "ebs_baseline_us-east-1" { 123 | count = contains(var.target_regions, "us-east-1") ? 1 : 0 124 | source = "./modules/ebs-baseline" 125 | 126 | providers = { 127 | aws = aws.us-east-1 128 | } 129 | } 130 | 131 | module "ebs_baseline_us-east-2" { 132 | count = contains(var.target_regions, "us-east-2") ? 1 : 0 133 | source = "./modules/ebs-baseline" 134 | 135 | providers = { 136 | aws = aws.us-east-2 137 | } 138 | } 139 | 140 | module "ebs_baseline_us-west-1" { 141 | count = contains(var.target_regions, "us-west-1") ? 1 : 0 142 | source = "./modules/ebs-baseline" 143 | 144 | providers = { 145 | aws = aws.us-west-1 146 | } 147 | } 148 | 149 | module "ebs_baseline_us-west-2" { 150 | count = contains(var.target_regions, "us-west-2") ? 1 : 0 151 | source = "./modules/ebs-baseline" 152 | 153 | providers = { 154 | aws = aws.us-west-2 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /examples/external-bucket/bucket.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "logs" { 2 | bucket = var.audit_s3_bucket_name 3 | force_destroy = true 4 | } 5 | 6 | resource "aws_s3_bucket_acl" "logs" { 7 | bucket = aws_s3_bucket.logs.id 8 | acl = "private" 9 | } 10 | 11 | data "aws_iam_policy_document" "logs_bucket_policy" { 12 | statement { 13 | sid = "AWSCloudTrailAclCheckForConfig" 14 | actions = ["s3:GetBucketAcl"] 15 | principals { 16 | type = "Service" 17 | identifiers = ["config.amazonaws.com"] 18 | } 19 | resources = [aws_s3_bucket.logs.arn] 20 | } 21 | 22 | statement { 23 | sid = "AWSCloudTrailWriteForConfig" 24 | actions = ["s3:PutObject"] 25 | principals { 26 | type = "Service" 27 | identifiers = ["config.amazonaws.com"] 28 | } 29 | resources = ["${aws_s3_bucket.logs.arn}/config/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*"] 30 | condition { 31 | test = "StringEquals" 32 | variable = "s3:x-amz-acl" 33 | values = ["bucket-owner-full-control"] 34 | } 35 | } 36 | 37 | statement { 38 | sid = "AWSCloudTrailAclCheckForCloudTrail" 39 | actions = ["s3:GetBucketAcl"] 40 | principals { 41 | type = "Service" 42 | identifiers = ["cloudtrail.amazonaws.com"] 43 | } 44 | resources = [aws_s3_bucket.logs.arn] 45 | } 46 | 47 | statement { 48 | sid = "AWSCloudTrailWriteForCloudTrail" 49 | actions = ["s3:PutObject"] 50 | principals { 51 | type = "Service" 52 | identifiers = ["cloudtrail.amazonaws.com"] 53 | } 54 | resources = ["${aws_s3_bucket.logs.arn}/cloudtrail/AWSLogs/*"] 55 | condition { 56 | test = "StringEquals" 57 | variable = "s3:x-amz-acl" 58 | values = ["bucket-owner-full-control"] 59 | } 60 | } 61 | } 62 | 63 | resource "aws_s3_bucket_policy" "logs" { 64 | bucket = aws_s3_bucket.logs.id 65 | policy = data.aws_iam_policy_document.logs_bucket_policy.json 66 | } 67 | -------------------------------------------------------------------------------- /examples/external-bucket/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | 12 | provider "aws" { 13 | region = var.region 14 | } 15 | 16 | data "aws_caller_identity" "current" { 17 | } 18 | 19 | resource "aws_iam_user" "admin" { 20 | name = "admin" 21 | } 22 | 23 | module "secure_baseline" { 24 | source = "../../" 25 | 26 | audit_log_bucket_name = aws_s3_bucket.logs.id 27 | use_external_audit_log_bucket = true 28 | aws_account_id = data.aws_caller_identity.current.account_id 29 | region = var.region 30 | support_iam_role_principal_arns = [aws_iam_user.admin.arn] 31 | 32 | providers = { 33 | aws = aws 34 | aws.ap-northeast-1 = aws.ap-northeast-1 35 | aws.ap-northeast-2 = aws.ap-northeast-2 36 | aws.ap-northeast-3 = aws.ap-northeast-3 37 | aws.ap-south-1 = aws.ap-south-1 38 | aws.ap-southeast-1 = aws.ap-southeast-1 39 | aws.ap-southeast-2 = aws.ap-southeast-2 40 | aws.ca-central-1 = aws.ca-central-1 41 | aws.eu-central-1 = aws.eu-central-1 42 | aws.eu-north-1 = aws.eu-north-1 43 | aws.eu-west-1 = aws.eu-west-1 44 | aws.eu-west-2 = aws.eu-west-2 45 | aws.eu-west-3 = aws.eu-west-3 46 | aws.sa-east-1 = aws.sa-east-1 47 | aws.us-east-1 = aws.us-east-1 48 | aws.us-east-2 = aws.us-east-2 49 | aws.us-west-1 = aws.us-west-1 50 | aws.us-west-2 = aws.us-west-2 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /examples/external-bucket/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/examples/external-bucket/outputs.tf -------------------------------------------------------------------------------- /examples/external-bucket/regions.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # A list of providers for all AWS regions. 3 | # Reference: https://docs.aws.amazon.com/general/latest/gr/rande.html 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = "ap-northeast-1" 8 | alias = "ap-northeast-1" 9 | } 10 | 11 | provider "aws" { 12 | region = "ap-northeast-2" 13 | alias = "ap-northeast-2" 14 | } 15 | 16 | provider "aws" { 17 | region = "ap-northeast-3" 18 | alias = "ap-northeast-3" 19 | } 20 | 21 | provider "aws" { 22 | region = "ap-south-1" 23 | alias = "ap-south-1" 24 | } 25 | 26 | provider "aws" { 27 | region = "ap-southeast-1" 28 | alias = "ap-southeast-1" 29 | } 30 | 31 | provider "aws" { 32 | region = "ap-southeast-2" 33 | alias = "ap-southeast-2" 34 | } 35 | 36 | provider "aws" { 37 | region = "ca-central-1" 38 | alias = "ca-central-1" 39 | } 40 | 41 | provider "aws" { 42 | region = "eu-central-1" 43 | alias = "eu-central-1" 44 | } 45 | 46 | provider "aws" { 47 | region = "eu-north-1" 48 | alias = "eu-north-1" 49 | } 50 | 51 | provider "aws" { 52 | region = "eu-west-1" 53 | alias = "eu-west-1" 54 | } 55 | 56 | provider "aws" { 57 | region = "eu-west-2" 58 | alias = "eu-west-2" 59 | } 60 | 61 | provider "aws" { 62 | region = "eu-west-3" 63 | alias = "eu-west-3" 64 | } 65 | 66 | provider "aws" { 67 | region = "sa-east-1" 68 | alias = "sa-east-1" 69 | } 70 | 71 | provider "aws" { 72 | region = "us-east-1" 73 | alias = "us-east-1" 74 | } 75 | 76 | provider "aws" { 77 | region = "us-east-2" 78 | alias = "us-east-2" 79 | } 80 | 81 | provider "aws" { 82 | region = "us-west-1" 83 | alias = "us-west-1" 84 | } 85 | 86 | provider "aws" { 87 | region = "us-west-2" 88 | alias = "us-west-2" 89 | } 90 | 91 | -------------------------------------------------------------------------------- /examples/external-bucket/variables.tf: -------------------------------------------------------------------------------- 1 | variable "audit_s3_bucket_name" { 2 | description = "The name of the S3 bucket to store various audit logs." 3 | type = string 4 | } 5 | 6 | variable "region" { 7 | description = "The AWS region in which global resources are set up." 8 | type = string 9 | default = "us-east-1" 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/organization/README.md: -------------------------------------------------------------------------------- 1 | # organization example 2 | 3 | This example shows how you can configure multiple AWS accounts, one master account and several member accounts, in AWS Organization with secure-baseline module. 4 | 5 | `secure-baseline` module can be set to configure the individual AWS account as well as accounts in AWS Organization. This behavior is controlled by `account_type` input variable, the default value is `individual` meaning that the AWS account assumed to have no relation with other AWS accounts. 6 | When it sets to `master`, this module configure the account to be ready to gather various audit logs from other member accounts as well as from the master account itself. Member accounts should set `account_type` to `member` , then their audit logs are sent to the master account so that all information are centrally managed there. 7 | 8 | ## Master Account 9 | 10 | In the master account configuration, you need to set `account_type` to `master` and specify member account information in `member_accounts`. 11 | 12 | The following shows a sample usage. 13 | 14 | ```hcl 15 | module "secure_baseline" { 16 | source = "nozaq/secure_baseline" 17 | 18 | account_type = "master" 19 | member_accounts = [ 20 | { 21 | account_id = "id_of_the_member_account" 22 | email = "email_of_the_member_account@example.com" 23 | } 24 | ] 25 | 26 | audit_log_bucket_name = "audit-log-bucket-1234" 27 | 28 | ... 29 | } 30 | ``` 31 | 32 | The S3 bucket named `audit-log-bucket-1234` is created in this master account, and used to store audit log records from both the master account and member accounts. 33 | 34 | ## Member Account 35 | 36 | In a member account configuration, you need to set `account_type` to `member` and specify master account ID in `master_account_id`. 37 | 38 | ```hcl 39 | data "aws_organizations_organization" "org" {} 40 | 41 | module "secure_baseline" { 42 | source = "nozaq/secure_baseline" 43 | 44 | account_type = "member" 45 | master_account_id = data.aws_organizations_organization.org.master_account_id 46 | use_external_audit_log_bucket = true 47 | audit_log_bucket_name = "audit-log-bucket-1234" 48 | 49 | ... 50 | } 51 | ``` 52 | 53 | Since `use_external_audit_log_bucket` set to `true`, no S3 bucket is created in member accounts. Instead, the bucket in the master account is used to store audit log records. You can create an individual S3 bucket in each member account by setting it to `false`. 54 | -------------------------------------------------------------------------------- /examples/organization/master/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | 12 | provider "aws" { 13 | region = var.region 14 | } 15 | 16 | data "aws_caller_identity" "current" { 17 | } 18 | 19 | resource "aws_iam_user" "admin" { 20 | name = "admin" 21 | } 22 | 23 | resource "aws_organizations_organization" "org" { 24 | aws_service_access_principals = [ 25 | "access-analyzer.amazonaws.com", 26 | "cloudtrail.amazonaws.com", 27 | "config.amazonaws.com", 28 | ] 29 | feature_set = "ALL" 30 | } 31 | 32 | module "secure_baseline" { 33 | source = "../../../" 34 | 35 | account_type = "master" 36 | member_accounts = var.member_accounts 37 | audit_log_bucket_name = var.audit_s3_bucket_name 38 | aws_account_id = data.aws_caller_identity.current.account_id 39 | region = var.region 40 | support_iam_role_principal_arns = [aws_iam_user.admin.arn] 41 | guardduty_disable_email_notification = true 42 | 43 | # Setting it to true means all audit logs are automatically deleted 44 | # when you run `terraform destroy`. 45 | # Note that it might be inappropriate for highly secured environment. 46 | audit_log_bucket_force_destroy = true 47 | 48 | providers = { 49 | aws = aws 50 | aws.ap-northeast-1 = aws.ap-northeast-1 51 | aws.ap-northeast-2 = aws.ap-northeast-2 52 | aws.ap-northeast-3 = aws.ap-northeast-3 53 | aws.ap-south-1 = aws.ap-south-1 54 | aws.ap-southeast-1 = aws.ap-southeast-1 55 | aws.ap-southeast-2 = aws.ap-southeast-2 56 | aws.ca-central-1 = aws.ca-central-1 57 | aws.eu-central-1 = aws.eu-central-1 58 | aws.eu-north-1 = aws.eu-north-1 59 | aws.eu-west-1 = aws.eu-west-1 60 | aws.eu-west-2 = aws.eu-west-2 61 | aws.eu-west-3 = aws.eu-west-3 62 | aws.sa-east-1 = aws.sa-east-1 63 | aws.us-east-1 = aws.us-east-1 64 | aws.us-east-2 = aws.us-east-2 65 | aws.us-west-1 = aws.us-west-1 66 | aws.us-west-2 = aws.us-west-2 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /examples/organization/master/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/examples/organization/master/outputs.tf -------------------------------------------------------------------------------- /examples/organization/master/regions.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # A list of providers for all AWS regions. 3 | # Reference: https://docs.aws.amazon.com/general/latest/gr/rande.html 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = "ap-northeast-1" 8 | alias = "ap-northeast-1" 9 | } 10 | 11 | provider "aws" { 12 | region = "ap-northeast-2" 13 | alias = "ap-northeast-2" 14 | } 15 | 16 | provider "aws" { 17 | region = "ap-northeast-3" 18 | alias = "ap-northeast-3" 19 | } 20 | 21 | provider "aws" { 22 | region = "ap-south-1" 23 | alias = "ap-south-1" 24 | } 25 | 26 | provider "aws" { 27 | region = "ap-southeast-1" 28 | alias = "ap-southeast-1" 29 | } 30 | 31 | provider "aws" { 32 | region = "ap-southeast-2" 33 | alias = "ap-southeast-2" 34 | } 35 | 36 | provider "aws" { 37 | region = "ca-central-1" 38 | alias = "ca-central-1" 39 | } 40 | 41 | provider "aws" { 42 | region = "eu-central-1" 43 | alias = "eu-central-1" 44 | } 45 | 46 | provider "aws" { 47 | region = "eu-north-1" 48 | alias = "eu-north-1" 49 | } 50 | 51 | provider "aws" { 52 | region = "eu-west-1" 53 | alias = "eu-west-1" 54 | } 55 | 56 | provider "aws" { 57 | region = "eu-west-2" 58 | alias = "eu-west-2" 59 | } 60 | 61 | provider "aws" { 62 | region = "eu-west-3" 63 | alias = "eu-west-3" 64 | } 65 | 66 | provider "aws" { 67 | region = "sa-east-1" 68 | alias = "sa-east-1" 69 | } 70 | 71 | provider "aws" { 72 | region = "us-east-1" 73 | alias = "us-east-1" 74 | } 75 | 76 | provider "aws" { 77 | region = "us-east-2" 78 | alias = "us-east-2" 79 | } 80 | 81 | provider "aws" { 82 | region = "us-west-1" 83 | alias = "us-west-1" 84 | } 85 | 86 | provider "aws" { 87 | region = "us-west-2" 88 | alias = "us-west-2" 89 | } 90 | 91 | -------------------------------------------------------------------------------- /examples/organization/master/variables.tf: -------------------------------------------------------------------------------- 1 | variable "audit_s3_bucket_name" { 2 | description = "The name of the S3 bucket to store various audit logs." 3 | type = string 4 | } 5 | 6 | variable "member_accounts" { 7 | description = "A list of AWS account IDs." 8 | type = list(object({ 9 | account_id = string 10 | email = string 11 | })) 12 | } 13 | 14 | variable "region" { 15 | description = "The AWS region in which global resources are set up." 16 | type = string 17 | default = "us-east-1" 18 | } 19 | 20 | -------------------------------------------------------------------------------- /examples/organization/member/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | 12 | provider "aws" { 13 | region = var.region 14 | } 15 | 16 | data "aws_caller_identity" "current" { 17 | } 18 | 19 | resource "aws_iam_user" "admin" { 20 | name = "admin" 21 | } 22 | 23 | data "aws_organizations_organization" "org" {} 24 | 25 | module "secure_baseline" { 26 | source = "../../../" 27 | 28 | account_type = "member" 29 | master_account_id = data.aws_organizations_organization.org.master_account_id 30 | use_external_audit_log_bucket = true 31 | audit_log_bucket_name = var.audit_s3_bucket_name 32 | aws_account_id = data.aws_caller_identity.current.account_id 33 | region = var.region 34 | support_iam_role_principal_arns = [aws_iam_user.admin.arn] 35 | 36 | # Setting it to true means all audit logs are automatically deleted 37 | # when you run `terraform destroy`. 38 | # Note that it might be inappropriate for highly secured environment. 39 | audit_log_bucket_force_destroy = true 40 | 41 | providers = { 42 | aws = aws 43 | aws.ap-northeast-1 = aws.ap-northeast-1 44 | aws.ap-northeast-2 = aws.ap-northeast-2 45 | aws.ap-northeast-3 = aws.ap-northeast-3 46 | aws.ap-south-1 = aws.ap-south-1 47 | aws.ap-southeast-1 = aws.ap-southeast-1 48 | aws.ap-southeast-2 = aws.ap-southeast-2 49 | aws.ca-central-1 = aws.ca-central-1 50 | aws.eu-central-1 = aws.eu-central-1 51 | aws.eu-north-1 = aws.eu-north-1 52 | aws.eu-west-1 = aws.eu-west-1 53 | aws.eu-west-2 = aws.eu-west-2 54 | aws.eu-west-3 = aws.eu-west-3 55 | aws.sa-east-1 = aws.sa-east-1 56 | aws.us-east-1 = aws.us-east-1 57 | aws.us-east-2 = aws.us-east-2 58 | aws.us-west-1 = aws.us-west-1 59 | aws.us-west-2 = aws.us-west-2 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /examples/organization/member/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/examples/organization/member/outputs.tf -------------------------------------------------------------------------------- /examples/organization/member/regions.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # A list of providers for all AWS regions. 3 | # Reference: https://docs.aws.amazon.com/general/latest/gr/rande.html 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = "ap-northeast-1" 8 | alias = "ap-northeast-1" 9 | } 10 | 11 | provider "aws" { 12 | region = "ap-northeast-2" 13 | alias = "ap-northeast-2" 14 | } 15 | 16 | provider "aws" { 17 | region = "ap-northeast-3" 18 | alias = "ap-northeast-3" 19 | } 20 | 21 | provider "aws" { 22 | region = "ap-south-1" 23 | alias = "ap-south-1" 24 | } 25 | 26 | provider "aws" { 27 | region = "ap-southeast-1" 28 | alias = "ap-southeast-1" 29 | } 30 | 31 | provider "aws" { 32 | region = "ap-southeast-2" 33 | alias = "ap-southeast-2" 34 | } 35 | 36 | provider "aws" { 37 | region = "ca-central-1" 38 | alias = "ca-central-1" 39 | } 40 | 41 | provider "aws" { 42 | region = "eu-central-1" 43 | alias = "eu-central-1" 44 | } 45 | 46 | provider "aws" { 47 | region = "eu-north-1" 48 | alias = "eu-north-1" 49 | } 50 | 51 | provider "aws" { 52 | region = "eu-west-1" 53 | alias = "eu-west-1" 54 | } 55 | 56 | provider "aws" { 57 | region = "eu-west-2" 58 | alias = "eu-west-2" 59 | } 60 | 61 | provider "aws" { 62 | region = "eu-west-3" 63 | alias = "eu-west-3" 64 | } 65 | 66 | provider "aws" { 67 | region = "sa-east-1" 68 | alias = "sa-east-1" 69 | } 70 | 71 | provider "aws" { 72 | region = "us-east-1" 73 | alias = "us-east-1" 74 | } 75 | 76 | provider "aws" { 77 | region = "us-east-2" 78 | alias = "us-east-2" 79 | } 80 | 81 | provider "aws" { 82 | region = "us-west-1" 83 | alias = "us-west-1" 84 | } 85 | 86 | provider "aws" { 87 | region = "us-west-2" 88 | alias = "us-west-2" 89 | } 90 | 91 | -------------------------------------------------------------------------------- /examples/organization/member/variables.tf: -------------------------------------------------------------------------------- 1 | variable "audit_s3_bucket_name" { 2 | description = "The name of the S3 bucket to store various audit logs." 3 | type = string 4 | } 5 | 6 | variable "region" { 7 | description = "The AWS region in which global resources are set up." 8 | type = string 9 | default = "us-east-1" 10 | } 11 | -------------------------------------------------------------------------------- /examples/select-region/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | 12 | provider "aws" { 13 | region = var.region 14 | } 15 | 16 | data "aws_caller_identity" "current" { 17 | } 18 | 19 | resource "aws_iam_user" "admin" { 20 | name = "admin" 21 | } 22 | 23 | module "secure_baseline" { 24 | source = "../../" 25 | 26 | audit_log_bucket_name = var.audit_s3_bucket_name 27 | aws_account_id = data.aws_caller_identity.current.account_id 28 | region = var.region 29 | support_iam_role_principal_arns = [aws_iam_user.admin.arn] 30 | target_regions = ["us-east-1", "us-west-1"] 31 | 32 | # Setting it to true means all audit logs are automatically deleted 33 | # when you run `terraform destroy`. 34 | # Note that it might be inappropriate for highly secured environment. 35 | audit_log_bucket_force_destroy = true 36 | 37 | # This module only configure regions specified in target_regions argument though, 38 | # all providers still need to be passed to the module. 39 | providers = { 40 | aws = aws 41 | aws.ap-northeast-1 = aws.ap-northeast-1 42 | aws.ap-northeast-2 = aws.ap-northeast-2 43 | aws.ap-northeast-3 = aws.ap-northeast-3 44 | aws.ap-south-1 = aws.ap-south-1 45 | aws.ap-southeast-1 = aws.ap-southeast-1 46 | aws.ap-southeast-2 = aws.ap-southeast-2 47 | aws.ca-central-1 = aws.ca-central-1 48 | aws.eu-central-1 = aws.eu-central-1 49 | aws.eu-north-1 = aws.eu-north-1 50 | aws.eu-west-1 = aws.eu-west-1 51 | aws.eu-west-2 = aws.eu-west-2 52 | aws.eu-west-3 = aws.eu-west-3 53 | aws.sa-east-1 = aws.sa-east-1 54 | aws.us-east-1 = aws.us-east-1 55 | aws.us-east-2 = aws.us-east-2 56 | aws.us-west-1 = aws.us-west-1 57 | aws.us-west-2 = aws.us-west-2 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/select-region/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/examples/select-region/outputs.tf -------------------------------------------------------------------------------- /examples/select-region/regions.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # A list of providers for all AWS regions. 3 | # Reference: https://docs.aws.amazon.com/general/latest/gr/rande.html 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = "ap-northeast-1" 8 | alias = "ap-northeast-1" 9 | } 10 | 11 | provider "aws" { 12 | region = "ap-northeast-2" 13 | alias = "ap-northeast-2" 14 | } 15 | 16 | provider "aws" { 17 | region = "ap-northeast-3" 18 | alias = "ap-northeast-3" 19 | } 20 | 21 | provider "aws" { 22 | region = "ap-south-1" 23 | alias = "ap-south-1" 24 | } 25 | 26 | provider "aws" { 27 | region = "ap-southeast-1" 28 | alias = "ap-southeast-1" 29 | } 30 | 31 | provider "aws" { 32 | region = "ap-southeast-2" 33 | alias = "ap-southeast-2" 34 | } 35 | 36 | provider "aws" { 37 | region = "ca-central-1" 38 | alias = "ca-central-1" 39 | } 40 | 41 | provider "aws" { 42 | region = "eu-central-1" 43 | alias = "eu-central-1" 44 | } 45 | 46 | provider "aws" { 47 | region = "eu-north-1" 48 | alias = "eu-north-1" 49 | } 50 | 51 | provider "aws" { 52 | region = "eu-west-1" 53 | alias = "eu-west-1" 54 | } 55 | 56 | provider "aws" { 57 | region = "eu-west-2" 58 | alias = "eu-west-2" 59 | } 60 | 61 | provider "aws" { 62 | region = "eu-west-3" 63 | alias = "eu-west-3" 64 | } 65 | 66 | provider "aws" { 67 | region = "sa-east-1" 68 | alias = "sa-east-1" 69 | } 70 | 71 | provider "aws" { 72 | region = "us-east-1" 73 | alias = "us-east-1" 74 | } 75 | 76 | provider "aws" { 77 | region = "us-east-2" 78 | alias = "us-east-2" 79 | } 80 | 81 | provider "aws" { 82 | region = "us-west-1" 83 | alias = "us-west-1" 84 | } 85 | 86 | provider "aws" { 87 | region = "us-west-2" 88 | alias = "us-west-2" 89 | } 90 | 91 | -------------------------------------------------------------------------------- /examples/select-region/variables.tf: -------------------------------------------------------------------------------- 1 | variable "audit_s3_bucket_name" { 2 | description = "The name of the S3 bucket to store various audit logs." 3 | type = string 4 | } 5 | 6 | variable "region" { 7 | description = "The AWS region in which global resources are set up." 8 | type = string 9 | default = "us-east-1" 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | 12 | provider "aws" { 13 | region = var.region 14 | } 15 | 16 | data "aws_caller_identity" "current" { 17 | } 18 | 19 | resource "aws_iam_user" "admin" { 20 | name = "admin" 21 | } 22 | 23 | module "secure_baseline" { 24 | source = "../../" 25 | 26 | audit_log_bucket_name = var.audit_s3_bucket_name 27 | aws_account_id = data.aws_caller_identity.current.account_id 28 | region = var.region 29 | support_iam_role_principal_arns = [aws_iam_user.admin.arn] 30 | 31 | # Setting it to true means all audit logs are automatically deleted 32 | # when you run `terraform destroy`. 33 | # Note that it might be inappropriate for highly secured environment. 34 | audit_log_bucket_force_destroy = true 35 | 36 | providers = { 37 | aws = aws 38 | aws.ap-northeast-1 = aws.ap-northeast-1 39 | aws.ap-northeast-2 = aws.ap-northeast-2 40 | aws.ap-northeast-3 = aws.ap-northeast-3 41 | aws.ap-south-1 = aws.ap-south-1 42 | aws.ap-southeast-1 = aws.ap-southeast-1 43 | aws.ap-southeast-2 = aws.ap-southeast-2 44 | aws.ca-central-1 = aws.ca-central-1 45 | aws.eu-central-1 = aws.eu-central-1 46 | aws.eu-north-1 = aws.eu-north-1 47 | aws.eu-west-1 = aws.eu-west-1 48 | aws.eu-west-2 = aws.eu-west-2 49 | aws.eu-west-3 = aws.eu-west-3 50 | aws.sa-east-1 = aws.sa-east-1 51 | aws.us-east-1 = aws.us-east-1 52 | aws.us-east-2 = aws.us-east-2 53 | aws.us-west-1 = aws.us-west-1 54 | aws.us-west-2 = aws.us-west-2 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /examples/simple/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/examples/simple/outputs.tf -------------------------------------------------------------------------------- /examples/simple/regions.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # A list of providers for all AWS regions. 3 | # Reference: https://docs.aws.amazon.com/general/latest/gr/rande.html 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = "ap-northeast-1" 8 | alias = "ap-northeast-1" 9 | } 10 | 11 | provider "aws" { 12 | region = "ap-northeast-2" 13 | alias = "ap-northeast-2" 14 | } 15 | 16 | provider "aws" { 17 | region = "ap-northeast-3" 18 | alias = "ap-northeast-3" 19 | } 20 | 21 | provider "aws" { 22 | region = "ap-south-1" 23 | alias = "ap-south-1" 24 | } 25 | 26 | provider "aws" { 27 | region = "ap-southeast-1" 28 | alias = "ap-southeast-1" 29 | } 30 | 31 | provider "aws" { 32 | region = "ap-southeast-2" 33 | alias = "ap-southeast-2" 34 | } 35 | 36 | provider "aws" { 37 | region = "ca-central-1" 38 | alias = "ca-central-1" 39 | } 40 | 41 | provider "aws" { 42 | region = "eu-central-1" 43 | alias = "eu-central-1" 44 | } 45 | 46 | provider "aws" { 47 | region = "eu-north-1" 48 | alias = "eu-north-1" 49 | } 50 | 51 | provider "aws" { 52 | region = "eu-west-1" 53 | alias = "eu-west-1" 54 | } 55 | 56 | provider "aws" { 57 | region = "eu-west-2" 58 | alias = "eu-west-2" 59 | } 60 | 61 | provider "aws" { 62 | region = "eu-west-3" 63 | alias = "eu-west-3" 64 | } 65 | 66 | provider "aws" { 67 | region = "sa-east-1" 68 | alias = "sa-east-1" 69 | } 70 | 71 | provider "aws" { 72 | region = "us-east-1" 73 | alias = "us-east-1" 74 | } 75 | 76 | provider "aws" { 77 | region = "us-east-2" 78 | alias = "us-east-2" 79 | } 80 | 81 | provider "aws" { 82 | region = "us-west-1" 83 | alias = "us-west-1" 84 | } 85 | 86 | provider "aws" { 87 | region = "us-west-2" 88 | alias = "us-west-2" 89 | } 90 | 91 | -------------------------------------------------------------------------------- /examples/simple/variables.tf: -------------------------------------------------------------------------------- 1 | variable "audit_s3_bucket_name" { 2 | description = "The name of the S3 bucket to store various audit logs." 3 | type = string 4 | } 5 | 6 | variable "region" { 7 | description = "The AWS region in which global resources are set up." 8 | type = string 9 | default = "us-east-1" 10 | } 11 | 12 | -------------------------------------------------------------------------------- /guardduty_baselines.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # GuardDuty Baseline 3 | # Needs to be set up in each region. 4 | # This is an extra configuration which is not included in CIS benchmark. 5 | # -------------------------------------------------------------------------------------------------- 6 | 7 | locals { 8 | guardduty_master_account_id = var.master_account_id 9 | guardduty_member_accounts = var.member_accounts 10 | } 11 | 12 | module "guardduty_baseline_ap-northeast-1" { 13 | count = contains(var.target_regions, "ap-northeast-1") && var.guardduty_enabled ? 1 : 0 14 | source = "./modules/guardduty-baseline" 15 | 16 | providers = { 17 | aws = aws.ap-northeast-1 18 | } 19 | 20 | disable_email_notification = var.guardduty_disable_email_notification 21 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 22 | invitation_message = var.guardduty_invitation_message 23 | master_account_id = local.guardduty_master_account_id 24 | member_accounts = local.guardduty_member_accounts 25 | 26 | tags = var.tags 27 | } 28 | 29 | module "guardduty_baseline_ap-northeast-2" { 30 | count = contains(var.target_regions, "ap-northeast-2") && var.guardduty_enabled ? 1 : 0 31 | source = "./modules/guardduty-baseline" 32 | 33 | providers = { 34 | aws = aws.ap-northeast-2 35 | } 36 | 37 | disable_email_notification = var.guardduty_disable_email_notification 38 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 39 | invitation_message = var.guardduty_invitation_message 40 | master_account_id = local.guardduty_master_account_id 41 | member_accounts = local.guardduty_member_accounts 42 | 43 | tags = var.tags 44 | } 45 | 46 | module "guardduty_baseline_ap-northeast-3" { 47 | count = contains(var.target_regions, "ap-northeast-3") && var.guardduty_enabled ? 1 : 0 48 | source = "./modules/guardduty-baseline" 49 | 50 | providers = { 51 | aws = aws.ap-northeast-3 52 | } 53 | 54 | disable_email_notification = var.guardduty_disable_email_notification 55 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 56 | invitation_message = var.guardduty_invitation_message 57 | master_account_id = local.guardduty_master_account_id 58 | member_accounts = local.guardduty_member_accounts 59 | 60 | tags = var.tags 61 | } 62 | 63 | module "guardduty_baseline_ap-south-1" { 64 | count = contains(var.target_regions, "ap-south-1") && var.guardduty_enabled ? 1 : 0 65 | source = "./modules/guardduty-baseline" 66 | 67 | providers = { 68 | aws = aws.ap-south-1 69 | } 70 | 71 | disable_email_notification = var.guardduty_disable_email_notification 72 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 73 | invitation_message = var.guardduty_invitation_message 74 | master_account_id = local.guardduty_master_account_id 75 | member_accounts = local.guardduty_member_accounts 76 | 77 | tags = var.tags 78 | } 79 | 80 | module "guardduty_baseline_ap-southeast-1" { 81 | count = contains(var.target_regions, "ap-southeast-1") && var.guardduty_enabled ? 1 : 0 82 | source = "./modules/guardduty-baseline" 83 | 84 | providers = { 85 | aws = aws.ap-southeast-1 86 | } 87 | 88 | disable_email_notification = var.guardduty_disable_email_notification 89 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 90 | invitation_message = var.guardduty_invitation_message 91 | master_account_id = local.guardduty_master_account_id 92 | member_accounts = local.guardduty_member_accounts 93 | 94 | tags = var.tags 95 | } 96 | 97 | module "guardduty_baseline_ap-southeast-2" { 98 | source = "./modules/guardduty-baseline" 99 | 100 | providers = { 101 | aws = aws.ap-southeast-2 102 | } 103 | 104 | count = contains(var.target_regions, "ap-southeast-2") && var.guardduty_enabled ? 1 : 0 105 | disable_email_notification = var.guardduty_disable_email_notification 106 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 107 | invitation_message = var.guardduty_invitation_message 108 | master_account_id = local.guardduty_master_account_id 109 | member_accounts = local.guardduty_member_accounts 110 | 111 | tags = var.tags 112 | } 113 | 114 | module "guardduty_baseline_ca-central-1" { 115 | count = contains(var.target_regions, "ca-central-1") && var.guardduty_enabled ? 1 : 0 116 | source = "./modules/guardduty-baseline" 117 | 118 | providers = { 119 | aws = aws.ca-central-1 120 | } 121 | 122 | disable_email_notification = var.guardduty_disable_email_notification 123 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 124 | invitation_message = var.guardduty_invitation_message 125 | master_account_id = local.guardduty_master_account_id 126 | member_accounts = local.guardduty_member_accounts 127 | 128 | tags = var.tags 129 | } 130 | 131 | module "guardduty_baseline_eu-central-1" { 132 | count = contains(var.target_regions, "eu-central-1") && var.guardduty_enabled ? 1 : 0 133 | source = "./modules/guardduty-baseline" 134 | 135 | providers = { 136 | aws = aws.eu-central-1 137 | } 138 | 139 | disable_email_notification = var.guardduty_disable_email_notification 140 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 141 | invitation_message = var.guardduty_invitation_message 142 | master_account_id = local.guardduty_master_account_id 143 | member_accounts = local.guardduty_member_accounts 144 | 145 | tags = var.tags 146 | } 147 | 148 | module "guardduty_baseline_eu-north-1" { 149 | count = contains(var.target_regions, "eu-north-1") && var.guardduty_enabled ? 1 : 0 150 | source = "./modules/guardduty-baseline" 151 | 152 | providers = { 153 | aws = aws.eu-north-1 154 | } 155 | 156 | disable_email_notification = var.guardduty_disable_email_notification 157 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 158 | invitation_message = var.guardduty_invitation_message 159 | master_account_id = local.guardduty_master_account_id 160 | member_accounts = local.guardduty_member_accounts 161 | 162 | tags = var.tags 163 | } 164 | 165 | module "guardduty_baseline_eu-west-1" { 166 | count = contains(var.target_regions, "eu-west-1") && var.guardduty_enabled ? 1 : 0 167 | source = "./modules/guardduty-baseline" 168 | 169 | providers = { 170 | aws = aws.eu-west-1 171 | } 172 | 173 | disable_email_notification = var.guardduty_disable_email_notification 174 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 175 | invitation_message = var.guardduty_invitation_message 176 | master_account_id = local.guardduty_master_account_id 177 | member_accounts = local.guardduty_member_accounts 178 | 179 | tags = var.tags 180 | } 181 | 182 | module "guardduty_baseline_eu-west-2" { 183 | count = contains(var.target_regions, "eu-west-2") && var.guardduty_enabled ? 1 : 0 184 | source = "./modules/guardduty-baseline" 185 | 186 | providers = { 187 | aws = aws.eu-west-2 188 | } 189 | 190 | disable_email_notification = var.guardduty_disable_email_notification 191 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 192 | invitation_message = var.guardduty_invitation_message 193 | master_account_id = local.guardduty_master_account_id 194 | member_accounts = local.guardduty_member_accounts 195 | 196 | tags = var.tags 197 | } 198 | 199 | module "guardduty_baseline_eu-west-3" { 200 | count = contains(var.target_regions, "eu-west-3") && var.guardduty_enabled ? 1 : 0 201 | source = "./modules/guardduty-baseline" 202 | 203 | providers = { 204 | aws = aws.eu-west-3 205 | } 206 | 207 | disable_email_notification = var.guardduty_disable_email_notification 208 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 209 | invitation_message = var.guardduty_invitation_message 210 | master_account_id = local.guardduty_master_account_id 211 | member_accounts = local.guardduty_member_accounts 212 | 213 | tags = var.tags 214 | } 215 | 216 | module "guardduty_baseline_sa-east-1" { 217 | count = contains(var.target_regions, "sa-east-1") && var.guardduty_enabled ? 1 : 0 218 | source = "./modules/guardduty-baseline" 219 | 220 | providers = { 221 | aws = aws.sa-east-1 222 | } 223 | 224 | disable_email_notification = var.guardduty_disable_email_notification 225 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 226 | invitation_message = var.guardduty_invitation_message 227 | master_account_id = local.guardduty_master_account_id 228 | member_accounts = local.guardduty_member_accounts 229 | 230 | tags = var.tags 231 | } 232 | 233 | module "guardduty_baseline_us-east-1" { 234 | count = contains(var.target_regions, "us-east-1") && var.guardduty_enabled ? 1 : 0 235 | source = "./modules/guardduty-baseline" 236 | 237 | providers = { 238 | aws = aws.us-east-1 239 | } 240 | 241 | disable_email_notification = var.guardduty_disable_email_notification 242 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 243 | invitation_message = var.guardduty_invitation_message 244 | master_account_id = local.guardduty_master_account_id 245 | member_accounts = local.guardduty_member_accounts 246 | 247 | tags = var.tags 248 | } 249 | 250 | module "guardduty_baseline_us-east-2" { 251 | count = contains(var.target_regions, "us-east-2") && var.guardduty_enabled ? 1 : 0 252 | source = "./modules/guardduty-baseline" 253 | 254 | providers = { 255 | aws = aws.us-east-2 256 | } 257 | 258 | disable_email_notification = var.guardduty_disable_email_notification 259 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 260 | invitation_message = var.guardduty_invitation_message 261 | master_account_id = local.guardduty_master_account_id 262 | member_accounts = local.guardduty_member_accounts 263 | 264 | tags = var.tags 265 | } 266 | 267 | module "guardduty_baseline_us-west-1" { 268 | count = contains(var.target_regions, "us-west-1") && var.guardduty_enabled ? 1 : 0 269 | source = "./modules/guardduty-baseline" 270 | 271 | providers = { 272 | aws = aws.us-west-1 273 | } 274 | 275 | disable_email_notification = var.guardduty_disable_email_notification 276 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 277 | invitation_message = var.guardduty_invitation_message 278 | master_account_id = local.guardduty_master_account_id 279 | member_accounts = local.guardduty_member_accounts 280 | 281 | tags = var.tags 282 | } 283 | 284 | module "guardduty_baseline_us-west-2" { 285 | count = contains(var.target_regions, "us-west-2") && var.guardduty_enabled ? 1 : 0 286 | source = "./modules/guardduty-baseline" 287 | 288 | providers = { 289 | aws = aws.us-west-2 290 | } 291 | 292 | disable_email_notification = var.guardduty_disable_email_notification 293 | finding_publishing_frequency = var.guardduty_finding_publishing_frequency 294 | invitation_message = var.guardduty_invitation_message 295 | master_account_id = local.guardduty_master_account_id 296 | member_accounts = local.guardduty_member_accounts 297 | 298 | tags = var.tags 299 | } 300 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | 9 | # A provider alias should be passed for each AWS region. 10 | # Reference: https://docs.aws.amazon.com/general/latest/gr/rande.html 11 | configuration_aliases = [ 12 | aws.ap-northeast-1, aws.ap-northeast-2, aws.ap-northeast-3, 13 | aws.ap-south-1, 14 | aws.ap-southeast-1, aws.ap-southeast-2, 15 | aws.ca-central-1, 16 | aws.eu-central-1, 17 | aws.eu-north-1, 18 | aws.eu-west-1, aws.eu-west-2, aws.eu-west-3, 19 | aws.sa-east-1, 20 | aws.us-east-1, aws.us-east-2, 21 | aws.us-west-1, aws.us-west-2, 22 | ] 23 | } 24 | } 25 | } 26 | 27 | data "aws_caller_identity" "current" {} 28 | 29 | locals { 30 | is_individual_account = var.account_type == "individual" 31 | is_master_account = var.account_type == "master" 32 | is_cloudtrail_enabled = var.cloudtrail_baseline_enabled && (local.is_individual_account || local.is_master_account) 33 | is_organization_trail = local.is_master_account && !var.turn_off_organization_trail 34 | } 35 | 36 | # -------------------------------------------------------------------------------------------------- 37 | # IAM Baseline 38 | # -------------------------------------------------------------------------------------------------- 39 | 40 | module "iam_baseline" { 41 | count = var.iam_baseline_enabled ? 1 : 0 42 | source = "./modules/iam-baseline" 43 | 44 | support_iam_role_name = var.support_iam_role_name 45 | support_iam_role_principal_arns = var.support_iam_role_principal_arns 46 | permissions_boundary_arn = var.permissions_boundary_arn 47 | minimum_password_length = var.minimum_password_length 48 | password_reuse_prevention = var.password_reuse_prevention 49 | require_lowercase_characters = var.require_lowercase_characters 50 | require_numbers = var.require_numbers 51 | require_uppercase_characters = var.require_uppercase_characters 52 | require_symbols = var.require_symbols 53 | allow_users_to_change_password = var.allow_users_to_change_password 54 | max_password_age = var.max_password_age 55 | create_password_policy = var.create_password_policy 56 | create_support_role = var.create_support_role 57 | 58 | tags = var.tags 59 | } 60 | 61 | # -------------------------------------------------------------------------------------------------- 62 | # CloudTrail Baseline 63 | # -------------------------------------------------------------------------------------------------- 64 | 65 | module "cloudtrail_baseline" { 66 | count = local.is_cloudtrail_enabled ? 1 : 0 67 | source = "./modules/cloudtrail-baseline" 68 | 69 | aws_account_id = var.aws_account_id 70 | cloudtrail_depends_on = [aws_s3_bucket_policy.audit_log] 71 | cloudtrail_name = var.cloudtrail_name 72 | cloudtrail_sns_topic_enabled = var.cloudtrail_sns_topic_enabled 73 | cloudtrail_sns_topic_name = var.cloudtrail_sns_topic_name 74 | cloudwatch_logs_enabled = var.cloudtrail_cloudwatch_logs_enabled 75 | cloudwatch_logs_group_name = var.cloudtrail_cloudwatch_logs_group_name 76 | cloudwatch_logs_retention_in_days = var.cloudwatch_logs_retention_in_days 77 | iam_role_name = var.cloudtrail_iam_role_name 78 | iam_role_policy_name = var.cloudtrail_iam_role_policy_name 79 | permissions_boundary_arn = var.permissions_boundary_arn 80 | key_deletion_window_in_days = var.cloudtrail_key_deletion_window_in_days 81 | region = var.region 82 | s3_bucket_name = local.audit_log_bucket_id 83 | s3_key_prefix = var.cloudtrail_s3_key_prefix 84 | s3_object_level_logging_buckets = var.cloudtrail_s3_object_level_logging_buckets 85 | dynamodb_event_logging_tables = var.cloudtrail_dynamodb_event_logging_tables 86 | lambda_invocation_logging_lambdas = var.cloudtrail_lambda_invocation_logging_lambdas 87 | is_organization_trail = local.is_organization_trail 88 | 89 | tags = var.tags 90 | } 91 | 92 | # -------------------------------------------------------------------------------------------------- 93 | # CloudWatch Alarms Baseline 94 | # -------------------------------------------------------------------------------------------------- 95 | 96 | module "alarm_baseline" { 97 | count = var.alarm_baseline_enabled && local.is_cloudtrail_enabled && var.cloudtrail_cloudwatch_logs_enabled ? 1 : 0 98 | source = "./modules/alarm-baseline" 99 | 100 | unauthorized_api_calls_enabled = var.unauthorized_api_calls_enabled 101 | no_mfa_console_signin_enabled = var.no_mfa_console_signin_enabled 102 | mfa_console_signin_allow_sso = var.mfa_console_signin_allow_sso 103 | root_usage_enabled = var.root_usage_enabled 104 | iam_changes_enabled = var.iam_changes_enabled 105 | cloudtrail_cfg_changes_enabled = var.cloudtrail_cfg_changes_enabled 106 | console_signin_failures_enabled = var.console_signin_failures_enabled 107 | disable_or_delete_cmk_enabled = var.disable_or_delete_cmk_enabled 108 | s3_bucket_policy_changes_enabled = var.s3_bucket_policy_changes_enabled 109 | aws_config_changes_enabled = var.aws_config_changes_enabled 110 | security_group_changes_enabled = var.security_group_changes_enabled 111 | nacl_changes_enabled = var.nacl_changes_enabled 112 | network_gw_changes_enabled = var.network_gw_changes_enabled 113 | route_table_changes_enabled = var.route_table_changes_enabled 114 | vpc_changes_enabled = var.vpc_changes_enabled 115 | organizations_changes_enabled = var.organizations_changes_enabled 116 | alarm_namespace = var.alarm_namespace 117 | cloudtrail_log_group_name = local.is_cloudtrail_enabled ? module.cloudtrail_baseline[0].log_group : "" 118 | sns_topic_name = var.alarm_sns_topic_name 119 | sns_topic_kms_master_key_id = var.alarm_sns_topic_kms_master_key_id 120 | 121 | tags = var.tags 122 | } 123 | 124 | # -------------------------------------------------------------------------------------------------- 125 | # S3 Baseline 126 | # -------------------------------------------------------------------------------------------------- 127 | 128 | module "s3_baseline" { 129 | count = var.s3_baseline_enabled ? 1 : 0 130 | source = "./modules/s3-baseline" 131 | 132 | block_public_acls = var.s3_block_public_acls 133 | block_public_policy = var.s3_block_public_policy 134 | ignore_public_acls = var.s3_ignore_public_acls 135 | restrict_public_buckets = var.s3_restrict_public_buckets 136 | } 137 | -------------------------------------------------------------------------------- /migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 1.0.0 3 | # Replacing `enabled` argument in secure-bucket module with `count` meta-argument 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = module.audit_log_bucket 8 | to = module.audit_log_bucket[0] 9 | } 10 | 11 | # -------------------------------------------------------------------------------------------------- 12 | # Migrations to 0.31.0 13 | # Replacing `enabled` argument in each sub-module with `count` meta-argument. 14 | # -------------------------------------------------------------------------------------------------- 15 | 16 | moved { 17 | from = module.cloudtrail_baseline 18 | to = module.cloudtrail_baseline[0] 19 | } 20 | 21 | moved { 22 | from = module.alarm_baseline 23 | to = module.alarm_baseline[0] 24 | } 25 | 26 | moved { 27 | from = module.s3_baseline 28 | to = module.s3_baseline[0] 29 | } 30 | 31 | moved { 32 | from = module.iam_baseline 33 | to = module.iam_baseline[0] 34 | } 35 | 36 | moved { 37 | from = module.analyzer_baseline 38 | to = module.analyzer_baseline[0] 39 | } 40 | 41 | # Config baseline 42 | moved { 43 | from = module.config_baseline_ap-northeast-1 44 | to = module.config_baseline_ap-northeast-1[0] 45 | } 46 | 47 | moved { 48 | from = module.config_baseline_ap-northeast-2 49 | to = module.config_baseline_ap-northeast-2[0] 50 | } 51 | 52 | moved { 53 | from = module.config_baseline_ap-northeast-3 54 | to = module.config_baseline_ap-northeast-3[0] 55 | } 56 | 57 | moved { 58 | from = module.config_baseline_ap-south-1 59 | to = module.config_baseline_ap-south-1[0] 60 | } 61 | 62 | moved { 63 | from = module.config_baseline_ap-southeast-1 64 | to = module.config_baseline_ap-southeast-1[0] 65 | } 66 | 67 | moved { 68 | from = module.config_baseline_ap-southeast-2 69 | to = module.config_baseline_ap-southeast-2[0] 70 | } 71 | 72 | moved { 73 | from = module.config_baseline_ca-central-1 74 | to = module.config_baseline_ca-central-1[0] 75 | } 76 | 77 | moved { 78 | from = module.config_baseline_eu-central-1 79 | to = module.config_baseline_eu-central-1[0] 80 | } 81 | 82 | moved { 83 | from = module.config_baseline_eu-north-1 84 | to = module.config_baseline_eu-north-1[0] 85 | } 86 | 87 | moved { 88 | from = module.config_baseline_eu-west-1 89 | to = module.config_baseline_eu-west-1[0] 90 | } 91 | 92 | moved { 93 | from = module.config_baseline_eu-west-2 94 | to = module.config_baseline_eu-west-2[0] 95 | } 96 | 97 | moved { 98 | from = module.config_baseline_eu-west-3 99 | to = module.config_baseline_eu-west-3[0] 100 | } 101 | 102 | moved { 103 | from = module.config_baseline_sa-east-1 104 | to = module.config_baseline_sa-east-1[0] 105 | } 106 | 107 | moved { 108 | from = module.config_baseline_us-east-1 109 | to = module.config_baseline_us-east-1[0] 110 | } 111 | 112 | moved { 113 | from = module.config_baseline_us-east-2 114 | to = module.config_baseline_us-east-2[0] 115 | } 116 | 117 | moved { 118 | from = module.config_baseline_us-west-1 119 | to = module.config_baseline_us-west-1[0] 120 | } 121 | 122 | moved { 123 | from = module.config_baseline_us-west-2 124 | to = module.config_baseline_us-west-2[0] 125 | } 126 | 127 | # EBS baseline 128 | moved { 129 | from = module.ebs_baseline_ap-northeast-1 130 | to = module.ebs_baseline_ap-northeast-1[0] 131 | } 132 | 133 | moved { 134 | from = module.ebs_baseline_ap-northeast-2 135 | to = module.ebs_baseline_ap-northeast-2[0] 136 | } 137 | 138 | moved { 139 | from = module.ebs_baseline_ap-northeast-3 140 | to = module.ebs_baseline_ap-northeast-3[0] 141 | } 142 | 143 | moved { 144 | from = module.ebs_baseline_ap-south-1 145 | to = module.ebs_baseline_ap-south-1[0] 146 | } 147 | 148 | moved { 149 | from = module.ebs_baseline_ap-southeast-1 150 | to = module.ebs_baseline_ap-southeast-1[0] 151 | } 152 | 153 | moved { 154 | from = module.ebs_baseline_ap-southeast-2 155 | to = module.ebs_baseline_ap-southeast-2[0] 156 | } 157 | 158 | moved { 159 | from = module.ebs_baseline_ca-central-1 160 | to = module.ebs_baseline_ca-central-1[0] 161 | } 162 | 163 | moved { 164 | from = module.ebs_baseline_eu-central-1 165 | to = module.ebs_baseline_eu-central-1[0] 166 | } 167 | 168 | moved { 169 | from = module.ebs_baseline_eu-north-1 170 | to = module.ebs_baseline_eu-north-1[0] 171 | } 172 | 173 | moved { 174 | from = module.ebs_baseline_eu-west-1 175 | to = module.ebs_baseline_eu-west-1[0] 176 | } 177 | 178 | moved { 179 | from = module.ebs_baseline_eu-west-2 180 | to = module.ebs_baseline_eu-west-2[0] 181 | } 182 | 183 | moved { 184 | from = module.ebs_baseline_eu-west-3 185 | to = module.ebs_baseline_eu-west-3[0] 186 | } 187 | 188 | moved { 189 | from = module.ebs_baseline_sa-east-1 190 | to = module.ebs_baseline_sa-east-1[0] 191 | } 192 | 193 | moved { 194 | from = module.ebs_baseline_us-east-1 195 | to = module.ebs_baseline_us-east-1[0] 196 | } 197 | 198 | moved { 199 | from = module.ebs_baseline_us-east-2 200 | to = module.ebs_baseline_us-east-2[0] 201 | } 202 | 203 | moved { 204 | from = module.ebs_baseline_us-west-1 205 | to = module.ebs_baseline_us-west-1[0] 206 | } 207 | 208 | moved { 209 | from = module.ebs_baseline_us-west-2 210 | to = module.ebs_baseline_us-west-2[0] 211 | } 212 | 213 | # Guardduty baseline 214 | moved { 215 | from = module.guardduty_baseline_ap-northeast-1 216 | to = module.guardduty_baseline_ap-northeast-1[0] 217 | } 218 | 219 | moved { 220 | from = module.guardduty_baseline_ap-northeast-2 221 | to = module.guardduty_baseline_ap-northeast-2[0] 222 | } 223 | 224 | moved { 225 | from = module.guardduty_baseline_ap-northeast-3 226 | to = module.guardduty_baseline_ap-northeast-3[0] 227 | } 228 | 229 | moved { 230 | from = module.guardduty_baseline_ap-south-1 231 | to = module.guardduty_baseline_ap-south-1[0] 232 | } 233 | 234 | moved { 235 | from = module.guardduty_baseline_ap-southeast-1 236 | to = module.guardduty_baseline_ap-southeast-1[0] 237 | } 238 | 239 | moved { 240 | from = module.guardduty_baseline_ap-southeast-2 241 | to = module.guardduty_baseline_ap-southeast-2[0] 242 | } 243 | 244 | moved { 245 | from = module.guardduty_baseline_ca-central-1 246 | to = module.guardduty_baseline_ca-central-1[0] 247 | } 248 | 249 | moved { 250 | from = module.guardduty_baseline_eu-central-1 251 | to = module.guardduty_baseline_eu-central-1[0] 252 | } 253 | 254 | moved { 255 | from = module.guardduty_baseline_eu-north-1 256 | to = module.guardduty_baseline_eu-north-1[0] 257 | } 258 | 259 | moved { 260 | from = module.guardduty_baseline_eu-west-1 261 | to = module.guardduty_baseline_eu-west-1[0] 262 | } 263 | 264 | moved { 265 | from = module.guardduty_baseline_eu-west-2 266 | to = module.guardduty_baseline_eu-west-2[0] 267 | } 268 | 269 | moved { 270 | from = module.guardduty_baseline_eu-west-3 271 | to = module.guardduty_baseline_eu-west-3[0] 272 | } 273 | 274 | moved { 275 | from = module.guardduty_baseline_sa-east-1 276 | to = module.guardduty_baseline_sa-east-1[0] 277 | } 278 | 279 | moved { 280 | from = module.guardduty_baseline_us-east-1 281 | to = module.guardduty_baseline_us-east-1[0] 282 | } 283 | 284 | moved { 285 | from = module.guardduty_baseline_us-east-2 286 | to = module.guardduty_baseline_us-east-2[0] 287 | } 288 | 289 | moved { 290 | from = module.guardduty_baseline_us-west-1 291 | to = module.guardduty_baseline_us-west-1[0] 292 | } 293 | 294 | moved { 295 | from = module.guardduty_baseline_us-west-2 296 | to = module.guardduty_baseline_us-west-2[0] 297 | } 298 | 299 | # SecurityHub baseline 300 | moved { 301 | from = module.securityhub_baseline_ap-northeast-1 302 | to = module.securityhub_baseline_ap-northeast-1[0] 303 | } 304 | 305 | moved { 306 | from = module.securityhub_baseline_ap-northeast-2 307 | to = module.securityhub_baseline_ap-northeast-2[0] 308 | } 309 | 310 | moved { 311 | from = module.securityhub_baseline_ap-northeast-3 312 | to = module.securityhub_baseline_ap-northeast-3[0] 313 | } 314 | 315 | moved { 316 | from = module.securityhub_baseline_ap-south-1 317 | to = module.securityhub_baseline_ap-south-1[0] 318 | } 319 | 320 | moved { 321 | from = module.securityhub_baseline_ap-southeast-1 322 | to = module.securityhub_baseline_ap-southeast-1[0] 323 | } 324 | 325 | moved { 326 | from = module.securityhub_baseline_ap-southeast-2 327 | to = module.securityhub_baseline_ap-southeast-2[0] 328 | } 329 | 330 | moved { 331 | from = module.securityhub_baseline_ca-central-1 332 | to = module.securityhub_baseline_ca-central-1[0] 333 | } 334 | 335 | moved { 336 | from = module.securityhub_baseline_eu-central-1 337 | to = module.securityhub_baseline_eu-central-1[0] 338 | } 339 | 340 | moved { 341 | from = module.securityhub_baseline_eu-north-1 342 | to = module.securityhub_baseline_eu-north-1[0] 343 | } 344 | 345 | moved { 346 | from = module.securityhub_baseline_eu-west-1 347 | to = module.securityhub_baseline_eu-west-1[0] 348 | } 349 | 350 | moved { 351 | from = module.securityhub_baseline_eu-west-2 352 | to = module.securityhub_baseline_eu-west-2[0] 353 | } 354 | 355 | moved { 356 | from = module.securityhub_baseline_eu-west-3 357 | to = module.securityhub_baseline_eu-west-3[0] 358 | } 359 | 360 | moved { 361 | from = module.securityhub_baseline_sa-east-1 362 | to = module.securityhub_baseline_sa-east-1[0] 363 | } 364 | 365 | moved { 366 | from = module.securityhub_baseline_us-east-1 367 | to = module.securityhub_baseline_us-east-1[0] 368 | } 369 | 370 | moved { 371 | from = module.securityhub_baseline_us-east-2 372 | to = module.securityhub_baseline_us-east-2[0] 373 | } 374 | 375 | moved { 376 | from = module.securityhub_baseline_us-west-1 377 | to = module.securityhub_baseline_us-west-1[0] 378 | } 379 | 380 | moved { 381 | from = module.securityhub_baseline_us-west-2 382 | to = module.securityhub_baseline_us-west-2[0] 383 | } 384 | 385 | # vpc baseline 386 | moved { 387 | from = module.vpc_baseline_ap-northeast-1 388 | to = module.vpc_baseline_ap-northeast-1[0] 389 | } 390 | 391 | moved { 392 | from = module.vpc_baseline_ap-northeast-2 393 | to = module.vpc_baseline_ap-northeast-2[0] 394 | } 395 | 396 | moved { 397 | from = module.vpc_baseline_ap-northeast-3 398 | to = module.vpc_baseline_ap-northeast-3[0] 399 | } 400 | 401 | moved { 402 | from = module.vpc_baseline_ap-south-1 403 | to = module.vpc_baseline_ap-south-1[0] 404 | } 405 | 406 | moved { 407 | from = module.vpc_baseline_ap-southeast-1 408 | to = module.vpc_baseline_ap-southeast-1[0] 409 | } 410 | 411 | moved { 412 | from = module.vpc_baseline_ap-southeast-2 413 | to = module.vpc_baseline_ap-southeast-2[0] 414 | } 415 | 416 | moved { 417 | from = module.vpc_baseline_ca-central-1 418 | to = module.vpc_baseline_ca-central-1[0] 419 | } 420 | 421 | moved { 422 | from = module.vpc_baseline_eu-central-1 423 | to = module.vpc_baseline_eu-central-1[0] 424 | } 425 | 426 | moved { 427 | from = module.vpc_baseline_eu-north-1 428 | to = module.vpc_baseline_eu-north-1[0] 429 | } 430 | 431 | moved { 432 | from = module.vpc_baseline_eu-west-1 433 | to = module.vpc_baseline_eu-west-1[0] 434 | } 435 | 436 | moved { 437 | from = module.vpc_baseline_eu-west-2 438 | to = module.vpc_baseline_eu-west-2[0] 439 | } 440 | 441 | moved { 442 | from = module.vpc_baseline_eu-west-3 443 | to = module.vpc_baseline_eu-west-3[0] 444 | } 445 | 446 | moved { 447 | from = module.vpc_baseline_sa-east-1 448 | to = module.vpc_baseline_sa-east-1[0] 449 | } 450 | 451 | moved { 452 | from = module.vpc_baseline_us-east-1 453 | to = module.vpc_baseline_us-east-1[0] 454 | } 455 | 456 | moved { 457 | from = module.vpc_baseline_us-east-2 458 | to = module.vpc_baseline_us-east-2[0] 459 | } 460 | 461 | moved { 462 | from = module.vpc_baseline_us-west-1 463 | to = module.vpc_baseline_us-west-1[0] 464 | } 465 | 466 | moved { 467 | from = module.vpc_baseline_us-west-2 468 | to = module.vpc_baseline_us-west-2[0] 469 | } 470 | 471 | # analyzer baseline 472 | moved { 473 | from = module.analyzer_baseline_ap-northeast-1 474 | to = module.analyzer_baseline_ap-northeast-1[0] 475 | } 476 | 477 | moved { 478 | from = module.analyzer_baseline_ap-northeast-2 479 | to = module.analyzer_baseline_ap-northeast-2[0] 480 | } 481 | 482 | moved { 483 | from = module.analyzer_baseline_ap-northeast-3 484 | to = module.analyzer_baseline_ap-northeast-3[0] 485 | } 486 | 487 | moved { 488 | from = module.analyzer_baseline_ap-south-1 489 | to = module.analyzer_baseline_ap-south-1[0] 490 | } 491 | 492 | moved { 493 | from = module.analyzer_baseline_ap-southeast-1 494 | to = module.analyzer_baseline_ap-southeast-1[0] 495 | } 496 | 497 | moved { 498 | from = module.analyzer_baseline_ap-southeast-2 499 | to = module.analyzer_baseline_ap-southeast-2[0] 500 | } 501 | 502 | moved { 503 | from = module.analyzer_baseline_ca-central-1 504 | to = module.analyzer_baseline_ca-central-1[0] 505 | } 506 | 507 | moved { 508 | from = module.analyzer_baseline_eu-central-1 509 | to = module.analyzer_baseline_eu-central-1[0] 510 | } 511 | 512 | moved { 513 | from = module.analyzer_baseline_eu-north-1 514 | to = module.analyzer_baseline_eu-north-1[0] 515 | } 516 | 517 | moved { 518 | from = module.analyzer_baseline_eu-west-1 519 | to = module.analyzer_baseline_eu-west-1[0] 520 | } 521 | 522 | moved { 523 | from = module.analyzer_baseline_eu-west-2 524 | to = module.analyzer_baseline_eu-west-2[0] 525 | } 526 | 527 | moved { 528 | from = module.analyzer_baseline_eu-west-3 529 | to = module.analyzer_baseline_eu-west-3[0] 530 | } 531 | 532 | moved { 533 | from = module.analyzer_baseline_sa-east-1 534 | to = module.analyzer_baseline_sa-east-1[0] 535 | } 536 | 537 | moved { 538 | from = module.analyzer_baseline_us-east-1 539 | to = module.analyzer_baseline_us-east-1[0] 540 | } 541 | 542 | moved { 543 | from = module.analyzer_baseline_us-east-2 544 | to = module.analyzer_baseline_us-east-2[0] 545 | } 546 | 547 | moved { 548 | from = module.analyzer_baseline_us-west-1 549 | to = module.analyzer_baseline_us-west-1[0] 550 | } 551 | 552 | moved { 553 | from = module.analyzer_baseline_us-west-2 554 | to = module.analyzer_baseline_us-west-2[0] 555 | } 556 | -------------------------------------------------------------------------------- /modules/alarm-baseline/README.md: -------------------------------------------------------------------------------- 1 | # alarm-baseline 2 | 3 | Set up CloudWatch alarms to notify you when critical changes happen in your AWS account. 4 | 5 | 6 | ## Requirements 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 11 | | [aws](#requirement\_aws) | >= 4.3 | 12 | 13 | ## Providers 14 | 15 | | Name | Version | 16 | |------|---------| 17 | | [aws](#provider\_aws) | >= 4.3 | 18 | 19 | ## Inputs 20 | 21 | | Name | Description | Type | Required | 22 | |------|-------------|------|:--------:| 23 | | [cloudtrail\_log\_group\_name](#input\_cloudtrail\_log\_group\_name) | The name of the CloudWatch Logs group to which CloudTrail events are delivered. | `string` | yes | 24 | | [alarm\_namespace](#input\_alarm\_namespace) | The namespace in which all alarms are set up. | `string` | no | 25 | | [aws\_config\_changes\_enabled](#input\_aws\_config\_changes\_enabled) | The boolean flag whether the aws\_config\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 26 | | [cloudtrail\_cfg\_changes\_enabled](#input\_cloudtrail\_cfg\_changes\_enabled) | The boolean flag whether the cloudtrail\_cfg\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 27 | | [console\_signin\_failures\_enabled](#input\_console\_signin\_failures\_enabled) | The boolean flag whether the console\_signin\_failures alarm is enabled or not. No resources are created when set to false. | `bool` | no | 28 | | [disable\_or\_delete\_cmk\_enabled](#input\_disable\_or\_delete\_cmk\_enabled) | The boolean flag whether the disable\_or\_delete\_cmk alarm is enabled or not. No resources are created when set to false. | `bool` | no | 29 | | [iam\_changes\_enabled](#input\_iam\_changes\_enabled) | The boolean flag whether the iam\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 30 | | [mfa\_console\_signin\_allow\_sso](#input\_mfa\_console\_signin\_allow\_sso) | The boolean flag whether the no\_mfa\_console\_signin alarm allows SSO auth to be ignored. | `bool` | no | 31 | | [nacl\_changes\_enabled](#input\_nacl\_changes\_enabled) | The boolean flag whether the nacl\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 32 | | [network\_gw\_changes\_enabled](#input\_network\_gw\_changes\_enabled) | The boolean flag whether the network\_gw\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 33 | | [no\_mfa\_console\_signin\_enabled](#input\_no\_mfa\_console\_signin\_enabled) | The boolean flag whether the no\_mfa\_console\_signin alarm is enabled or not. No resources are created when set to false. | `bool` | no | 34 | | [organizations\_changes\_enabled](#input\_organizations\_changes\_enabled) | The boolean flag whether the organizations\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 35 | | [root\_usage\_enabled](#input\_root\_usage\_enabled) | The boolean flag whether the root\_usage alarm is enabled or not. No resources are created when set to false. | `bool` | no | 36 | | [route\_table\_changes\_enabled](#input\_route\_table\_changes\_enabled) | The boolean flag whether the route\_table\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 37 | | [s3\_bucket\_policy\_changes\_enabled](#input\_s3\_bucket\_policy\_changes\_enabled) | The boolean flag whether the s3\_bucket\_policy\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 38 | | [security\_group\_changes\_enabled](#input\_security\_group\_changes\_enabled) | The boolean flag whether the security\_group\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 39 | | [sns\_topic\_kms\_master\_key\_id](#input\_sns\_topic\_kms\_master\_key\_id) | To enable SNS Topic encryption enter value with the ID of a custom master KMS key that is used for encryption | `string` | no | 40 | | [sns\_topic\_name](#input\_sns\_topic\_name) | The name of the SNS Topic which will be notified when any alarm is performed. | `string` | no | 41 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 42 | | [unauthorized\_api\_calls\_enabled](#input\_unauthorized\_api\_calls\_enabled) | The boolean flag whether the unauthorized\_api\_calls alarm is enabled or not. No resources are created when set to false. | `bool` | no | 43 | | [vpc\_changes\_enabled](#input\_vpc\_changes\_enabled) | The boolean flag whether the vpc\_changes alarm is enabled or not. No resources are created when set to false. | `bool` | no | 44 | 45 | ## Outputs 46 | 47 | | Name | Description | 48 | |------|-------------| 49 | | [alarm\_sns\_topic](#output\_alarm\_sns\_topic) | The SNS topic to which CloudWatch Alarms will be sent. | 50 | 51 | -------------------------------------------------------------------------------- /modules/alarm-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_sns_topic.alarms[0] 8 | to = aws_sns_topic.alarms 9 | } 10 | 11 | moved { 12 | from = aws_sns_topic_policy.alarms[0] 13 | to = aws_sns_topic_policy.alarms 14 | } 15 | -------------------------------------------------------------------------------- /modules/alarm-baseline/outputs.tf: -------------------------------------------------------------------------------- 1 | output "alarm_sns_topic" { 2 | description = "The SNS topic to which CloudWatch Alarms will be sent." 3 | value = aws_sns_topic.alarms 4 | } 5 | -------------------------------------------------------------------------------- /modules/alarm-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "unauthorized_api_calls_enabled" { 2 | description = "The boolean flag whether the unauthorized_api_calls alarm is enabled or not. No resources are created when set to false." 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "no_mfa_console_signin_enabled" { 8 | description = "The boolean flag whether the no_mfa_console_signin alarm is enabled or not. No resources are created when set to false." 9 | type = bool 10 | default = true 11 | } 12 | 13 | variable "mfa_console_signin_allow_sso" { 14 | description = "The boolean flag whether the no_mfa_console_signin alarm allows SSO auth to be ignored." 15 | type = bool 16 | default = false 17 | } 18 | 19 | variable "root_usage_enabled" { 20 | description = "The boolean flag whether the root_usage alarm is enabled or not. No resources are created when set to false." 21 | type = bool 22 | default = true 23 | } 24 | 25 | variable "iam_changes_enabled" { 26 | description = "The boolean flag whether the iam_changes alarm is enabled or not. No resources are created when set to false." 27 | type = bool 28 | default = true 29 | } 30 | 31 | variable "cloudtrail_cfg_changes_enabled" { 32 | description = "The boolean flag whether the cloudtrail_cfg_changes alarm is enabled or not. No resources are created when set to false." 33 | type = bool 34 | default = true 35 | } 36 | 37 | variable "console_signin_failures_enabled" { 38 | description = "The boolean flag whether the console_signin_failures alarm is enabled or not. No resources are created when set to false." 39 | type = bool 40 | default = true 41 | } 42 | 43 | variable "disable_or_delete_cmk_enabled" { 44 | description = "The boolean flag whether the disable_or_delete_cmk alarm is enabled or not. No resources are created when set to false." 45 | type = bool 46 | default = true 47 | } 48 | 49 | variable "s3_bucket_policy_changes_enabled" { 50 | description = "The boolean flag whether the s3_bucket_policy_changes alarm is enabled or not. No resources are created when set to false." 51 | type = bool 52 | default = true 53 | } 54 | 55 | variable "aws_config_changes_enabled" { 56 | description = "The boolean flag whether the aws_config_changes alarm is enabled or not. No resources are created when set to false." 57 | type = bool 58 | default = true 59 | } 60 | 61 | variable "security_group_changes_enabled" { 62 | description = "The boolean flag whether the security_group_changes alarm is enabled or not. No resources are created when set to false." 63 | type = bool 64 | default = true 65 | } 66 | 67 | variable "nacl_changes_enabled" { 68 | description = "The boolean flag whether the nacl_changes alarm is enabled or not. No resources are created when set to false." 69 | type = bool 70 | default = true 71 | } 72 | 73 | variable "network_gw_changes_enabled" { 74 | description = "The boolean flag whether the network_gw_changes alarm is enabled or not. No resources are created when set to false." 75 | type = bool 76 | default = true 77 | } 78 | 79 | variable "route_table_changes_enabled" { 80 | description = "The boolean flag whether the route_table_changes alarm is enabled or not. No resources are created when set to false." 81 | type = bool 82 | default = true 83 | } 84 | 85 | variable "vpc_changes_enabled" { 86 | description = "The boolean flag whether the vpc_changes alarm is enabled or not. No resources are created when set to false." 87 | type = bool 88 | default = true 89 | } 90 | 91 | variable "organizations_changes_enabled" { 92 | description = "The boolean flag whether the organizations_changes alarm is enabled or not. No resources are created when set to false." 93 | type = bool 94 | default = true 95 | } 96 | 97 | variable "alarm_namespace" { 98 | description = "The namespace in which all alarms are set up." 99 | type = string 100 | default = "CISBenchmark" 101 | } 102 | 103 | variable "cloudtrail_log_group_name" { 104 | description = "The name of the CloudWatch Logs group to which CloudTrail events are delivered." 105 | type = string 106 | } 107 | 108 | variable "sns_topic_name" { 109 | description = "The name of the SNS Topic which will be notified when any alarm is performed." 110 | type = string 111 | default = "CISAlarm" 112 | } 113 | 114 | variable "sns_topic_kms_master_key_id" { 115 | description = "To enable SNS Topic encryption enter value with the ID of a custom master KMS key that is used for encryption" 116 | type = string 117 | default = null 118 | } 119 | 120 | variable "tags" { 121 | description = "Specifies object tags key and value. This applies to all resources created by this module." 122 | type = map(string) 123 | default = { 124 | "Terraform" = "true" 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /modules/alarm-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/analyzer-baseline/README.md: -------------------------------------------------------------------------------- 1 | # analyzer-baseline 2 | 3 | ## Features 4 | 5 | - Enable IAM Acess Analyzer 6 | 7 | 8 | ## Requirements 9 | 10 | | Name | Version | 11 | |------|---------| 12 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 13 | | [aws](#requirement\_aws) | >= 4.3 | 14 | 15 | ## Providers 16 | 17 | | Name | Version | 18 | |------|---------| 19 | | [aws](#provider\_aws) | >= 4.3 | 20 | 21 | ## Inputs 22 | 23 | | Name | Description | Type | Required | 24 | |------|-------------|------|:--------:| 25 | | [analyzer\_name](#input\_analyzer\_name) | The name for the IAM Access Analyzer resource to be created. | `string` | no | 26 | | [is\_organization](#input\_is\_organization) | The boolean flag whether this module is configured for the organization master account or the individual account. | `bool` | no | 27 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 28 | 29 | ## Outputs 30 | 31 | No outputs. 32 | 33 | -------------------------------------------------------------------------------- /modules/analyzer-baseline/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_accessanalyzer_analyzer" "default" { 2 | analyzer_name = var.analyzer_name 3 | type = var.is_organization ? "ORGANIZATION" : "ACCOUNT" 4 | 5 | tags = var.tags 6 | } 7 | -------------------------------------------------------------------------------- /modules/analyzer-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_accessanalyzer_analyzer.default[0] 8 | to = aws_accessanalyzer_analyzer.default 9 | } 10 | -------------------------------------------------------------------------------- /modules/analyzer-baseline/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/modules/analyzer-baseline/outputs.tf -------------------------------------------------------------------------------- /modules/analyzer-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "analyzer_name" { 2 | description = "The name for the IAM Access Analyzer resource to be created." 3 | type = string 4 | default = "default-analyer" 5 | } 6 | 7 | variable "is_organization" { 8 | description = "The boolean flag whether this module is configured for the organization master account or the individual account." 9 | type = bool 10 | default = false 11 | } 12 | 13 | variable "tags" { 14 | description = "Specifies object tags key and value. This applies to all resources created by this module." 15 | type = map(string) 16 | default = { 17 | "Terraform" = "true" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /modules/analyzer-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/cloudtrail-baseline/README.md: -------------------------------------------------------------------------------- 1 | # cloudtrail-baseline 2 | 3 | Enable CloudTrail in all regions and deliver events to CloudWatch Logs. CloudTrail logs are encrypted using AWS Key Management Service. 4 | 5 | 6 | ## Requirements 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 11 | | [aws](#requirement\_aws) | >= 4.3 | 12 | 13 | ## Providers 14 | 15 | | Name | Version | 16 | |------|---------| 17 | | [aws](#provider\_aws) | >= 4.3 | 18 | 19 | ## Inputs 20 | 21 | | Name | Description | Type | Required | 22 | |------|-------------|------|:--------:| 23 | | [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID number of the account. | `string` | yes | 24 | | [region](#input\_region) | The AWS region in which CloudTrail is set up. | `string` | yes | 25 | | [s3\_bucket\_name](#input\_s3\_bucket\_name) | The name of the S3 bucket which will store configuration snapshots. | `string` | yes | 26 | | [cloudtrail\_depends\_on](#input\_cloudtrail\_depends\_on) | External resources which should be set up before CloudTrail. | `list(any)` | no | 27 | | [cloudtrail\_name](#input\_cloudtrail\_name) | The name of the trail. | `string` | no | 28 | | [cloudtrail\_sns\_topic\_enabled](#input\_cloudtrail\_sns\_topic\_enabled) | Specifies whether the trail is delivered to a SNS topic. | `bool` | no | 29 | | [cloudtrail\_sns\_topic\_name](#input\_cloudtrail\_sns\_topic\_name) | The SNS topic linked to the CloudTrail | `string` | no | 30 | | [cloudwatch\_logs\_enabled](#input\_cloudwatch\_logs\_enabled) | Specifies whether the trail is delivered to CloudWatch Logs. | `bool` | no | 31 | | [cloudwatch\_logs\_group\_name](#input\_cloudwatch\_logs\_group\_name) | The name of CloudWatch Logs group to which CloudTrail events are delivered. | `string` | no | 32 | | [cloudwatch\_logs\_retention\_in\_days](#input\_cloudwatch\_logs\_retention\_in\_days) | Number of days to retain logs for. CIS recommends 365 days. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. Set to 0 to keep logs indefinitely. | `number` | no | 33 | | [dynamodb\_event\_logging\_tables](#input\_dynamodb\_event\_logging\_tables) | The list of DynamoDB table ARNs on which to enable event logging. | `list(string)` | no | 34 | | [iam\_role\_name](#input\_iam\_role\_name) | The name of the IAM Role to be used by CloudTrail to delivery logs to CloudWatch Logs group. | `string` | no | 35 | | [iam\_role\_policy\_name](#input\_iam\_role\_policy\_name) | The name of the IAM Role Policy to be used by CloudTrail to delivery logs to CloudWatch Logs group. | `string` | no | 36 | | [is\_organization\_trail](#input\_is\_organization\_trail) | Specifies whether the trail is an AWS Organizations trail. Organization trails log events for the master account and all member accounts. Can only be created in the organization master account. | `bool` | no | 37 | | [key\_deletion\_window\_in\_days](#input\_key\_deletion\_window\_in\_days) | Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days. Defaults to 30 days. | `number` | no | 38 | | [lambda\_invocation\_logging\_lambdas](#input\_lambda\_invocation\_logging\_lambdas) | The list of lambda ARNs on which to enable invocation logging. | `list(string)` | no | 39 | | [permissions\_boundary\_arn](#input\_permissions\_boundary\_arn) | The permissions boundary ARN for all IAM Roles, provisioned by this module | `string` | no | 40 | | [s3\_key\_prefix](#input\_s3\_key\_prefix) | The prefix for the specified S3 bucket. | `string` | no | 41 | | [s3\_object\_level\_logging\_buckets](#input\_s3\_object\_level\_logging\_buckets) | The list of S3 bucket ARNs on which to enable object-level logging. | `list(string)` | no | 42 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 43 | 44 | ## Outputs 45 | 46 | | Name | Description | 47 | |------|-------------| 48 | | [cloudtrail](#output\_cloudtrail) | The trail for recording events in all regions. | 49 | | [cloudtrail\_sns\_topic](#output\_cloudtrail\_sns\_topic) | The sns topic linked to the cloudtrail. | 50 | | [kms\_key](#output\_kms\_key) | The KMS key used for encrypting CloudTrail events. | 51 | | [log\_delivery\_iam\_role](#output\_log\_delivery\_iam\_role) | The IAM role used for delivering CloudTrail events to CloudWatch Logs. | 52 | | [log\_group](#output\_log\_group) | The CloudWatch Logs log group which stores CloudTrail events. | 53 | 54 | -------------------------------------------------------------------------------- /modules/cloudtrail-baseline/main.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # CloudWatch Logs group to accept CloudTrail event stream. 3 | # -------------------------------------------------------------------------------------------------- 4 | resource "aws_cloudwatch_log_group" "cloudtrail_events" { 5 | count = var.cloudwatch_logs_enabled ? 1 : 0 6 | 7 | name = var.cloudwatch_logs_group_name 8 | retention_in_days = var.cloudwatch_logs_retention_in_days 9 | 10 | tags = var.tags 11 | } 12 | 13 | # IAM Role to deliver CloudTrail events to CloudWatch Logs group. 14 | # The policy was derived from the default key policy descrived in AWS CloudTrail User Guide. 15 | # https://docs.aws.amazon.com/awscloudtrail/latest/userguide/send-cloudtrail-events-to-cloudwatch-logs.html 16 | data "aws_iam_policy_document" "cloudwatch_delivery_assume_policy" { 17 | statement { 18 | principals { 19 | type = "Service" 20 | identifiers = ["cloudtrail.amazonaws.com"] 21 | } 22 | actions = ["sts:AssumeRole"] 23 | } 24 | } 25 | 26 | resource "aws_iam_role" "cloudwatch_delivery" { 27 | count = var.cloudwatch_logs_enabled ? 1 : 0 28 | 29 | name = var.iam_role_name 30 | assume_role_policy = data.aws_iam_policy_document.cloudwatch_delivery_assume_policy.json 31 | 32 | permissions_boundary = var.permissions_boundary_arn 33 | 34 | tags = var.tags 35 | } 36 | 37 | data "aws_iam_policy_document" "cloudwatch_delivery_policy" { 38 | count = var.cloudwatch_logs_enabled ? 1 : 0 39 | 40 | statement { 41 | sid = "AWSCloudTrailCreateLogStream2014110" 42 | actions = ["logs:CreateLogStream"] 43 | resources = ["arn:aws:logs:${var.region}:${var.aws_account_id}:log-group:${aws_cloudwatch_log_group.cloudtrail_events[0].name}:log-stream:*"] 44 | } 45 | 46 | statement { 47 | sid = "AWSCloudTrailPutLogEvents20141101" 48 | actions = ["logs:PutLogEvents"] 49 | resources = ["arn:aws:logs:${var.region}:${var.aws_account_id}:log-group:${aws_cloudwatch_log_group.cloudtrail_events[0].name}:log-stream:*"] 50 | } 51 | } 52 | 53 | resource "aws_iam_role_policy" "cloudwatch_delivery_policy" { 54 | count = var.cloudwatch_logs_enabled ? 1 : 0 55 | 56 | name = var.iam_role_policy_name 57 | role = aws_iam_role.cloudwatch_delivery[0].id 58 | policy = data.aws_iam_policy_document.cloudwatch_delivery_policy[0].json 59 | } 60 | 61 | # KMS Key to encrypt CloudTrail events. 62 | # The policy was derived from the default key policy described in AWS CloudTrail User Guide. 63 | # https://docs.aws.amazon.com/awscloudtrail/latest/userguide/default-cmk-policy.html 64 | data "aws_iam_policy_document" "cloudtrail_key_policy" { 65 | policy_id = "Key policy created by CloudTrail" 66 | 67 | statement { 68 | sid = "Enable IAM User Permissions" 69 | 70 | principals { 71 | type = "AWS" 72 | identifiers = [ 73 | "arn:aws:iam::${var.aws_account_id}:root" 74 | ] 75 | } 76 | actions = ["kms:*"] 77 | resources = ["*"] 78 | } 79 | 80 | statement { 81 | sid = "Allow CloudTrail to encrypt logs" 82 | principals { 83 | type = "Service" 84 | identifiers = ["cloudtrail.amazonaws.com"] 85 | } 86 | actions = ["kms:GenerateDataKey*"] 87 | resources = ["*"] 88 | condition { 89 | test = "StringLike" 90 | variable = "kms:EncryptionContext:aws:cloudtrail:arn" 91 | values = ["arn:aws:cloudtrail:*:${var.aws_account_id}:trail/*"] 92 | } 93 | } 94 | 95 | statement { 96 | sid = "Allow CloudTrail to describe key" 97 | principals { 98 | type = "Service" 99 | identifiers = ["cloudtrail.amazonaws.com"] 100 | } 101 | actions = ["kms:DescribeKey"] 102 | resources = ["*"] 103 | } 104 | 105 | statement { 106 | sid = "Allow principals in the account to decrypt log files" 107 | principals { 108 | type = "AWS" 109 | identifiers = ["*"] 110 | } 111 | actions = [ 112 | "kms:Decrypt", 113 | "kms:ReEncryptFrom" 114 | ] 115 | resources = ["*"] 116 | condition { 117 | test = "StringEquals" 118 | variable = "kms:CallerAccount" 119 | values = [var.aws_account_id] 120 | } 121 | condition { 122 | test = "StringLike" 123 | variable = "kms:EncryptionContext:aws:cloudtrail:arn" 124 | values = ["arn:aws:cloudtrail:*:${var.aws_account_id}:trail/*"] 125 | } 126 | } 127 | 128 | statement { 129 | sid = "Allow alias creation during setup" 130 | principals { 131 | type = "AWS" 132 | identifiers = ["*"] 133 | } 134 | actions = ["kms:CreateAlias"] 135 | resources = ["*"] 136 | condition { 137 | test = "StringEquals" 138 | variable = "kms:ViaService" 139 | values = ["ec2.${var.region}.amazonaws.com"] 140 | } 141 | condition { 142 | test = "StringEquals" 143 | variable = "kms:CallerAccount" 144 | values = [var.aws_account_id] 145 | } 146 | } 147 | 148 | statement { 149 | sid = "Enable cross account log decryption" 150 | principals { 151 | type = "AWS" 152 | identifiers = ["*"] 153 | } 154 | actions = [ 155 | "kms:Decrypt", 156 | "kms:ReEncryptFrom" 157 | ] 158 | resources = ["*"] 159 | condition { 160 | test = "StringEquals" 161 | variable = "kms:CallerAccount" 162 | values = [var.aws_account_id] 163 | } 164 | condition { 165 | test = "StringLike" 166 | variable = "kms:EncryptionContext:aws:cloudtrail:arn" 167 | values = ["arn:aws:cloudtrail:*:${var.aws_account_id}:trail/*"] 168 | } 169 | } 170 | 171 | # https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-permissions-for-sns-notifications.html 172 | statement { 173 | sid = "Allow CloudTrail to send notifications to the encrypted SNS topic" 174 | principals { 175 | type = "Service" 176 | identifiers = ["cloudtrail.amazonaws.com"] 177 | } 178 | actions = [ 179 | "kms:GenerateDataKey*", 180 | "kms:Decrypt" 181 | ] 182 | resources = ["*"] 183 | } 184 | } 185 | 186 | resource "aws_kms_key" "cloudtrail" { 187 | description = "A KMS key to encrypt CloudTrail events." 188 | deletion_window_in_days = var.key_deletion_window_in_days 189 | enable_key_rotation = "true" 190 | policy = data.aws_iam_policy_document.cloudtrail_key_policy.json 191 | 192 | tags = var.tags 193 | } 194 | 195 | # -------------------------------------------------------------------------------------------------- 196 | # SNS Topic 197 | # Could be used as subscription target to get feed of audit trail messages 198 | # -------------------------------------------------------------------------------------------------- 199 | 200 | resource "aws_sns_topic" "cloudtrail-sns-topic" { 201 | count = var.cloudtrail_sns_topic_enabled ? 1 : 0 202 | 203 | name = var.cloudtrail_sns_topic_name 204 | kms_master_key_id = aws_kms_key.cloudtrail.id 205 | } 206 | 207 | data "aws_iam_policy_document" "cloudtrail-sns-policy" { 208 | count = var.cloudtrail_sns_topic_enabled ? 1 : 0 209 | 210 | statement { 211 | actions = ["sns:Publish"] 212 | resources = [aws_sns_topic.cloudtrail-sns-topic[0].arn] 213 | 214 | principals { 215 | type = "Service" 216 | identifiers = ["cloudtrail.amazonaws.com"] 217 | } 218 | } 219 | } 220 | 221 | resource "aws_sns_topic_policy" "local-account-cloudtrail" { 222 | count = var.cloudtrail_sns_topic_enabled ? 1 : 0 223 | 224 | arn = aws_sns_topic.cloudtrail-sns-topic[0].arn 225 | policy = data.aws_iam_policy_document.cloudtrail-sns-policy[0].json 226 | } 227 | 228 | # -------------------------------------------------------------------------------------------------- 229 | # CloudTrail configuration. 230 | # -------------------------------------------------------------------------------------------------- 231 | 232 | resource "aws_cloudtrail" "global" { 233 | name = var.cloudtrail_name 234 | cloud_watch_logs_group_arn = var.cloudwatch_logs_enabled ? "${aws_cloudwatch_log_group.cloudtrail_events[0].arn}:*" : null 235 | cloud_watch_logs_role_arn = var.cloudwatch_logs_enabled ? aws_iam_role.cloudwatch_delivery[0].arn : null 236 | enable_log_file_validation = true 237 | include_global_service_events = true 238 | is_multi_region_trail = true 239 | is_organization_trail = var.is_organization_trail 240 | kms_key_id = aws_kms_key.cloudtrail.arn 241 | s3_bucket_name = var.s3_bucket_name 242 | s3_key_prefix = var.s3_key_prefix 243 | sns_topic_name = var.cloudtrail_sns_topic_enabled ? aws_sns_topic.cloudtrail-sns-topic[0].arn : null 244 | 245 | event_selector { 246 | read_write_type = "All" 247 | include_management_events = true 248 | 249 | data_resource { 250 | type = "AWS::S3::Object" 251 | values = var.s3_object_level_logging_buckets 252 | } 253 | } 254 | 255 | event_selector { 256 | read_write_type = "All" 257 | include_management_events = true 258 | 259 | data_resource { 260 | type = "AWS::DynamoDB::Table" 261 | values = var.dynamodb_event_logging_tables 262 | } 263 | 264 | data_resource { 265 | type = "AWS::Lambda::Function" 266 | values = var.lambda_invocation_logging_lambdas 267 | } 268 | } 269 | 270 | insight_selector { 271 | insight_type = "ApiCallRateInsight" 272 | } 273 | 274 | tags = var.tags 275 | 276 | depends_on = [var.cloudtrail_depends_on] 277 | } 278 | -------------------------------------------------------------------------------- /modules/cloudtrail-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_kms_key.cloudtrail[0] 8 | to = aws_kms_key.cloudtrail 9 | } 10 | 11 | moved { 12 | from = aws_cloudtrail.global[0] 13 | to = aws_cloudtrail.global 14 | } 15 | -------------------------------------------------------------------------------- /modules/cloudtrail-baseline/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cloudtrail" { 2 | description = "The trail for recording events in all regions." 3 | value = aws_cloudtrail.global 4 | } 5 | 6 | output "cloudtrail_sns_topic" { 7 | description = "The sns topic linked to the cloudtrail." 8 | value = var.cloudtrail_sns_topic_enabled ? aws_sns_topic.cloudtrail-sns-topic[0] : null 9 | } 10 | 11 | output "kms_key" { 12 | description = "The KMS key used for encrypting CloudTrail events." 13 | value = aws_kms_key.cloudtrail 14 | } 15 | 16 | output "log_delivery_iam_role" { 17 | description = "The IAM role used for delivering CloudTrail events to CloudWatch Logs." 18 | value = var.cloudwatch_logs_enabled ? aws_iam_role.cloudwatch_delivery[0] : null 19 | } 20 | 21 | output "log_group" { 22 | description = "The CloudWatch Logs log group which stores CloudTrail events." 23 | value = var.cloudwatch_logs_enabled ? aws_cloudwatch_log_group.cloudtrail_events[0].name : null 24 | } 25 | -------------------------------------------------------------------------------- /modules/cloudtrail-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aws_account_id" { 2 | description = "The AWS Account ID number of the account." 3 | type = string 4 | } 5 | 6 | variable "cloudtrail_name" { 7 | description = "The name of the trail." 8 | type = string 9 | default = "cloudtrail-multi-region" 10 | } 11 | 12 | variable "cloudtrail_sns_topic_enabled" { 13 | description = "Specifies whether the trail is delivered to a SNS topic." 14 | type = bool 15 | default = true 16 | } 17 | 18 | variable "cloudtrail_sns_topic_name" { 19 | description = "The SNS topic linked to the CloudTrail" 20 | type = string 21 | default = "cloudtrail-multi-region-sns-topic" 22 | } 23 | 24 | variable "cloudwatch_logs_enabled" { 25 | description = "Specifies whether the trail is delivered to CloudWatch Logs." 26 | type = bool 27 | default = true 28 | } 29 | 30 | variable "cloudwatch_logs_group_name" { 31 | description = "The name of CloudWatch Logs group to which CloudTrail events are delivered." 32 | type = string 33 | default = "cloudtrail-multi-region" 34 | } 35 | 36 | variable "cloudwatch_logs_retention_in_days" { 37 | description = "Number of days to retain logs for. CIS recommends 365 days. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. Set to 0 to keep logs indefinitely." 38 | type = number 39 | default = 365 40 | } 41 | 42 | variable "iam_role_name" { 43 | description = "The name of the IAM Role to be used by CloudTrail to delivery logs to CloudWatch Logs group." 44 | type = string 45 | default = "CloudTrail-CloudWatch-Delivery-Role" 46 | } 47 | 48 | variable "iam_role_policy_name" { 49 | description = "The name of the IAM Role Policy to be used by CloudTrail to delivery logs to CloudWatch Logs group." 50 | type = string 51 | default = "CloudTrail-CloudWatch-Delivery-Policy" 52 | } 53 | 54 | variable "permissions_boundary_arn" { 55 | description = "The permissions boundary ARN for all IAM Roles, provisioned by this module" 56 | type = string 57 | default = "" 58 | } 59 | 60 | variable "key_deletion_window_in_days" { 61 | description = "Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days. Defaults to 30 days." 62 | type = number 63 | default = 10 64 | } 65 | 66 | variable "region" { 67 | description = "The AWS region in which CloudTrail is set up." 68 | type = string 69 | } 70 | 71 | variable "s3_bucket_name" { 72 | description = "The name of the S3 bucket which will store configuration snapshots." 73 | type = string 74 | } 75 | 76 | variable "s3_key_prefix" { 77 | description = "The prefix for the specified S3 bucket." 78 | type = string 79 | default = "" 80 | } 81 | 82 | variable "is_organization_trail" { 83 | description = "Specifies whether the trail is an AWS Organizations trail. Organization trails log events for the master account and all member accounts. Can only be created in the organization master account." 84 | type = bool 85 | default = false 86 | } 87 | 88 | variable "s3_object_level_logging_buckets" { 89 | description = "The list of S3 bucket ARNs on which to enable object-level logging." 90 | type = list(string) 91 | default = ["arn:aws:s3:::"] # All S3 buckets 92 | } 93 | 94 | variable "dynamodb_event_logging_tables" { 95 | description = "The list of DynamoDB table ARNs on which to enable event logging." 96 | type = list(string) 97 | default = ["arn:aws:dynamodb"] # All DynamoDB tables 98 | } 99 | 100 | variable "lambda_invocation_logging_lambdas" { 101 | description = "The list of lambda ARNs on which to enable invocation logging." 102 | type = list(string) 103 | default = ["arn:aws:lambda"] # All lambdas 104 | } 105 | 106 | variable "tags" { 107 | description = "Specifies object tags key and value. This applies to all resources created by this module." 108 | type = map(string) 109 | default = { 110 | "Terraform" = "true" 111 | } 112 | } 113 | 114 | # Use the hack to inject external dependencies from outsite the module. 115 | # See below for more detail. 116 | # https://stackoverflow.com/questions/58275233/terraform-depends-on-with-modules 117 | variable "cloudtrail_depends_on" { 118 | description = "External resources which should be set up before CloudTrail." 119 | type = list(any) 120 | default = [] 121 | } 122 | -------------------------------------------------------------------------------- /modules/cloudtrail-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/config-baseline/README.md: -------------------------------------------------------------------------------- 1 | # config-baseline 2 | 3 | Enable AWS Config in all regions to automatically take configuration snapshots. 4 | 5 | 6 | ## Requirements 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 11 | | [aws](#requirement\_aws) | >= 4.3 | 12 | 13 | ## Providers 14 | 15 | | Name | Version | 16 | |------|---------| 17 | | [aws](#provider\_aws) | >= 4.3 | 18 | 19 | ## Inputs 20 | 21 | | Name | Description | Type | Required | 22 | |------|-------------|------|:--------:| 23 | | [iam\_role\_arn](#input\_iam\_role\_arn) | The ARN of the IAM Role which AWS Config will use. | `string` | yes | 24 | | [s3\_bucket\_name](#input\_s3\_bucket\_name) | The name of the S3 bucket which will store configuration snapshots. | `string` | yes | 25 | | [delivery\_channel\_name](#input\_delivery\_channel\_name) | The name of the delivery channel. | `string` | no | 26 | | [delivery\_frequency](#input\_delivery\_frequency) | The frequency which AWS Config sends a snapshot into the S3 bucket. | `string` | no | 27 | | [include\_global\_resource\_types](#input\_include\_global\_resource\_types) | Specifies whether AWS Config includes all supported types of global resources with the resources that it records. | `bool` | no | 28 | | [recorder\_name](#input\_recorder\_name) | The name of the configuration recorder. | `string` | no | 29 | | [s3\_key\_prefix](#input\_s3\_key\_prefix) | The prefix for the specified S3 bucket. | `string` | no | 30 | | [sns\_topic\_kms\_master\_key\_id](#input\_sns\_topic\_kms\_master\_key\_id) | To enable SNS Topic encryption enter value with the ID of a custom master KMS key that is used for encryption | `string` | no | 31 | | [sns\_topic\_name](#input\_sns\_topic\_name) | The name of the SNS Topic to be used to notify configuration changes. | `string` | no | 32 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 33 | 34 | ## Outputs 35 | 36 | | Name | Description | 37 | |------|-------------| 38 | | [config\_sns\_topic](#output\_config\_sns\_topic) | The SNS topic that AWS Config delivers notifications to. | 39 | | [configuration\_recorder](#output\_configuration\_recorder) | The configuration recorder. | 40 | 41 | -------------------------------------------------------------------------------- /modules/config-baseline/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | data "aws_region" "current" {} 3 | 4 | # -------------------------------------------------------------------------------------------------- 5 | # Set up AWS Config recorder and let it publish results and send notifications. 6 | # -------------------------------------------------------------------------------------------------- 7 | 8 | resource "aws_sns_topic" "config" { 9 | name = var.sns_topic_name 10 | kms_master_key_id = var.sns_topic_kms_master_key_id 11 | 12 | tags = var.tags 13 | } 14 | 15 | resource "aws_sns_topic_policy" "config" { 16 | arn = aws_sns_topic.config.arn 17 | policy = data.aws_iam_policy_document.config-sns-policy.json 18 | } 19 | 20 | data "aws_iam_policy_document" "config-sns-policy" { 21 | statement { 22 | actions = ["sns:Publish"] 23 | resources = [aws_sns_topic.config.arn] 24 | 25 | principals { 26 | type = "Service" 27 | identifiers = ["config.amazonaws.com"] 28 | } 29 | 30 | condition { 31 | test = "ArnLike" 32 | variable = "aws:SourceArn" 33 | values = ["arn:aws:config:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:*"] 34 | } 35 | } 36 | } 37 | 38 | resource "aws_config_configuration_recorder" "recorder" { 39 | name = var.recorder_name 40 | role_arn = var.iam_role_arn 41 | 42 | recording_group { 43 | all_supported = true 44 | include_global_resource_types = var.include_global_resource_types 45 | } 46 | } 47 | 48 | resource "aws_config_delivery_channel" "bucket" { 49 | name = var.delivery_channel_name 50 | s3_bucket_name = var.s3_bucket_name 51 | s3_key_prefix = var.s3_key_prefix 52 | sns_topic_arn = aws_sns_topic.config.arn 53 | 54 | snapshot_delivery_properties { 55 | delivery_frequency = var.delivery_frequency 56 | } 57 | 58 | depends_on = [aws_config_configuration_recorder.recorder] 59 | } 60 | 61 | resource "aws_config_configuration_recorder_status" "recorder" { 62 | name = aws_config_configuration_recorder.recorder.id 63 | is_enabled = true 64 | 65 | depends_on = [aws_config_delivery_channel.bucket] 66 | } 67 | -------------------------------------------------------------------------------- /modules/config-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_sns_topic.config[0] 8 | to = aws_sns_topic.config 9 | } 10 | 11 | moved { 12 | from = aws_sns_topic_policy.config[0] 13 | to = aws_sns_topic_policy.config 14 | } 15 | 16 | moved { 17 | from = aws_config_configuration_recorder.recorder[0] 18 | to = aws_config_configuration_recorder.recorder 19 | } 20 | 21 | moved { 22 | from = aws_config_configuration_recorder_status.recorder[0] 23 | to = aws_config_configuration_recorder_status.recorder 24 | } 25 | 26 | moved { 27 | from = aws_config_delivery_channel.bucket[0] 28 | to = aws_config_delivery_channel.bucket 29 | } 30 | -------------------------------------------------------------------------------- /modules/config-baseline/outputs.tf: -------------------------------------------------------------------------------- 1 | output "configuration_recorder" { 2 | description = "The configuration recorder." 3 | value = aws_config_configuration_recorder.recorder 4 | } 5 | 6 | output "config_sns_topic" { 7 | description = "The SNS topic that AWS Config delivers notifications to." 8 | value = aws_sns_topic.config 9 | } 10 | -------------------------------------------------------------------------------- /modules/config-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "iam_role_arn" { 2 | description = "The ARN of the IAM Role which AWS Config will use." 3 | type = string 4 | } 5 | 6 | variable "s3_bucket_name" { 7 | description = "The name of the S3 bucket which will store configuration snapshots." 8 | type = string 9 | } 10 | 11 | variable "s3_key_prefix" { 12 | description = "The prefix for the specified S3 bucket." 13 | type = string 14 | default = "" 15 | } 16 | 17 | variable "sns_topic_name" { 18 | description = "The name of the SNS Topic to be used to notify configuration changes." 19 | type = string 20 | default = "ConfigChanges" 21 | } 22 | 23 | variable "sns_topic_kms_master_key_id" { 24 | description = "To enable SNS Topic encryption enter value with the ID of a custom master KMS key that is used for encryption" 25 | type = string 26 | default = null 27 | } 28 | 29 | variable "delivery_frequency" { 30 | description = "The frequency which AWS Config sends a snapshot into the S3 bucket." 31 | type = string 32 | default = "One_Hour" 33 | } 34 | 35 | variable "recorder_name" { 36 | description = "The name of the configuration recorder." 37 | type = string 38 | default = "default" 39 | } 40 | 41 | variable "delivery_channel_name" { 42 | description = "The name of the delivery channel." 43 | type = string 44 | default = "default" 45 | } 46 | 47 | variable "include_global_resource_types" { 48 | description = "Specifies whether AWS Config includes all supported types of global resources with the resources that it records." 49 | type = bool 50 | default = true 51 | } 52 | 53 | variable "tags" { 54 | description = "Specifies object tags key and value. This applies to all resources created by this module." 55 | type = map(string) 56 | default = { 57 | "Terraform" = "true" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /modules/config-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/ebs-baseline/README.md: -------------------------------------------------------------------------------- 1 | # ebs-baseline 2 | 3 | ## Features 4 | 5 | - Enable EBS encryption by default. 6 | 7 | 8 | ## Requirements 9 | 10 | | Name | Version | 11 | |------|---------| 12 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 13 | | [aws](#requirement\_aws) | >= 4.3 | 14 | 15 | ## Providers 16 | 17 | | Name | Version | 18 | |------|---------| 19 | | [aws](#provider\_aws) | >= 4.3 | 20 | 21 | ## Inputs 22 | 23 | No inputs. 24 | 25 | ## Outputs 26 | 27 | No outputs. 28 | 29 | -------------------------------------------------------------------------------- /modules/ebs-baseline/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ebs_encryption_by_default" "this" { 2 | enabled = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/ebs-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_ebs_encryption_by_default.this[0] 8 | to = aws_ebs_encryption_by_default.this 9 | } 10 | -------------------------------------------------------------------------------- /modules/ebs-baseline/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/modules/ebs-baseline/outputs.tf -------------------------------------------------------------------------------- /modules/ebs-baseline/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/modules/ebs-baseline/variables.tf -------------------------------------------------------------------------------- /modules/ebs-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/guardduty-baseline/README.md: -------------------------------------------------------------------------------- 1 | # guardduty-baseline 2 | 3 | Enable GuardDuty in all regions. 4 | 5 | 6 | ## Requirements 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 11 | | [aws](#requirement\_aws) | >= 4.3 | 12 | 13 | ## Providers 14 | 15 | | Name | Version | 16 | |------|---------| 17 | | [aws](#provider\_aws) | >= 4.3 | 18 | 19 | ## Inputs 20 | 21 | | Name | Description | Type | Required | 22 | |------|-------------|------|:--------:| 23 | | [disable\_email\_notification](#input\_disable\_email\_notification) | Boolean whether an email notification is sent to the accounts. | `bool` | no | 24 | | [finding\_publishing\_frequency](#input\_finding\_publishing\_frequency) | Specifies the frequency of notifications sent for subsequent finding occurrences. | `string` | no | 25 | | [invitation\_message](#input\_invitation\_message) | Message for invitation. | `string` | no | 26 | | [master\_account\_id](#input\_master\_account\_id) | AWS account ID for master account. | `string` | no | 27 | | [member\_accounts](#input\_member\_accounts) | A list of IDs and emails of AWS accounts which associated as member accounts. |
list(object({
account_id = string
email = string
}))
| no | 28 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 29 | 30 | ## Outputs 31 | 32 | | Name | Description | 33 | |------|-------------| 34 | | [guardduty\_detector](#output\_guardduty\_detector) | The GuardDuty detector. | 35 | 36 | -------------------------------------------------------------------------------- /modules/guardduty-baseline/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_guardduty_detector" "default" { 2 | enable = true 3 | finding_publishing_frequency = var.finding_publishing_frequency 4 | 5 | # datasources can't be individually managed in each member account. 6 | dynamic "datasources" { 7 | for_each = var.master_account_id == "" ? [var.master_account_id] : [] 8 | 9 | content { 10 | s3_logs { 11 | enable = true 12 | } 13 | } 14 | } 15 | 16 | tags = var.tags 17 | } 18 | 19 | resource "aws_guardduty_member" "members" { 20 | count = length(var.member_accounts) 21 | 22 | detector_id = aws_guardduty_detector.default.id 23 | invite = true 24 | account_id = var.member_accounts[count.index].account_id 25 | disable_email_notification = var.disable_email_notification 26 | email = var.member_accounts[count.index].email 27 | invitation_message = var.invitation_message 28 | } 29 | 30 | resource "aws_guardduty_invite_accepter" "master" { 31 | count = var.master_account_id != "" ? 1 : 0 32 | 33 | detector_id = aws_guardduty_detector.default.id 34 | master_account_id = var.master_account_id 35 | } 36 | -------------------------------------------------------------------------------- /modules/guardduty-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_guardduty_detector.default[0] 8 | to = aws_guardduty_detector.default 9 | } 10 | -------------------------------------------------------------------------------- /modules/guardduty-baseline/outputs.tf: -------------------------------------------------------------------------------- 1 | output "guardduty_detector" { 2 | description = "The GuardDuty detector." 3 | value = aws_guardduty_detector.default 4 | } 5 | -------------------------------------------------------------------------------- /modules/guardduty-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "disable_email_notification" { 2 | description = "Boolean whether an email notification is sent to the accounts." 3 | type = bool 4 | default = false 5 | } 6 | 7 | variable "finding_publishing_frequency" { 8 | description = "Specifies the frequency of notifications sent for subsequent finding occurrences." 9 | type = string 10 | default = "SIX_HOURS" 11 | } 12 | 13 | variable "invitation_message" { 14 | description = "Message for invitation." 15 | type = string 16 | default = "This is an automatic invitation message from guardduty-baseline module." 17 | } 18 | 19 | variable "master_account_id" { 20 | description = "AWS account ID for master account." 21 | type = string 22 | default = "" 23 | } 24 | 25 | variable "member_accounts" { 26 | description = "A list of IDs and emails of AWS accounts which associated as member accounts." 27 | type = list(object({ 28 | account_id = string 29 | email = string 30 | })) 31 | default = [] 32 | } 33 | 34 | variable "tags" { 35 | description = "Specifies object tags key and value. This applies to all resources created by this module." 36 | type = map(string) 37 | default = { 38 | "Terraform" = "true" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /modules/guardduty-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/iam-baseline/README.md: -------------------------------------------------------------------------------- 1 | # iam-baseline 2 | 3 | ## Features 4 | 5 | - Set up IAM Password Policy. 6 | - Create default IAM roles for managing AWS account. 7 | 8 | 9 | ## Requirements 10 | 11 | | Name | Version | 12 | |------|---------| 13 | | [terraform](#requirement\_terraform) | >= 0.13 | 14 | | [aws](#requirement\_aws) | >= 4.3 | 15 | 16 | ## Providers 17 | 18 | | Name | Version | 19 | |------|---------| 20 | | [aws](#provider\_aws) | >= 4.3 | 21 | 22 | ## Inputs 23 | 24 | | Name | Description | Type | Required | 25 | |------|-------------|------|:--------:| 26 | | [support\_iam\_role\_principal\_arns](#input\_support\_iam\_role\_principal\_arns) | List of ARNs of the IAM principal elements by which the support role could be assumed. | `list(any)` | yes | 27 | | [allow\_users\_to\_change\_password](#input\_allow\_users\_to\_change\_password) | Whether to allow users to change their own password. | `bool` | no | 28 | | [create\_password\_policy](#input\_create\_password\_policy) | Define if the password policy should be created. | `bool` | no | 29 | | [create\_support\_role](#input\_create\_support\_role) | Define if the support role should be created. | `bool` | no | 30 | | [max\_password\_age](#input\_max\_password\_age) | The number of days that an user password is valid. | `number` | no | 31 | | [minimum\_password\_length](#input\_minimum\_password\_length) | Minimum length to require for user passwords. | `number` | no | 32 | | [password\_reuse\_prevention](#input\_password\_reuse\_prevention) | The number of previous passwords that users are prevented from reusing. | `number` | no | 33 | | [permissions\_boundary\_arn](#input\_permissions\_boundary\_arn) | The permissions boundary ARN for all IAM Roles, provisioned by this module | `string` | no | 34 | | [require\_lowercase\_characters](#input\_require\_lowercase\_characters) | Whether to require lowercase characters for user passwords. | `bool` | no | 35 | | [require\_numbers](#input\_require\_numbers) | Whether to require numbers for user passwords. | `bool` | no | 36 | | [require\_symbols](#input\_require\_symbols) | Whether to require symbols for user passwords. | `bool` | no | 37 | | [require\_uppercase\_characters](#input\_require\_uppercase\_characters) | Whether to require uppercase characters for user passwords. | `bool` | no | 38 | | [support\_iam\_role\_name](#input\_support\_iam\_role\_name) | The name of the the support role. | `string` | no | 39 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 40 | 41 | ## Outputs 42 | 43 | | Name | Description | 44 | |------|-------------| 45 | | [support\_iam\_role](#output\_support\_iam\_role) | The IAM role used for the support user. | 46 | 47 | -------------------------------------------------------------------------------- /modules/iam-baseline/main.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Password Policy 3 | # -------------------------------------------------------------------------------------------------- 4 | 5 | resource "aws_iam_account_password_policy" "default" { 6 | count = var.create_password_policy ? 1 : 0 7 | 8 | minimum_password_length = var.minimum_password_length 9 | password_reuse_prevention = var.password_reuse_prevention 10 | require_lowercase_characters = var.require_lowercase_characters 11 | require_numbers = var.require_numbers 12 | require_uppercase_characters = var.require_uppercase_characters 13 | require_symbols = var.require_symbols 14 | allow_users_to_change_password = var.allow_users_to_change_password 15 | max_password_age = var.max_password_age 16 | } 17 | 18 | # -------------------------------------------------------------------------------------------------- 19 | # Support Role 20 | # -------------------------------------------------------------------------------------------------- 21 | 22 | data "aws_iam_policy_document" "support_assume_policy" { 23 | statement { 24 | principals { 25 | type = "AWS" 26 | identifiers = var.support_iam_role_principal_arns 27 | } 28 | actions = ["sts:AssumeRole"] 29 | } 30 | } 31 | 32 | resource "aws_iam_role" "support" { 33 | count = var.create_support_role ? 1 : 0 34 | 35 | name = var.support_iam_role_name 36 | assume_role_policy = data.aws_iam_policy_document.support_assume_policy.json 37 | 38 | permissions_boundary = var.permissions_boundary_arn 39 | 40 | tags = var.tags 41 | } 42 | 43 | resource "aws_iam_role_policy_attachment" "support_policy" { 44 | count = var.create_support_role ? 1 : 0 45 | 46 | role = aws_iam_role.support[0].id 47 | policy_arn = "arn:aws:iam::aws:policy/AWSSupportAccess" 48 | } 49 | 50 | -------------------------------------------------------------------------------- /modules/iam-baseline/outputs.tf: -------------------------------------------------------------------------------- 1 | output "support_iam_role" { 2 | description = "The IAM role used for the support user." 3 | value = aws_iam_role.support 4 | } 5 | -------------------------------------------------------------------------------- /modules/iam-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "support_iam_role_name" { 2 | description = "The name of the the support role." 3 | type = string 4 | default = "IAM-Support" 5 | } 6 | 7 | variable "permissions_boundary_arn" { 8 | description = "The permissions boundary ARN for all IAM Roles, provisioned by this module" 9 | type = string 10 | default = "" 11 | } 12 | 13 | variable "support_iam_role_principal_arns" { 14 | type = list(any) 15 | description = "List of ARNs of the IAM principal elements by which the support role could be assumed." 16 | } 17 | 18 | variable "max_password_age" { 19 | description = "The number of days that an user password is valid." 20 | type = number 21 | default = 0 22 | } 23 | 24 | variable "minimum_password_length" { 25 | description = "Minimum length to require for user passwords." 26 | type = number 27 | default = 14 28 | } 29 | 30 | variable "password_reuse_prevention" { 31 | description = "The number of previous passwords that users are prevented from reusing." 32 | type = number 33 | default = 24 34 | } 35 | 36 | variable "require_lowercase_characters" { 37 | description = "Whether to require lowercase characters for user passwords." 38 | type = bool 39 | default = true 40 | } 41 | 42 | variable "require_numbers" { 43 | description = "Whether to require numbers for user passwords." 44 | type = bool 45 | default = true 46 | } 47 | 48 | variable "require_uppercase_characters" { 49 | description = "Whether to require uppercase characters for user passwords." 50 | type = bool 51 | default = true 52 | } 53 | 54 | variable "require_symbols" { 55 | description = "Whether to require symbols for user passwords." 56 | type = bool 57 | default = true 58 | } 59 | 60 | variable "allow_users_to_change_password" { 61 | description = "Whether to allow users to change their own password." 62 | type = bool 63 | default = true 64 | } 65 | 66 | variable "create_password_policy" { 67 | description = "Define if the password policy should be created." 68 | type = bool 69 | default = true 70 | } 71 | 72 | variable "create_support_role" { 73 | description = "Define if the support role should be created." 74 | type = bool 75 | default = true 76 | } 77 | 78 | variable "tags" { 79 | description = "Specifies object tags key and value. This applies to all resources created by this module." 80 | type = map(string) 81 | default = { 82 | "Terraform" = "true" 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /modules/iam-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/s3-baseline/README.md: -------------------------------------------------------------------------------- 1 | # s3-baseline 2 | 3 | ## Features 4 | 5 | - Enable S3 account-level Public Access Block configuration. 6 | 7 | 8 | ## Requirements 9 | 10 | | Name | Version | 11 | |------|---------| 12 | | [terraform](#requirement\_terraform) | >= 0.13 | 13 | | [aws](#requirement\_aws) | >= 4.3 | 14 | 15 | ## Providers 16 | 17 | | Name | Version | 18 | |------|---------| 19 | | [aws](#provider\_aws) | >= 4.3 | 20 | 21 | ## Inputs 22 | 23 | | Name | Description | Type | Required | 24 | |------|-------------|------|:--------:| 25 | | [block\_public\_acls](#input\_block\_public\_acls) | Whether Amazon S3 should block public ACLs for buckets in this account. Defaults to true. | `bool` | no | 26 | | [block\_public\_policy](#input\_block\_public\_policy) | Whether Amazon S3 should block public bucket policies for buckets in this account. Defaults to true. | `bool` | no | 27 | | [ignore\_public\_acls](#input\_ignore\_public\_acls) | Whether Amazon S3 should ignore public ACLs for buckets in this account. Defaults to true. | `bool` | no | 28 | | [restrict\_public\_buckets](#input\_restrict\_public\_buckets) | Whether Amazon S3 should restrict public bucket policies for buckets in this account. Defaults to true. | `bool` | no | 29 | 30 | ## Outputs 31 | 32 | No outputs. 33 | 34 | -------------------------------------------------------------------------------- /modules/s3-baseline/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_account_public_access_block" "this" { 2 | block_public_acls = var.block_public_acls 3 | block_public_policy = var.block_public_policy 4 | ignore_public_acls = var.ignore_public_acls 5 | restrict_public_buckets = var.restrict_public_buckets 6 | } 7 | 8 | -------------------------------------------------------------------------------- /modules/s3-baseline/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/modules/s3-baseline/outputs.tf -------------------------------------------------------------------------------- /modules/s3-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "block_public_acls" { 2 | description = "Whether Amazon S3 should block public ACLs for buckets in this account. Defaults to true." 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "block_public_policy" { 8 | description = "Whether Amazon S3 should block public bucket policies for buckets in this account. Defaults to true." 9 | type = bool 10 | default = true 11 | } 12 | 13 | variable "ignore_public_acls" { 14 | description = "Whether Amazon S3 should ignore public ACLs for buckets in this account. Defaults to true." 15 | type = bool 16 | default = true 17 | } 18 | 19 | variable "restrict_public_buckets" { 20 | description = "Whether Amazon S3 should restrict public bucket policies for buckets in this account. Defaults to true." 21 | type = bool 22 | default = true 23 | } 24 | -------------------------------------------------------------------------------- /modules/s3-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/secure-bucket/README.md: -------------------------------------------------------------------------------- 1 | # secure-bucket 2 | 3 | Creates a S3 bucket with access logging enabled. 4 | 5 | 6 | ## Requirements 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [terraform](#requirement\_terraform) | >= 0.13 | 11 | | [aws](#requirement\_aws) | >= 4.3 | 12 | 13 | ## Providers 14 | 15 | | Name | Version | 16 | |------|---------| 17 | | [aws](#provider\_aws) | >= 4.3 | 18 | 19 | ## Inputs 20 | 21 | | Name | Description | Type | Required | 22 | |------|-------------|------|:--------:| 23 | | [bucket\_name](#input\_bucket\_name) | The name of the S3 bucket to create. | `string` | yes | 24 | | [log\_bucket\_name](#input\_log\_bucket\_name) | The name of the S3 bucket to store access logs to the main bucket. | `string` | yes | 25 | | [bucket\_key\_enabled](#input\_bucket\_key\_enabled) | Whether or not to use Amazon S3 Bucket Keys for this bucket. | `bool` | no | 26 | | [force\_destroy](#input\_force\_destroy) | A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable. | `bool` | no | 27 | | [lifecycle\_glacier\_transition\_days](#input\_lifecycle\_glacier\_transition\_days) | The number of days after object creation when the object is archived into Glacier. Setting to zero disables the transition. | `number` | no | 28 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 29 | 30 | ## Outputs 31 | 32 | | Name | Description | 33 | |------|-------------| 34 | | [log\_bucket](#output\_log\_bucket) | The S3 bucket used for storing access logs of this bucket. | 35 | | [this\_bucket](#output\_this\_bucket) | This S3 bucket. | 36 | 37 | -------------------------------------------------------------------------------- /modules/secure-bucket/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "access_log_policy" { 2 | statement { 3 | actions = ["s3:*"] 4 | effect = "Deny" 5 | resources = [ 6 | aws_s3_bucket.access_log.arn, 7 | "${aws_s3_bucket.access_log.arn}/*" 8 | ] 9 | condition { 10 | test = "Bool" 11 | variable = "aws:SecureTransport" 12 | values = ["false"] 13 | } 14 | principals { 15 | type = "*" 16 | identifiers = ["*"] 17 | } 18 | } 19 | } 20 | 21 | resource "aws_s3_bucket" "access_log" { 22 | bucket = var.log_bucket_name 23 | force_destroy = var.force_destroy 24 | 25 | tags = var.tags 26 | } 27 | 28 | resource "aws_s3_bucket_acl" "access_log" { 29 | bucket = aws_s3_bucket.access_log.id 30 | acl = "log-delivery-write" 31 | } 32 | 33 | resource "aws_s3_bucket_server_side_encryption_configuration" "access_log" { 34 | bucket = aws_s3_bucket.access_log.id 35 | 36 | rule { 37 | apply_server_side_encryption_by_default { 38 | sse_algorithm = "AES256" 39 | } 40 | } 41 | } 42 | 43 | resource "aws_s3_bucket_lifecycle_configuration" "access_log" { 44 | count = var.lifecycle_glacier_transition_days > 0 ? 1 : 0 45 | 46 | bucket = aws_s3_bucket.access_log.id 47 | 48 | rule { 49 | id = "auto-archive" 50 | status = "Enabled" 51 | 52 | filter {} 53 | 54 | transition { 55 | days = var.lifecycle_glacier_transition_days 56 | storage_class = "GLACIER" 57 | } 58 | } 59 | } 60 | 61 | resource "aws_s3_bucket_policy" "access_log_policy" { 62 | bucket = aws_s3_bucket.access_log.id 63 | policy = data.aws_iam_policy_document.access_log_policy.json 64 | 65 | depends_on = [ 66 | aws_s3_bucket_public_access_block.access_log, 67 | ] 68 | } 69 | 70 | resource "aws_s3_bucket_public_access_block" "access_log" { 71 | bucket = aws_s3_bucket.access_log.id 72 | block_public_acls = true 73 | block_public_policy = true 74 | ignore_public_acls = true 75 | restrict_public_buckets = true 76 | } 77 | 78 | resource "aws_s3_bucket" "content" { 79 | bucket = var.bucket_name 80 | force_destroy = var.force_destroy 81 | 82 | tags = var.tags 83 | 84 | depends_on = [ 85 | aws_s3_bucket_public_access_block.access_log 86 | ] 87 | } 88 | 89 | resource "aws_s3_bucket_acl" "content" { 90 | bucket = aws_s3_bucket.content.id 91 | acl = "private" 92 | } 93 | 94 | resource "aws_s3_bucket_server_side_encryption_configuration" "content" { 95 | bucket = aws_s3_bucket.content.id 96 | 97 | rule { 98 | apply_server_side_encryption_by_default { 99 | sse_algorithm = "AES256" 100 | } 101 | bucket_key_enabled = var.bucket_key_enabled 102 | } 103 | } 104 | 105 | resource "aws_s3_bucket_logging" "content" { 106 | bucket = aws_s3_bucket.content.id 107 | 108 | target_bucket = aws_s3_bucket.access_log.id 109 | target_prefix = "" 110 | } 111 | 112 | resource "aws_s3_bucket_lifecycle_configuration" "content" { 113 | count = var.lifecycle_glacier_transition_days > 0 ? 1 : 0 114 | 115 | bucket = aws_s3_bucket.content.id 116 | 117 | rule { 118 | id = "auto-archive" 119 | status = "Enabled" 120 | 121 | filter {} 122 | 123 | transition { 124 | days = var.lifecycle_glacier_transition_days 125 | storage_class = "GLACIER" 126 | } 127 | 128 | noncurrent_version_transition { 129 | noncurrent_days = var.lifecycle_glacier_transition_days 130 | storage_class = "GLACIER" 131 | } 132 | } 133 | } 134 | 135 | resource "aws_s3_bucket_versioning" "content" { 136 | bucket = aws_s3_bucket.content.id 137 | 138 | versioning_configuration { 139 | status = "Enabled" 140 | # Temporarily disabled due to Terraform issue. 141 | # https://github.com/terraform-providers/terraform-provider-aws/issues/629 142 | # mfa_delete = true 143 | } 144 | } 145 | 146 | resource "aws_s3_bucket_public_access_block" "content" { 147 | bucket = aws_s3_bucket.content.id 148 | block_public_acls = true 149 | block_public_policy = true 150 | ignore_public_acls = true 151 | restrict_public_buckets = true 152 | } 153 | 154 | -------------------------------------------------------------------------------- /modules/secure-bucket/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 1.0.0 3 | # Replacing `enabled` argument in secure-bucket module with `count` meta-argument 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_s3_bucket.access_log[0] 8 | to = aws_s3_bucket.access_log 9 | } 10 | 11 | moved { 12 | from = aws_s3_bucket_policy.access_log_policy[0] 13 | to = aws_s3_bucket_policy.access_log_policy 14 | } 15 | 16 | moved { 17 | from = aws_s3_bucket_public_access_block.access_log[0] 18 | to = aws_s3_bucket_public_access_block.access_log 19 | } 20 | 21 | moved { 22 | from = aws_s3_bucket.content[0] 23 | to = aws_s3_bucket.content 24 | } 25 | 26 | moved { 27 | from = aws_s3_bucket_public_access_block.content[0] 28 | to = aws_s3_bucket_public_access_block.content 29 | } 30 | 31 | -------------------------------------------------------------------------------- /modules/secure-bucket/outputs.tf: -------------------------------------------------------------------------------- 1 | output "this_bucket" { 2 | description = "This S3 bucket." 3 | value = aws_s3_bucket.content 4 | } 5 | 6 | output "log_bucket" { 7 | description = "The S3 bucket used for storing access logs of this bucket." 8 | value = aws_s3_bucket.access_log 9 | } 10 | -------------------------------------------------------------------------------- /modules/secure-bucket/variables.tf: -------------------------------------------------------------------------------- 1 | variable "bucket_name" { 2 | description = "The name of the S3 bucket to create." 3 | type = string 4 | } 5 | 6 | variable "log_bucket_name" { 7 | description = "The name of the S3 bucket to store access logs to the main bucket." 8 | type = string 9 | } 10 | 11 | variable "lifecycle_glacier_transition_days" { 12 | description = "The number of days after object creation when the object is archived into Glacier. Setting to zero disables the transition." 13 | type = number 14 | default = 0 15 | } 16 | 17 | variable "force_destroy" { 18 | description = " A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable." 19 | type = bool 20 | default = false 21 | } 22 | 23 | variable "tags" { 24 | description = "Specifies object tags key and value. This applies to all resources created by this module." 25 | type = map(string) 26 | default = { 27 | "Terraform" = "true" 28 | } 29 | } 30 | 31 | variable "bucket_key_enabled" { 32 | description = "Whether or not to use Amazon S3 Bucket Keys for this bucket." 33 | type = bool 34 | default = false 35 | } 36 | -------------------------------------------------------------------------------- /modules/secure-bucket/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/securityhub-baseline/README.md: -------------------------------------------------------------------------------- 1 | # securityhub-baseline 2 | 3 | ## Features 4 | 5 | - Enable SecurityHub. 6 | - Subscribe CIS benchmark standard. 7 | - Subscribe PCI DSS standard. 8 | - Subscribe AWS Foundational security best practices standard. 9 | 10 | 11 | ## Requirements 12 | 13 | | Name | Version | 14 | |------|---------| 15 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 16 | | [aws](#requirement\_aws) | >= 4.3 | 17 | 18 | ## Providers 19 | 20 | | Name | Version | 21 | |------|---------| 22 | | [aws](#provider\_aws) | >= 4.3 | 23 | 24 | ## Inputs 25 | 26 | | Name | Description | Type | Required | 27 | |------|-------------|------|:--------:| 28 | | [aggregate\_findings](#input\_aggregate\_findings) | Boolean whether to enable finding aggregator for every region | `bool` | no | 29 | | [enable\_aws\_foundational\_standard](#input\_enable\_aws\_foundational\_standard) | Boolean whether AWS Foundations standard is enabled. | `bool` | no | 30 | | [enable\_cis\_standard](#input\_enable\_cis\_standard) | Boolean whether CIS standard is enabled. | `bool` | no | 31 | | [enable\_pci\_dss\_standard](#input\_enable\_pci\_dss\_standard) | Boolean whether PCI DSS standard is enabled. | `bool` | no | 32 | | [enable\_product\_arns](#input\_enable\_product\_arns) | List of Security Hub product ARNs, `` will be replaced. See https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-partner-providers.html for list. | `list(string)` | no | 33 | | [master\_account\_id](#input\_master\_account\_id) | AWS account ID for master account. | `string` | no | 34 | | [member\_accounts](#input\_member\_accounts) | A list of IDs and emails of AWS accounts which associated as member accounts. |
list(object({
account_id = string
email = string
}))
| no | 35 | 36 | ## Outputs 37 | 38 | No outputs. 39 | 40 | -------------------------------------------------------------------------------- /modules/securityhub-baseline/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "current" {} 2 | 3 | # -------------------------------------------------------------------------------------------------- 4 | # Enable SecurityHub 5 | # -------------------------------------------------------------------------------------------------- 6 | 7 | resource "aws_securityhub_account" "main" { 8 | } 9 | 10 | resource "aws_securityhub_finding_aggregator" "main" { 11 | count = var.aggregate_findings && var.master_account_id == "" ? 1 : 0 12 | 13 | linking_mode = "ALL_REGIONS" 14 | 15 | depends_on = [aws_securityhub_account.main] 16 | } 17 | 18 | # -------------------------------------------------------------------------------------------------- 19 | # Add member accounts 20 | # -------------------------------------------------------------------------------------------------- 21 | 22 | resource "aws_securityhub_member" "members" { 23 | count = length(var.member_accounts) 24 | 25 | depends_on = [aws_securityhub_account.main] 26 | account_id = var.member_accounts[count.index].account_id 27 | email = var.member_accounts[count.index].email 28 | invite = true 29 | } 30 | 31 | resource "aws_securityhub_invite_accepter" "invitee" { 32 | count = var.master_account_id != "" ? 1 : 0 33 | 34 | master_id = var.master_account_id 35 | 36 | depends_on = [aws_securityhub_account.main] 37 | } 38 | 39 | # -------------------------------------------------------------------------------------------------- 40 | # Subscribe standards 41 | # -------------------------------------------------------------------------------------------------- 42 | 43 | resource "aws_securityhub_standards_subscription" "cis" { 44 | count = var.enable_cis_standard ? 1 : 0 45 | 46 | standards_arn = "arn:aws:securityhub:${data.aws_region.current.name}::standards/cis-aws-foundations-benchmark/v/1.4.0" 47 | 48 | depends_on = [aws_securityhub_account.main] 49 | } 50 | 51 | resource "aws_securityhub_standards_subscription" "aws_foundational" { 52 | count = var.enable_aws_foundational_standard ? 1 : 0 53 | 54 | standards_arn = "arn:aws:securityhub:${data.aws_region.current.name}::standards/aws-foundational-security-best-practices/v/1.0.0" 55 | 56 | depends_on = [aws_securityhub_account.main] 57 | } 58 | 59 | resource "aws_securityhub_standards_subscription" "pci_dss" { 60 | count = var.enable_pci_dss_standard ? 1 : 0 61 | 62 | standards_arn = "arn:aws:securityhub:${data.aws_region.current.name}::standards/pci-dss/v/3.2.1" 63 | 64 | depends_on = [aws_securityhub_account.main] 65 | } 66 | 67 | # 3rd party products 68 | resource "aws_securityhub_product_subscription" "products" { 69 | count = length(var.enable_product_arns) 70 | 71 | product_arn = replace(var.enable_product_arns[count.index], "", data.aws_region.current.name) 72 | 73 | depends_on = [aws_securityhub_account.main] 74 | } 75 | -------------------------------------------------------------------------------- /modules/securityhub-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | 2 | # -------------------------------------------------------------------------------------------------- 3 | # Migrations to 0.31.0 4 | # Removing `enabled` argument. 5 | # -------------------------------------------------------------------------------------------------- 6 | 7 | moved { 8 | from = aws_securityhub_account.main[0] 9 | to = aws_securityhub_account.main 10 | } 11 | -------------------------------------------------------------------------------- /modules/securityhub-baseline/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nozaq/terraform-aws-secure-baseline/6b2d679cf480093ec279450d7d0a90affe3ddc43/modules/securityhub-baseline/outputs.tf -------------------------------------------------------------------------------- /modules/securityhub-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aggregate_findings" { 2 | description = "Boolean whether to enable finding aggregator for every region" 3 | type = bool 4 | default = false 5 | } 6 | 7 | variable "enable_cis_standard" { 8 | description = "Boolean whether CIS standard is enabled." 9 | type = bool 10 | default = true 11 | } 12 | 13 | variable "enable_pci_dss_standard" { 14 | description = "Boolean whether PCI DSS standard is enabled." 15 | type = bool 16 | default = true 17 | } 18 | 19 | variable "enable_aws_foundational_standard" { 20 | description = "Boolean whether AWS Foundations standard is enabled." 21 | type = bool 22 | default = true 23 | } 24 | 25 | variable "enable_product_arns" { 26 | description = "List of Security Hub product ARNs, `` will be replaced. See https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-partner-providers.html for list." 27 | type = list(string) 28 | default = [] 29 | } 30 | 31 | variable "master_account_id" { 32 | description = "AWS account ID for master account." 33 | type = string 34 | default = "" 35 | } 36 | 37 | variable "member_accounts" { 38 | description = "A list of IDs and emails of AWS accounts which associated as member accounts." 39 | type = list(object({ 40 | account_id = string 41 | email = string 42 | })) 43 | default = [] 44 | } 45 | -------------------------------------------------------------------------------- /modules/securityhub-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/vpc-baseline/README.md: -------------------------------------------------------------------------------- 1 | # vpc-baseline 2 | 3 | ## Features 4 | 5 | - Enable VPC Flow Logs with the default VPC in all regions. 6 | - Remove all rules associated with default route tables, default network ACLs and default security groups in the default VPC in all regions. 7 | - Disable automatic public IP assignments in default subnets. 8 | 9 | 10 | ## Requirements 11 | 12 | | Name | Version | 13 | |------|---------| 14 | | [terraform](#requirement\_terraform) | >= 1.1.4 | 15 | | [aws](#requirement\_aws) | >= 4.3 | 16 | 17 | ## Providers 18 | 19 | | Name | Version | 20 | |------|---------| 21 | | [aws](#provider\_aws) | >= 4.3 | 22 | 23 | ## Inputs 24 | 25 | | Name | Description | Type | Required | 26 | |------|-------------|------|:--------:| 27 | | [enable\_flow\_logs](#input\_enable\_flow\_logs) | The boolean flag whether to enable VPC Flow Logs in the default VPC | `bool` | no | 28 | | [flow\_logs\_destination\_type](#input\_flow\_logs\_destination\_type) | The type of the logging destination. Valid values: cloud-watch-logs, s3 | `string` | no | 29 | | [flow\_logs\_iam\_role\_arn](#input\_flow\_logs\_iam\_role\_arn) | The ARN of the IAM Role which will be used by VPC Flow Logs if vpc\_log\_destination\_type is cloud-watch-logs. | `string` | no | 30 | | [flow\_logs\_log\_group\_name](#input\_flow\_logs\_log\_group\_name) | The name of CloudWatch Logs group to which VPC Flow Logs are delivered if vpc\_log\_destination\_type is cloud-watch-logs. | `string` | no | 31 | | [flow\_logs\_retention\_in\_days](#input\_flow\_logs\_retention\_in\_days) | Number of days to retain logs if vpc\_log\_destination\_type is cloud-watch-logs. CIS recommends 365 days. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. Set to 0 to keep logs indefinitely. | `number` | no | 32 | | [flow\_logs\_s3\_arn](#input\_flow\_logs\_s3\_arn) | The ARN of the S3 bucket to which VPC Flow Logs are delivered if vpc\_log\_destination\_type is s3. | `string` | no | 33 | | [flow\_logs\_s3\_key\_prefix](#input\_flow\_logs\_s3\_key\_prefix) | The prefix used when VPC Flow Logs delivers logs to the S3 bucket. | `string` | no | 34 | | [tags](#input\_tags) | Specifies object tags key and value. This applies to all resources created by this module. | `map(string)` | no | 35 | 36 | ## Outputs 37 | 38 | | Name | Description | 39 | |------|-------------| 40 | | [default\_network\_acl](#output\_default\_network\_acl) | The default network ACL. | 41 | | [default\_route\_table](#output\_default\_route\_table) | The default route table. | 42 | | [default\_security\_group](#output\_default\_security\_group) | The default security group. | 43 | | [default\_vpc](#output\_default\_vpc) | The default VPC. | 44 | | [vpc\_flow\_logs\_group](#output\_vpc\_flow\_logs\_group) | The CloudWatch Logs log group which stores VPC Flow Logs. | 45 | 46 | -------------------------------------------------------------------------------- /modules/vpc-baseline/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | flow_logs_to_cw_logs = var.enable_flow_logs && var.flow_logs_destination_type == "cloud-watch-logs" 3 | } 4 | 5 | data "aws_subnets" "default" { 6 | filter { 7 | name = "default-for-az" 8 | values = [true] 9 | } 10 | } 11 | 12 | data "aws_subnet" "default" { 13 | for_each = toset(data.aws_subnets.default.ids) 14 | id = each.value 15 | } 16 | 17 | # -------------------------------------------------------------------------------------------------- 18 | # Enable VPC Flow Logs for the default VPC. 19 | # -------------------------------------------------------------------------------------------------- 20 | 21 | resource "aws_cloudwatch_log_group" "default_vpc_flow_logs" { 22 | count = var.enable_flow_logs && local.flow_logs_to_cw_logs ? 1 : 0 23 | 24 | name = var.flow_logs_log_group_name 25 | retention_in_days = var.flow_logs_retention_in_days 26 | 27 | tags = var.tags 28 | } 29 | 30 | resource "aws_flow_log" "default_vpc_flow_logs" { 31 | count = var.enable_flow_logs ? 1 : 0 32 | 33 | log_destination_type = var.flow_logs_destination_type 34 | log_destination = local.flow_logs_to_cw_logs ? aws_cloudwatch_log_group.default_vpc_flow_logs[0].arn : "${var.flow_logs_s3_arn}/${var.flow_logs_s3_key_prefix}" 35 | iam_role_arn = local.flow_logs_to_cw_logs ? var.flow_logs_iam_role_arn : null 36 | vpc_id = aws_default_vpc.default.id 37 | traffic_type = "ALL" 38 | 39 | tags = var.tags 40 | } 41 | 42 | # -------------------------------------------------------------------------------------------------- 43 | # Clears rules associated with default resources. 44 | # -------------------------------------------------------------------------------------------------- 45 | 46 | resource "aws_default_vpc" "default" { 47 | tags = merge( 48 | var.tags, 49 | { Name = "Default VPC" } 50 | ) 51 | } 52 | 53 | resource "aws_default_subnet" "default" { 54 | for_each = data.aws_subnet.default 55 | 56 | availability_zone = each.value.availability_zone 57 | map_public_ip_on_launch = false 58 | 59 | tags = merge( 60 | var.tags, 61 | { Name = "Default Subnet" } 62 | ) 63 | } 64 | 65 | resource "aws_default_route_table" "default" { 66 | default_route_table_id = aws_default_vpc.default.default_route_table_id 67 | 68 | tags = merge( 69 | var.tags, 70 | { Name = "Default Route Table" } 71 | ) 72 | } 73 | 74 | # Ignore "subnet_ids" changes to avoid the known issue below. 75 | # https://github.com/hashicorp/terraform/issues/9824 76 | # https://github.com/terraform-providers/terraform-provider-aws/issues/346 77 | resource "aws_default_network_acl" "default" { 78 | default_network_acl_id = aws_default_vpc.default.default_network_acl_id 79 | 80 | tags = merge( 81 | var.tags, 82 | { Name = "Default Network ACL" } 83 | ) 84 | 85 | lifecycle { 86 | ignore_changes = [subnet_ids] 87 | } 88 | } 89 | 90 | resource "aws_default_security_group" "default" { 91 | vpc_id = aws_default_vpc.default.id 92 | 93 | tags = merge( 94 | var.tags, 95 | { Name = "Default Security Group" } 96 | ) 97 | } 98 | -------------------------------------------------------------------------------- /modules/vpc-baseline/migrations.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # Migrations to 0.31.0 3 | # Removing `enabled` argument. 4 | # -------------------------------------------------------------------------------------------------- 5 | 6 | moved { 7 | from = aws_default_vpc.default[0] 8 | to = aws_default_vpc.default 9 | } 10 | 11 | moved { 12 | from = aws_default_route_table.default[0] 13 | to = aws_default_route_table.default 14 | } 15 | 16 | moved { 17 | from = aws_default_network_acl.default[0] 18 | to = aws_default_network_acl.default 19 | } 20 | 21 | moved { 22 | from = aws_default_security_group.default[0] 23 | to = aws_default_security_group.default 24 | } 25 | -------------------------------------------------------------------------------- /modules/vpc-baseline/outputs.tf: -------------------------------------------------------------------------------- 1 | output "default_vpc" { 2 | description = "The default VPC." 3 | value = aws_default_vpc.default 4 | } 5 | 6 | output "default_security_group" { 7 | description = "The default security group." 8 | value = aws_default_security_group.default 9 | } 10 | 11 | output "default_network_acl" { 12 | description = "The default network ACL." 13 | value = aws_default_network_acl.default 14 | } 15 | 16 | output "default_route_table" { 17 | description = "The default route table." 18 | value = aws_default_route_table.default 19 | } 20 | 21 | output "vpc_flow_logs_group" { 22 | description = "The CloudWatch Logs log group which stores VPC Flow Logs." 23 | value = local.flow_logs_to_cw_logs ? aws_cloudwatch_log_group.default_vpc_flow_logs[0] : null 24 | } 25 | -------------------------------------------------------------------------------- /modules/vpc-baseline/variables.tf: -------------------------------------------------------------------------------- 1 | variable "enable_flow_logs" { 2 | description = "The boolean flag whether to enable VPC Flow Logs in the default VPC" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "flow_logs_destination_type" { 8 | description = "The type of the logging destination. Valid values: cloud-watch-logs, s3" 9 | type = string 10 | default = "cloud-watch-logs" 11 | } 12 | 13 | # -------------------------------------------------------------------------------------------------- 14 | # Variables for CloudWatch Logs logging. 15 | # -------------------------------------------------------------------------------------------------- 16 | 17 | variable "flow_logs_log_group_name" { 18 | description = "The name of CloudWatch Logs group to which VPC Flow Logs are delivered if vpc_log_destination_type is cloud-watch-logs." 19 | type = string 20 | default = "" 21 | } 22 | 23 | variable "flow_logs_iam_role_arn" { 24 | description = "The ARN of the IAM Role which will be used by VPC Flow Logs if vpc_log_destination_type is cloud-watch-logs." 25 | type = string 26 | default = "" 27 | } 28 | 29 | variable "flow_logs_retention_in_days" { 30 | description = "Number of days to retain logs if vpc_log_destination_type is cloud-watch-logs. CIS recommends 365 days. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. Set to 0 to keep logs indefinitely." 31 | type = number 32 | default = 365 33 | } 34 | 35 | # -------------------------------------------------------------------------------------------------- 36 | # Variables for S3 logging. 37 | # -------------------------------------------------------------------------------------------------- 38 | 39 | variable "flow_logs_s3_arn" { 40 | description = "The ARN of the S3 bucket to which VPC Flow Logs are delivered if vpc_log_destination_type is s3." 41 | type = string 42 | default = "" 43 | } 44 | 45 | variable "flow_logs_s3_key_prefix" { 46 | description = "The prefix used when VPC Flow Logs delivers logs to the S3 bucket." 47 | type = string 48 | default = "flow-logs" 49 | } 50 | 51 | variable "tags" { 52 | description = "Specifies object tags key and value. This applies to all resources created by this module." 53 | type = map(string) 54 | default = { 55 | "Terraform" = "true" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /modules/vpc-baseline/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /securityhub_baselines.tf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------------------------- 2 | # SecurityHub Baseline 3 | # -------------------------------------------------------------------------------------------------- 4 | 5 | locals { 6 | securityhub_master_account_id = var.master_account_id 7 | securityhub_member_accounts = var.member_accounts 8 | } 9 | 10 | module "securityhub_baseline_ap-northeast-1" { 11 | count = contains(var.target_regions, "ap-northeast-1") && var.securityhub_enabled ? 1 : 0 12 | source = "./modules/securityhub-baseline" 13 | 14 | providers = { 15 | aws = aws.ap-northeast-1 16 | } 17 | 18 | aggregate_findings = var.region == "ap-northeast-1" 19 | enable_cis_standard = var.securityhub_enable_cis_standard 20 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 21 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 22 | master_account_id = local.securityhub_master_account_id 23 | member_accounts = local.securityhub_member_accounts 24 | } 25 | 26 | module "securityhub_baseline_ap-northeast-2" { 27 | count = contains(var.target_regions, "ap-northeast-2") && var.securityhub_enabled ? 1 : 0 28 | source = "./modules/securityhub-baseline" 29 | 30 | providers = { 31 | aws = aws.ap-northeast-2 32 | } 33 | 34 | aggregate_findings = var.region == "ap-northeast-2" 35 | enable_cis_standard = var.securityhub_enable_cis_standard 36 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 37 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 38 | enable_product_arns = var.securityhub_enable_product_arns 39 | master_account_id = local.securityhub_master_account_id 40 | member_accounts = local.securityhub_member_accounts 41 | } 42 | 43 | module "securityhub_baseline_ap-northeast-3" { 44 | count = contains(var.target_regions, "ap-northeast-3") && var.securityhub_enabled ? 1 : 0 45 | source = "./modules/securityhub-baseline" 46 | 47 | providers = { 48 | aws = aws.ap-northeast-3 49 | } 50 | 51 | aggregate_findings = var.region == "ap-northeast-3" 52 | enable_cis_standard = var.securityhub_enable_cis_standard 53 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 54 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 55 | enable_product_arns = var.securityhub_enable_product_arns 56 | master_account_id = local.securityhub_master_account_id 57 | member_accounts = local.securityhub_member_accounts 58 | } 59 | 60 | module "securityhub_baseline_ap-south-1" { 61 | count = contains(var.target_regions, "ap-south-1") && var.securityhub_enabled ? 1 : 0 62 | source = "./modules/securityhub-baseline" 63 | 64 | providers = { 65 | aws = aws.ap-south-1 66 | } 67 | 68 | aggregate_findings = var.region == "ap-south-1" 69 | enable_cis_standard = var.securityhub_enable_cis_standard 70 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 71 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 72 | enable_product_arns = var.securityhub_enable_product_arns 73 | master_account_id = local.securityhub_master_account_id 74 | member_accounts = local.securityhub_member_accounts 75 | } 76 | 77 | module "securityhub_baseline_ap-southeast-1" { 78 | count = contains(var.target_regions, "ap-southeast-1") && var.securityhub_enabled ? 1 : 0 79 | source = "./modules/securityhub-baseline" 80 | 81 | providers = { 82 | aws = aws.ap-southeast-1 83 | } 84 | 85 | aggregate_findings = var.region == "ap-southeast-1" 86 | enable_cis_standard = var.securityhub_enable_cis_standard 87 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 88 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 89 | enable_product_arns = var.securityhub_enable_product_arns 90 | master_account_id = local.securityhub_master_account_id 91 | member_accounts = local.securityhub_member_accounts 92 | } 93 | 94 | module "securityhub_baseline_ap-southeast-2" { 95 | count = contains(var.target_regions, "ap-southeast-2") && var.securityhub_enabled ? 1 : 0 96 | source = "./modules/securityhub-baseline" 97 | 98 | providers = { 99 | aws = aws.ap-southeast-2 100 | } 101 | 102 | aggregate_findings = var.region == "ap-southeast-2" 103 | enable_cis_standard = var.securityhub_enable_cis_standard 104 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 105 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 106 | enable_product_arns = var.securityhub_enable_product_arns 107 | master_account_id = local.securityhub_master_account_id 108 | member_accounts = local.securityhub_member_accounts 109 | } 110 | 111 | module "securityhub_baseline_ca-central-1" { 112 | count = contains(var.target_regions, "ca-central-1") && var.securityhub_enabled ? 1 : 0 113 | source = "./modules/securityhub-baseline" 114 | 115 | providers = { 116 | aws = aws.ca-central-1 117 | } 118 | 119 | aggregate_findings = var.region == "ca-central-1" 120 | enable_cis_standard = var.securityhub_enable_cis_standard 121 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 122 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 123 | enable_product_arns = var.securityhub_enable_product_arns 124 | master_account_id = local.securityhub_master_account_id 125 | member_accounts = local.securityhub_member_accounts 126 | } 127 | 128 | module "securityhub_baseline_eu-central-1" { 129 | count = contains(var.target_regions, "eu-central-1") && var.securityhub_enabled ? 1 : 0 130 | source = "./modules/securityhub-baseline" 131 | 132 | providers = { 133 | aws = aws.eu-central-1 134 | } 135 | 136 | aggregate_findings = var.region == "eu-central-1" 137 | enable_cis_standard = var.securityhub_enable_cis_standard 138 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 139 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 140 | enable_product_arns = var.securityhub_enable_product_arns 141 | master_account_id = local.securityhub_master_account_id 142 | member_accounts = local.securityhub_member_accounts 143 | } 144 | 145 | module "securityhub_baseline_eu-north-1" { 146 | count = contains(var.target_regions, "eu-north-1") && var.securityhub_enabled ? 1 : 0 147 | source = "./modules/securityhub-baseline" 148 | 149 | providers = { 150 | aws = aws.eu-north-1 151 | } 152 | 153 | aggregate_findings = var.region == "eu-north-1" 154 | enable_cis_standard = var.securityhub_enable_cis_standard 155 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 156 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 157 | enable_product_arns = var.securityhub_enable_product_arns 158 | master_account_id = local.securityhub_master_account_id 159 | member_accounts = local.securityhub_member_accounts 160 | } 161 | 162 | module "securityhub_baseline_eu-west-1" { 163 | count = contains(var.target_regions, "eu-west-1") && var.securityhub_enabled ? 1 : 0 164 | source = "./modules/securityhub-baseline" 165 | 166 | providers = { 167 | aws = aws.eu-west-1 168 | } 169 | 170 | aggregate_findings = var.region == "eu-west-1" 171 | enable_cis_standard = var.securityhub_enable_cis_standard 172 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 173 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 174 | enable_product_arns = var.securityhub_enable_product_arns 175 | master_account_id = local.securityhub_master_account_id 176 | member_accounts = local.securityhub_member_accounts 177 | } 178 | 179 | module "securityhub_baseline_eu-west-2" { 180 | count = contains(var.target_regions, "eu-west-2") && var.securityhub_enabled ? 1 : 0 181 | source = "./modules/securityhub-baseline" 182 | 183 | providers = { 184 | aws = aws.eu-west-2 185 | } 186 | 187 | aggregate_findings = var.region == "eu-west-2" 188 | enable_cis_standard = var.securityhub_enable_cis_standard 189 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 190 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 191 | enable_product_arns = var.securityhub_enable_product_arns 192 | master_account_id = local.securityhub_master_account_id 193 | member_accounts = local.securityhub_member_accounts 194 | } 195 | 196 | module "securityhub_baseline_eu-west-3" { 197 | count = contains(var.target_regions, "eu-west-3") && var.securityhub_enabled ? 1 : 0 198 | source = "./modules/securityhub-baseline" 199 | 200 | providers = { 201 | aws = aws.eu-west-3 202 | } 203 | 204 | aggregate_findings = var.region == "eu-west-3" 205 | enable_cis_standard = var.securityhub_enable_cis_standard 206 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 207 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 208 | enable_product_arns = var.securityhub_enable_product_arns 209 | master_account_id = local.securityhub_master_account_id 210 | member_accounts = local.securityhub_member_accounts 211 | } 212 | 213 | module "securityhub_baseline_sa-east-1" { 214 | count = contains(var.target_regions, "sa-east-1") && var.securityhub_enabled ? 1 : 0 215 | source = "./modules/securityhub-baseline" 216 | 217 | providers = { 218 | aws = aws.sa-east-1 219 | } 220 | 221 | aggregate_findings = var.region == "sa-east-1" 222 | enable_cis_standard = var.securityhub_enable_cis_standard 223 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 224 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 225 | enable_product_arns = var.securityhub_enable_product_arns 226 | master_account_id = local.securityhub_master_account_id 227 | member_accounts = local.securityhub_member_accounts 228 | } 229 | 230 | module "securityhub_baseline_us-east-1" { 231 | count = contains(var.target_regions, "us-east-1") && var.securityhub_enabled ? 1 : 0 232 | source = "./modules/securityhub-baseline" 233 | 234 | providers = { 235 | aws = aws.us-east-1 236 | } 237 | 238 | aggregate_findings = var.region == "us-east-1" 239 | enable_cis_standard = var.securityhub_enable_cis_standard 240 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 241 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 242 | enable_product_arns = var.securityhub_enable_product_arns 243 | master_account_id = local.securityhub_master_account_id 244 | member_accounts = local.securityhub_member_accounts 245 | } 246 | 247 | module "securityhub_baseline_us-east-2" { 248 | count = contains(var.target_regions, "us-east-2") && var.securityhub_enabled ? 1 : 0 249 | source = "./modules/securityhub-baseline" 250 | 251 | providers = { 252 | aws = aws.us-east-2 253 | } 254 | 255 | aggregate_findings = var.region == "us-east-2" 256 | enable_cis_standard = var.securityhub_enable_cis_standard 257 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 258 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 259 | enable_product_arns = var.securityhub_enable_product_arns 260 | master_account_id = local.securityhub_master_account_id 261 | member_accounts = local.securityhub_member_accounts 262 | } 263 | 264 | module "securityhub_baseline_us-west-1" { 265 | count = contains(var.target_regions, "us-west-1") && var.securityhub_enabled ? 1 : 0 266 | source = "./modules/securityhub-baseline" 267 | 268 | providers = { 269 | aws = aws.us-west-1 270 | } 271 | 272 | aggregate_findings = var.region == "us-west-1" 273 | enable_cis_standard = var.securityhub_enable_cis_standard 274 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 275 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 276 | enable_product_arns = var.securityhub_enable_product_arns 277 | master_account_id = local.securityhub_master_account_id 278 | member_accounts = local.securityhub_member_accounts 279 | } 280 | 281 | module "securityhub_baseline_us-west-2" { 282 | count = contains(var.target_regions, "us-west-2") && var.securityhub_enabled ? 1 : 0 283 | source = "./modules/securityhub-baseline" 284 | 285 | providers = { 286 | aws = aws.us-west-2 287 | } 288 | 289 | aggregate_findings = var.region == "us-west-2" 290 | enable_cis_standard = var.securityhub_enable_cis_standard 291 | enable_pci_dss_standard = var.securityhub_enable_pci_dss_standard 292 | enable_aws_foundational_standard = var.securityhub_enable_aws_foundational_standard 293 | enable_product_arns = var.securityhub_enable_product_arns 294 | master_account_id = local.securityhub_master_account_id 295 | member_accounts = local.securityhub_member_accounts 296 | } 297 | -------------------------------------------------------------------------------- /vpc_baselines.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | flow_logs_to_cw_logs = var.vpc_enable && var.vpc_enable_flow_logs && (var.vpc_flow_logs_destination_type == "cloud-watch-logs") 3 | flow_logs_to_s3 = var.vpc_enable && var.vpc_enable_flow_logs && (var.vpc_flow_logs_destination_type == "s3") 4 | flow_logs_s3_arn = local.flow_logs_to_s3 ? ( 5 | var.vpc_flow_logs_s3_arn != "" ? var.vpc_flow_logs_s3_arn : local.audit_log_bucket_arn 6 | ) : "" 7 | } 8 | 9 | # -------------------------------------------------------------------------------------------------- 10 | # Create an IAM Role for publishing VPC Flow Logs into CloudWatch Logs group. 11 | # Reference: https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/flow-logs.html#flow-logs-iam 12 | # -------------------------------------------------------------------------------------------------- 13 | 14 | data "aws_iam_policy_document" "flow_logs_publisher_assume_role_policy" { 15 | count = local.flow_logs_to_cw_logs ? 1 : 0 16 | 17 | statement { 18 | principals { 19 | type = "Service" 20 | identifiers = ["vpc-flow-logs.amazonaws.com"] 21 | } 22 | actions = ["sts:AssumeRole"] 23 | } 24 | } 25 | 26 | resource "aws_iam_role" "flow_logs_publisher" { 27 | count = local.flow_logs_to_cw_logs ? 1 : 0 28 | 29 | name = var.vpc_iam_role_name 30 | assume_role_policy = data.aws_iam_policy_document.flow_logs_publisher_assume_role_policy[0].json 31 | 32 | permissions_boundary = var.permissions_boundary_arn 33 | 34 | tags = var.tags 35 | } 36 | 37 | data "aws_iam_policy_document" "flow_logs_publish_policy" { 38 | count = local.flow_logs_to_cw_logs ? 1 : 0 39 | 40 | statement { 41 | actions = [ 42 | "logs:CreateLogGroup", 43 | "logs:CreateLogStream", 44 | "logs:PutLogEvents", 45 | "logs:DescribeLogGroups", 46 | "logs:DescribeLogStreams" 47 | ] 48 | resources = ["*"] 49 | } 50 | } 51 | 52 | resource "aws_iam_role_policy" "flow_logs_publish_policy" { 53 | count = local.flow_logs_to_cw_logs ? 1 : 0 54 | 55 | name = var.vpc_iam_role_policy_name 56 | role = aws_iam_role.flow_logs_publisher[0].id 57 | 58 | policy = data.aws_iam_policy_document.flow_logs_publish_policy[0].json 59 | } 60 | 61 | # -------------------------------------------------------------------------------------------------- 62 | # VPC Baseline 63 | # Needs to be set up in each region. 64 | # -------------------------------------------------------------------------------------------------- 65 | 66 | module "vpc_baseline_ap-northeast-1" { 67 | count = var.vpc_enable && contains(var.target_regions, "ap-northeast-1") ? 1 : 0 68 | source = "./modules/vpc-baseline" 69 | 70 | providers = { 71 | aws = aws.ap-northeast-1 72 | } 73 | 74 | enable_flow_logs = var.vpc_enable_flow_logs 75 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 76 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 77 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 78 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 79 | flow_logs_s3_arn = local.flow_logs_s3_arn 80 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 81 | 82 | tags = var.tags 83 | } 84 | 85 | module "vpc_baseline_ap-northeast-2" { 86 | count = var.vpc_enable && contains(var.target_regions, "ap-northeast-2") ? 1 : 0 87 | source = "./modules/vpc-baseline" 88 | 89 | providers = { 90 | aws = aws.ap-northeast-2 91 | } 92 | 93 | enable_flow_logs = var.vpc_enable_flow_logs 94 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 95 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 96 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 97 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 98 | flow_logs_s3_arn = local.flow_logs_s3_arn 99 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 100 | 101 | tags = var.tags 102 | } 103 | 104 | module "vpc_baseline_ap-northeast-3" { 105 | count = var.vpc_enable && contains(var.target_regions, "ap-northeast-3") ? 1 : 0 106 | source = "./modules/vpc-baseline" 107 | 108 | providers = { 109 | aws = aws.ap-northeast-3 110 | } 111 | 112 | enable_flow_logs = var.vpc_enable_flow_logs 113 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 114 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 115 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 116 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 117 | flow_logs_s3_arn = local.flow_logs_s3_arn 118 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 119 | 120 | tags = var.tags 121 | } 122 | 123 | module "vpc_baseline_ap-south-1" { 124 | count = var.vpc_enable && contains(var.target_regions, "ap-south-1") ? 1 : 0 125 | source = "./modules/vpc-baseline" 126 | 127 | providers = { 128 | aws = aws.ap-south-1 129 | } 130 | 131 | enable_flow_logs = var.vpc_enable_flow_logs 132 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 133 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 134 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 135 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 136 | flow_logs_s3_arn = local.flow_logs_s3_arn 137 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 138 | 139 | tags = var.tags 140 | } 141 | 142 | module "vpc_baseline_ap-southeast-1" { 143 | count = var.vpc_enable && contains(var.target_regions, "ap-southeast-1") ? 1 : 0 144 | source = "./modules/vpc-baseline" 145 | 146 | providers = { 147 | aws = aws.ap-southeast-1 148 | } 149 | 150 | enable_flow_logs = var.vpc_enable_flow_logs 151 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 152 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 153 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 154 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 155 | flow_logs_s3_arn = local.flow_logs_s3_arn 156 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 157 | 158 | tags = var.tags 159 | } 160 | 161 | module "vpc_baseline_ap-southeast-2" { 162 | count = var.vpc_enable && contains(var.target_regions, "ap-southeast-2") ? 1 : 0 163 | source = "./modules/vpc-baseline" 164 | 165 | providers = { 166 | aws = aws.ap-southeast-2 167 | } 168 | 169 | enable_flow_logs = var.vpc_enable_flow_logs 170 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 171 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 172 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 173 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 174 | flow_logs_s3_arn = local.flow_logs_s3_arn 175 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 176 | 177 | tags = var.tags 178 | } 179 | 180 | module "vpc_baseline_ca-central-1" { 181 | count = var.vpc_enable && contains(var.target_regions, "ca-central-1") ? 1 : 0 182 | source = "./modules/vpc-baseline" 183 | 184 | providers = { 185 | aws = aws.ca-central-1 186 | } 187 | 188 | enable_flow_logs = var.vpc_enable_flow_logs 189 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 190 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 191 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 192 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 193 | flow_logs_s3_arn = local.flow_logs_s3_arn 194 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 195 | 196 | tags = var.tags 197 | } 198 | 199 | module "vpc_baseline_eu-central-1" { 200 | count = var.vpc_enable && contains(var.target_regions, "eu-central-1") ? 1 : 0 201 | source = "./modules/vpc-baseline" 202 | 203 | providers = { 204 | aws = aws.eu-central-1 205 | } 206 | 207 | enable_flow_logs = var.vpc_enable_flow_logs 208 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 209 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 210 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 211 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 212 | flow_logs_s3_arn = local.flow_logs_s3_arn 213 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 214 | 215 | tags = var.tags 216 | } 217 | 218 | module "vpc_baseline_eu-north-1" { 219 | count = var.vpc_enable && contains(var.target_regions, "eu-north-1") ? 1 : 0 220 | source = "./modules/vpc-baseline" 221 | 222 | providers = { 223 | aws = aws.eu-north-1 224 | } 225 | 226 | enable_flow_logs = var.vpc_enable_flow_logs 227 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 228 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 229 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 230 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 231 | flow_logs_s3_arn = local.flow_logs_s3_arn 232 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 233 | 234 | tags = var.tags 235 | } 236 | 237 | module "vpc_baseline_eu-west-1" { 238 | count = var.vpc_enable && contains(var.target_regions, "eu-west-1") ? 1 : 0 239 | source = "./modules/vpc-baseline" 240 | 241 | providers = { 242 | aws = aws.eu-west-1 243 | } 244 | 245 | enable_flow_logs = var.vpc_enable_flow_logs 246 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 247 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 248 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 249 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 250 | flow_logs_s3_arn = local.flow_logs_s3_arn 251 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 252 | 253 | tags = var.tags 254 | } 255 | 256 | module "vpc_baseline_eu-west-2" { 257 | count = var.vpc_enable && contains(var.target_regions, "eu-west-2") ? 1 : 0 258 | source = "./modules/vpc-baseline" 259 | 260 | providers = { 261 | aws = aws.eu-west-2 262 | } 263 | 264 | enable_flow_logs = var.vpc_enable_flow_logs 265 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 266 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 267 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 268 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 269 | flow_logs_s3_arn = local.flow_logs_s3_arn 270 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 271 | 272 | tags = var.tags 273 | } 274 | 275 | module "vpc_baseline_eu-west-3" { 276 | count = var.vpc_enable && contains(var.target_regions, "eu-west-3") ? 1 : 0 277 | source = "./modules/vpc-baseline" 278 | 279 | providers = { 280 | aws = aws.eu-west-3 281 | } 282 | 283 | enable_flow_logs = var.vpc_enable_flow_logs 284 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 285 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 286 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 287 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 288 | flow_logs_s3_arn = local.flow_logs_s3_arn 289 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 290 | 291 | tags = var.tags 292 | } 293 | 294 | module "vpc_baseline_sa-east-1" { 295 | count = var.vpc_enable && contains(var.target_regions, "sa-east-1") ? 1 : 0 296 | source = "./modules/vpc-baseline" 297 | 298 | providers = { 299 | aws = aws.sa-east-1 300 | } 301 | 302 | enable_flow_logs = var.vpc_enable_flow_logs 303 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 304 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 305 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 306 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 307 | flow_logs_s3_arn = local.flow_logs_s3_arn 308 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 309 | 310 | tags = var.tags 311 | } 312 | 313 | module "vpc_baseline_us-east-1" { 314 | count = var.vpc_enable && contains(var.target_regions, "us-east-1") ? 1 : 0 315 | source = "./modules/vpc-baseline" 316 | 317 | providers = { 318 | aws = aws.us-east-1 319 | } 320 | 321 | enable_flow_logs = var.vpc_enable_flow_logs 322 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 323 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 324 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 325 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 326 | flow_logs_s3_arn = local.flow_logs_s3_arn 327 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 328 | 329 | tags = var.tags 330 | } 331 | 332 | module "vpc_baseline_us-east-2" { 333 | count = var.vpc_enable && contains(var.target_regions, "us-east-2") ? 1 : 0 334 | source = "./modules/vpc-baseline" 335 | 336 | providers = { 337 | aws = aws.us-east-2 338 | } 339 | 340 | enable_flow_logs = var.vpc_enable_flow_logs 341 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 342 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 343 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 344 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 345 | flow_logs_s3_arn = local.flow_logs_s3_arn 346 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 347 | 348 | tags = var.tags 349 | } 350 | 351 | module "vpc_baseline_us-west-1" { 352 | count = var.vpc_enable && contains(var.target_regions, "us-west-1") ? 1 : 0 353 | source = "./modules/vpc-baseline" 354 | 355 | providers = { 356 | aws = aws.us-west-1 357 | } 358 | 359 | enable_flow_logs = var.vpc_enable_flow_logs 360 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 361 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 362 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 363 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 364 | flow_logs_s3_arn = local.flow_logs_s3_arn 365 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 366 | 367 | tags = var.tags 368 | } 369 | 370 | module "vpc_baseline_us-west-2" { 371 | count = var.vpc_enable && contains(var.target_regions, "us-west-2") ? 1 : 0 372 | source = "./modules/vpc-baseline" 373 | 374 | providers = { 375 | aws = aws.us-west-2 376 | } 377 | 378 | enable_flow_logs = var.vpc_enable_flow_logs 379 | flow_logs_destination_type = var.vpc_flow_logs_destination_type 380 | flow_logs_log_group_name = var.vpc_flow_logs_log_group_name 381 | flow_logs_iam_role_arn = local.flow_logs_to_cw_logs ? aws_iam_role.flow_logs_publisher[0].arn : null 382 | flow_logs_retention_in_days = var.vpc_flow_logs_retention_in_days 383 | flow_logs_s3_arn = local.flow_logs_s3_arn 384 | flow_logs_s3_key_prefix = var.vpc_flow_logs_s3_key_prefix 385 | 386 | tags = var.tags 387 | } 388 | --------------------------------------------------------------------------------