├── .editorconfig ├── .github ├── CODEOWNERS ├── dependabot.yml ├── labeler.yaml ├── labels.yaml └── workflows │ ├── pull-request-labeler.yaml │ ├── sync-labels.yaml │ ├── terraform.integration.yaml │ ├── welcome.yaml │ └── yaml.integration.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .tflint.hcl ├── .yamllint.yaml ├── LICENSE ├── README.md ├── VERSION ├── examples ├── nat-gateway-private-secondary-ip-addresses │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── nat-gateway-private │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── nat-gateway-public │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── security-group-simple │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── security-group-with-ipv4-cidrs │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── vpc-full │ ├── main.tf │ ├── nacls.tf │ ├── nat-gateways.tf │ ├── outputs.tf │ ├── route-tables.tf │ ├── subnet-groups.tf │ └── versions.tf ├── vpc-ipv4-secondary-cidrs │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── vpc-ipv6-cidrs │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── vpc-simple │ ├── main.tf │ ├── outputs.tf │ └── versions.tf └── vpc-with-ipam │ ├── ipam.tf │ ├── main.tf │ ├── outputs.tf │ └── versions.tf └── modules ├── nacl ├── README.md ├── main.tf ├── migrations.tf ├── outputs.tf ├── resource-group.tf ├── variables.tf └── versions.tf ├── nat-gateway ├── README.md ├── main.tf ├── migrations.tf ├── outputs.tf ├── resource-group.tf ├── variables.tf └── versions.tf ├── route-table ├── README.md ├── main.tf ├── migrations.tf ├── outputs.tf ├── resource-group.tf ├── routes.tf ├── variables.tf └── versions.tf ├── security-group ├── README.md ├── main.tf ├── migrations.tf ├── outputs.tf ├── resource-group.tf ├── rules.tf ├── variables.tf └── versions.tf ├── subnet-group ├── README.md ├── integrations.tf ├── main.tf ├── migrations.tf ├── outputs.tf ├── ram-share.tf ├── resource-group.tf ├── variables.tf └── versions.tf └── vpc ├── README.md ├── defaults.tf ├── dhcp-options.tf ├── gateways.tf ├── main.tf ├── migrations.tf ├── outputs.tf ├── resource-group.tf ├── route53.tf ├── variables.tf └── versions.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | # Top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 150 12 | 13 | [*.{tf,tfvars}] 14 | indent_size = 2 15 | indent_style = space 16 | 17 | [*.md] 18 | max_line_length = 0 19 | 20 | [COMMIT_EDITMSG] 21 | max_line_length = 0 22 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @posquit0 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | 8 | - package-ecosystem: terraform 9 | directories: 10 | - /modules/* 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /.github/labeler.yaml: -------------------------------------------------------------------------------- 1 | # Modules 2 | ":floppy_disk: nacl": 3 | - changed-files: 4 | - any-glob-to-any-file: 5 | - modules/nacl/**/* 6 | 7 | ":floppy_disk: nat-gateway": 8 | - changed-files: 9 | - any-glob-to-any-file: 10 | - modules/nat-gateway/**/* 11 | 12 | ":floppy_disk: route-table": 13 | - changed-files: 14 | - any-glob-to-any-file: 15 | - modules/route-table/**/* 16 | 17 | ":floppy_disk: security-group": 18 | - changed-files: 19 | - any-glob-to-any-file: 20 | - modules/security-group/**/* 21 | 22 | ":floppy_disk: subnet-group": 23 | - changed-files: 24 | - any-glob-to-any-file: 25 | - modules/subnet-group/**/* 26 | 27 | ":floppy_disk: vpc": 28 | - changed-files: 29 | - any-glob-to-any-file: 30 | - modules/vpc/**/* 31 | -------------------------------------------------------------------------------- /.github/labels.yaml: -------------------------------------------------------------------------------- 1 | # Warning 2 | - color: "ee0701" 3 | description: "Categorize bug reports." 4 | name: ":warning: bug" 5 | - color: "ee0701" 6 | description: "Categorize vulnerability reports." 7 | name: ":warning: vulnerability" 8 | 9 | # Highlight 10 | - color: "0e8a16" 11 | description: "Good for newcomers." 12 | name: ":fire: good first issue" 13 | - color: "0e8a16" 14 | description: "Extra attention is needed." 15 | name: ":fire: help wanted" 16 | 17 | # Cancel 18 | - color: "b60205" 19 | description: "This issue or pull request already exists." 20 | name: ":pray: duplicate" 21 | - color: "b60205" 22 | description: "This will not be worked on." 23 | name: ":pray: wontfix" 24 | 25 | # Size 26 | - color: "cfd3d7" 27 | description: "Extra Small size issue or PR." 28 | name: "size/XS" 29 | - color: "cfd3d7" 30 | description: "Small size issue or PR." 31 | name: "size/S" 32 | - color: "cfd3d7" 33 | description: "Medium size issue or PR." 34 | name: "size/M" 35 | - color: "cfd3d7" 36 | description: "Large size issue or PR." 37 | name: "size/L" 38 | - color: "cfd3d7" 39 | description: "Extra Large size issue or PR." 40 | name: "size/XL" 41 | 42 | # Modules 43 | - color: "fbca04" 44 | description: "This issue or pull request is related to nacl module." 45 | name: ":floppy_disk: nacl" 46 | - color: "fbca04" 47 | description: "This issue or pull request is related to nat-gateway module." 48 | name: ":floppy_disk: nat-gateway" 49 | - color: "fbca04" 50 | description: "This issue or pull request is related to route-table module." 51 | name: ":floppy_disk: route-table" 52 | - color: "fbca04" 53 | description: "This issue or pull request is related to security-group module." 54 | name: ":floppy_disk: security-group" 55 | - color: "fbca04" 56 | description: "This issue or pull request is related to subnet-group module." 57 | name: ":floppy_disk: subnet-group" 58 | - color: "fbca04" 59 | description: "This issue or pull request is related to vpc module." 60 | name: ":floppy_disk: vpc" 61 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-labeler.yaml: -------------------------------------------------------------------------------- 1 | name: Label Pull Requests 2 | 3 | on: 4 | - pull_request_target 5 | 6 | jobs: 7 | label-pr: 8 | runs-on: ubuntu-latest 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: write 13 | 14 | steps: 15 | - name: Add Labels for PR 16 | uses: actions/labeler@v5 17 | with: 18 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 19 | configuration-path: .github/labeler.yaml 20 | dot: true 21 | sync-labels: true 22 | 23 | - name: Add PR Size Labels for PR 24 | uses: codelytv/pr-size-labeler@v1 25 | with: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | xs_label: 'size/XS' 28 | xs_max_size: '20' 29 | s_label: 'size/S' 30 | s_max_size: '50' 31 | m_label: 'size/M' 32 | m_max_size: '150' 33 | l_label: 'size/L' 34 | l_max_size: '300' 35 | xl_label: 'size/XL' 36 | fail_if_xl: 'false' 37 | message_if_xl: > 38 | 'This PR has too many changes. 39 | Please make sure you are NOT addressing multiple issues with one PR.' 40 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yaml: -------------------------------------------------------------------------------- 1 | name: Sync labels 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/labels.yaml 9 | workflow_dispatch: {} 10 | 11 | jobs: 12 | sync-labels: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | - name: Sync labels 20 | uses: crazy-max/ghaction-github-labeler@v5 21 | with: 22 | github-token: ${{ secrets.GITHUB_TOKEN }} 23 | yaml-file: .github/labels.yaml 24 | skip-delete: false 25 | dry-run: false 26 | # exclude: | 27 | -------------------------------------------------------------------------------- /.github/workflows/terraform.integration.yaml: -------------------------------------------------------------------------------- 1 | name: Integration (Terraform) 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: {} 8 | 9 | concurrency: 10 | group: terraform-integration-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | changed: 15 | name: Filter Changed Files and Directories 16 | runs-on: ubuntu-latest 17 | 18 | outputs: 19 | changed: ${{ steps.set-outputs.outputs.changed }} 20 | modified: ${{ steps.set-outputs.outputs.modified }} 21 | changed_files: ${{ steps.set-outputs.outputs.changed_files }} 22 | modified_files: ${{ steps.set-outputs.outputs.modified_files }} 23 | changed_directories: ${{ steps.set-outputs.outputs.changed_directories }} 24 | modified_directories: ${{ steps.set-outputs.outputs.modified_directories }} 25 | 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 31 | 32 | - name: Get Changed Files 33 | id: changed-files 34 | uses: tj-actions/changed-files@v44 35 | with: 36 | files: | 37 | modules/** 38 | examples/** 39 | json: true 40 | 41 | - name: Get Changed Directories 42 | id: changed-directories 43 | uses: tj-actions/changed-files@v44 44 | with: 45 | files: | 46 | modules/** 47 | examples/** 48 | dir_names: "true" 49 | dir_names_max_depth: 2 50 | json: true 51 | 52 | - name: Set outputs 53 | id: set-outputs 54 | run: | 55 | echo "changed=${{ steps.changed-directories.outputs.any_changed }}" >> $GITHUB_OUTPUT 56 | echo "modified=${{ steps.changed-directories.outputs.any_modified }}" >> $GITHUB_OUTPUT 57 | 58 | echo "changed_files=${{ steps.changed-files.outputs.all_changed_files }}" >> $GITHUB_OUTPUT 59 | echo "modified_files=${{ steps.changed-files.outputs.all_modified_files }}" >> $GITHUB_OUTPUT 60 | 61 | echo "changed_directories=${{ steps.changed-directories.outputs.all_changed_files }}" >> $GITHUB_OUTPUT 62 | echo "modified_directories=${{ steps.changed-directories.outputs.all_modified_files }}" >> $GITHUB_OUTPUT 63 | 64 | 65 | terraform: 66 | name: Lint (terraform) 67 | needs: 68 | - changed 69 | if: ${{ needs.changed.outputs.modified == 'true' }} 70 | uses: tedilabs/.github/.github/workflows/terraform.terraform.yaml@main 71 | 72 | strategy: 73 | matrix: 74 | path: ${{ fromJson(needs.changed.outputs.modified_directories) }} 75 | 76 | with: 77 | terraform_target_dir: ${{ matrix.path }} 78 | terraform_version: latest 79 | terraform_host: app.terraform.io 80 | secrets: 81 | gh_token: ${{ secrets.GITHUB_TOKEN }} 82 | token: ${{ secrets.GITHUB_TOKEN }} 83 | terraform_token: ${{ secrets.TERRAFORM_TOKEN }} 84 | 85 | 86 | tflint: 87 | name: Lint (tflint) 88 | needs: 89 | - changed 90 | if: ${{ needs.changed.outputs.modified == 'true' }} 91 | uses: tedilabs/.github/.github/workflows/terraform.tflint.yaml@main 92 | 93 | strategy: 94 | matrix: 95 | path: ${{ fromJson(needs.changed.outputs.modified_directories) }} 96 | 97 | with: 98 | tflint_version: latest 99 | tflint_config_file: .tflint.hcl 100 | tflint_target_dir: ${{ matrix.path }} 101 | tflint_recursive_enabled: false 102 | tflint_terraform_init_enabled: true 103 | terraform_version: latest 104 | terraform_host: app.terraform.io 105 | secrets: 106 | gh_token: ${{ secrets.GITHUB_TOKEN }} 107 | token: ${{ secrets.GITHUB_TOKEN }} 108 | terraform_token: ${{ secrets.TERRAFORM_TOKEN }} 109 | -------------------------------------------------------------------------------- /.github/workflows/welcome.yaml: -------------------------------------------------------------------------------- 1 | name: Welcome for First Issue or Pull Request 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | issues: 8 | types: 9 | - opened 10 | 11 | jobs: 12 | welcome: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Welcome for First Issue or Pull Request 17 | uses: actions/first-interaction@v1 18 | with: 19 | repo-token: ${{ secrets.GITHUB_TOKEN }} 20 | issue-message: | 21 | ### :wave: Welcome! Looks like this is your first issue. 22 | 23 | Hey, thanks for your contribution! Please give us a bit of time to review it. 😄 24 | 25 | **Be sure to follow the issue template!** 26 | pr-message: | 27 | ### :wave: Welcome! Looks like this is your first pull request. 28 | 29 | Hey, thanks for your contribution! Please give us a bit of time to review it. 😄 30 | 31 | **Please check out our contributing guidelines.** 32 | -------------------------------------------------------------------------------- /.github/workflows/yaml.integration.yaml: -------------------------------------------------------------------------------- 1 | name: Integration (YAML) 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: {} 8 | 9 | concurrency: 10 | group: yaml-integration-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | changed: 15 | name: Filter Changed Files and Directories 16 | runs-on: ubuntu-latest 17 | 18 | outputs: 19 | changed: ${{ steps.set-outputs.outputs.changed }} 20 | modified: ${{ steps.set-outputs.outputs.modified }} 21 | changed_files: ${{ steps.set-outputs.outputs.changed_files }} 22 | modified_files: ${{ steps.set-outputs.outputs.modified_files }} 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | with: 28 | fetch-depth: 0 29 | 30 | - name: Get Changed Files 31 | id: changed-files 32 | uses: tj-actions/changed-files@v44 33 | with: 34 | files: | 35 | **/*.yaml 36 | **/*.yml 37 | json: true 38 | 39 | - name: Set outputs 40 | id: set-outputs 41 | run: | 42 | echo "changed=${{ steps.changed-files.outputs.any_changed }}" >> $GITHUB_OUTPUT 43 | echo "modified=${{ steps.changed-files.outputs.any_modified }}" >> $GITHUB_OUTPUT 44 | 45 | echo "changed_files=${{ steps.changed-files.outputs.all_changed_files }}" >> $GITHUB_OUTPUT 46 | echo "modified_files=${{ steps.changed-files.outputs.all_modified_files }}" >> $GITHUB_OUTPUT 47 | 48 | lint: 49 | name: Lint (yamllint) 50 | needs: 51 | - changed 52 | if: ${{ needs.changed.outputs.modified == 'true' }} 53 | uses: tedilabs/.github/.github/workflows/yaml.yamllint.yaml@main 54 | 55 | with: 56 | yamllint_version: latest 57 | yamllint_config_file: .yamllint.yaml 58 | yamllint_target_dir: ./ 59 | secrets: 60 | token: ${{ secrets.GITHUB_TOKEN }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | # General 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | 30 | ### Terraform ### 31 | # Lock file 32 | .terraform.lock.hcl 33 | 34 | # Local .terraform directories 35 | **/.terraform/* 36 | 37 | # .tfstate files 38 | *.tfstate 39 | *.tfstate.* 40 | 41 | # Crash log files 42 | crash.log 43 | 44 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 45 | # .tfvars files are managed as part of configuration and so should be included in 46 | # version control. 47 | # 48 | # example.tfvars 49 | 50 | # Ignore override files as they are usually used to override resources locally and so 51 | # are not checked in 52 | override.tf 53 | override.tf.json 54 | *_override.tf 55 | *_override.tf.json 56 | 57 | # Include override files you do wish to add to version control using negated pattern 58 | # !example_override.tf 59 | 60 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 61 | # example: *tfplan* 62 | 63 | 64 | ### Vim ### 65 | # Swap 66 | [._]*.s[a-v][a-z] 67 | !*.svg # comment out if you don't need vector files 68 | [._]*.sw[a-p] 69 | [._]s[a-rt-v][a-z] 70 | [._]ss[a-gi-z] 71 | [._]sw[a-p] 72 | 73 | # Session 74 | Session.vim 75 | Sessionx.vim 76 | 77 | # Temporary 78 | .netrwhist 79 | *~ 80 | # Auto-generated tag files 81 | tags 82 | # Persistent undo 83 | [._]*.un~ 84 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_install_hook_types: 2 | - pre-commit 3 | - commit-msg 4 | 5 | repos: 6 | - repo: https://github.com/antonbabenko/pre-commit-terraform 7 | rev: v1.97.4 8 | hooks: 9 | - id: terraform_fmt 10 | name: (terraform) Format .tf files with `terraform fmt` 11 | args: 12 | - --args=-diff 13 | - id: terraform_validate 14 | name: (terraform) Check with `terraform validate` 15 | args: 16 | - --hook-config=--retry-once-with-cleanup=true 17 | - --tf-init-args=-upgrade 18 | - id: terraform_tflint 19 | name: (terraform) Check with `tflint` 20 | args: 21 | - --args=--config=__GIT_WORKING_DIR__/.tflint.hcl 22 | files: ^modules/ 23 | - id: terraform_docs 24 | name: (terraform) Generate docs with `terraform-docs` 25 | args: ["--args=--sort-by required"] 26 | 27 | - repo: https://github.com/adrienverge/yamllint 28 | rev: v1.36.2 29 | hooks: 30 | - id: yamllint 31 | name: (yaml) Check with `yamllint` 32 | 33 | - repo: https://github.com/compilerla/conventional-pre-commit 34 | rev: v4.0.0 35 | hooks: 36 | - id: conventional-pre-commit 37 | name: (commit-message) Check conventional commit 38 | stages: [commit-msg] 39 | args: [] 40 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | plugin_dir = "~/.tflint.d/plugins" 3 | 4 | format = "compact" 5 | call_module_type = "local" 6 | force = false 7 | disabled_by_default = false 8 | 9 | ignore_module = {} 10 | } 11 | 12 | 13 | ################################################### 14 | # Rule Sets - Terraform 15 | ################################################### 16 | 17 | plugin "terraform" { 18 | enabled = true 19 | preset = "recommended" 20 | } 21 | 22 | rule "terraform_comment_syntax" { 23 | enabled = true 24 | } 25 | 26 | rule "terraform_documented_variables" { 27 | enabled = true 28 | } 29 | 30 | rule "terraform_documented_outputs" { 31 | enabled = true 32 | } 33 | 34 | rule "terraform_naming_convention" { 35 | enabled = true 36 | format = "snake_case" 37 | 38 | custom_formats = { 39 | extended_snake_case = { 40 | description = "Extended snake_case Format which allows double underscore like `a__b`." 41 | regex = "^[a-z][a-z0-9]+([_]{1,2}[a-z0-9]+)*$" 42 | } 43 | } 44 | 45 | module { 46 | format = "extended_snake_case" 47 | } 48 | 49 | resource { 50 | format = "extended_snake_case" 51 | } 52 | 53 | data { 54 | format = "extended_snake_case" 55 | } 56 | } 57 | 58 | rule "terraform_unused_declarations" { 59 | enabled = false 60 | } 61 | 62 | rule "terraform_unused_required_providers" { 63 | enabled = true 64 | } 65 | 66 | 67 | ################################################### 68 | # Rule Sets - AWS 69 | ################################################### 70 | 71 | plugin "aws" { 72 | source = "github.com/terraform-linters/tflint-ruleset-aws" 73 | version = "0.38.0" 74 | 75 | enabled = true 76 | deep_check = false 77 | } 78 | -------------------------------------------------------------------------------- /.yamllint.yaml: -------------------------------------------------------------------------------- 1 | yaml-files: 2 | - '*.yaml' 3 | - '*.yml' 4 | 5 | rules: 6 | braces: 7 | min-spaces-inside: 0 8 | max-spaces-inside: 1 9 | min-spaces-inside-empty: 0 10 | max-spaces-inside-empty: 0 11 | brackets: 12 | min-spaces-inside: 0 13 | max-spaces-inside: 1 14 | min-spaces-inside-empty: 0 15 | max-spaces-inside-empty: 0 16 | colons: 17 | max-spaces-before: 0 18 | max-spaces-after: 1 19 | commas: 20 | max-spaces-before: 0 21 | comments: 22 | level: warning 23 | require-starting-space: true 24 | min-spaces-from-content: 1 25 | comments-indentation: disable 26 | document-end: disable 27 | document-start: disable 28 | empty-lines: 29 | level: warning 30 | max: 2 31 | max-start: 0 32 | max-end: 1 33 | empty-values: 34 | forbid-in-block-mappings: true 35 | forbid-in-flow-mappings: true 36 | hyphens: 37 | max-spaces-after: 1 38 | indentation: 39 | spaces: consistent 40 | indent-sequences: false 41 | key-duplicates: enable 42 | key-ordering: disable 43 | line-length: disable 44 | new-line-at-end-of-file: enable 45 | # Use UNIX new line characters `\n` instead of DOS new line characters `\r\n` 46 | new-lines: 47 | type: unix 48 | octal-values: disable 49 | quoted-strings: 50 | quote-type: any 51 | required: false 52 | trailing-spaces: enable 53 | truthy: disable 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-aws-network 2 | 3 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/tedilabs/terraform-aws-network?color=blue&sort=semver&style=flat-square) 4 | ![GitHub](https://img.shields.io/github/license/tedilabs/terraform-aws-network?color=blue&style=flat-square) 5 | [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square)](https://github.com/pre-commit/pre-commit) 6 | 7 | Terraform module which creates network related resources on AWS. 8 | 9 | - [nacl](./modules/nacl) 10 | - [nat-gateway](./modules/nat-gateway) 11 | - [route-table](./modules/route-table) 12 | - [security-group](./modules/security-group) 13 | - [subnet-group](./modules/subnet-group) 14 | - [vpc](./modules/vpc) 15 | 16 | 17 | ## Target AWS Services 18 | 19 | Terraform Modules from [this package](https://github.com/tedilabs/terraform-aws-network) were written to manage the following AWS Services with Terraform. 20 | 21 | - **AWS VPC (Virtual Private Cloud)** 22 | - VPC 23 | - Default Network ACL 24 | - Default Security Group 25 | - Subnet 26 | - Route Table 27 | - NACL (Network ACL) 28 | - Security Group 29 | - Gateways 30 | - Internet Gateway 31 | - Egress-only Internet Gateway 32 | - NAT Gateway 33 | - VPN Gateway (Virtual Private Gateway) 34 | 35 | 36 | ## Examples 37 | 38 | ### VPC 39 | 40 | - [vpc-full](./examples/vpc-full) 41 | - [vpc-ipv4-secondary-cidrs](./examples/vpc-ipv4-secondary-cidrs) 42 | - [vpc-ipv6-cidrs](./examples/vpc-ipv6-cidrs) 43 | - [vpc-simple](./examples/vpc-simple) 44 | - [vpc-with-ipam](./examples/vpc-with-ipam) 45 | 46 | ### Security Group 47 | 48 | - [security-group-simple](./examples/security-group-simple) 49 | - [security-group-with-ipv4-cidrs](./examples/security-group-with-ipv4-cidrs) 50 | 51 | ### NAT Gateway 52 | 53 | - [nat-gateway-public](./examples/nat-gateway-public/) 54 | - [nat-gateway-private](./examples/nat-gateway-private/) 55 | - [nat-gateway-private-secondary-ip-addresses](./examples/nat-gateway-private-secondary-ip-addresses) 56 | 57 | 58 | ## Other Terraform Modules from Tedilabs 59 | 60 | Enjoying [terraform-aws-network](https://github.com/tedilabs/terraform-aws-network)? Check out some of our other modules: 61 | 62 | - [AWS Container](https://github.com/tedilabs/terraform-aws-container) - A package of Terraform Modules to manage AWS Container resources. 63 | - [AWS Domain](https://github.com/tedilabs/terraform-aws-domain) - A package of Terraform Modules to manage AWS Domain resources. 64 | - [AWS IPAM](https://github.com/tedilabs/terraform-aws-ipam) - A package of Terraform Modules to manage AWS IPAM related resources (IPAM, Elastic IP, Prefix List). 65 | - [AWS Load Balancer](https://github.com/tedilabs/terraform-aws-load-balancer) - A package of Terraform Modules to manage AWS Load Balancer resources. 66 | - [AWS Security](https://github.com/tedilabs/terraform-aws-security) - A package of Terraform Modules to manage AWS Security resources. 67 | - [AWS VPC Connectivity](https://github.com/tedilabs/terraform-aws-vpc-connectivity) - A package of Terraform Modules to manage AWS VPC Connectivity related resources (VPC Peering, VPC Private Link, VPC Lattice, Client VPN, Site-to-Site VPN, DX). 68 | 69 | Or check out [the full list](https://github.com/search?q=org%3Atedilabs+topic%3Aterraform-module&type=repositories) 70 | 71 | 72 | ## Self Promotion 73 | 74 | Like this project? Follow the repository on [GitHub](https://github.com/tedilabs/terraform-aws-network). And if you're feeling especially charitable, follow **[posquit0](https://github.com/posquit0)** on GitHub. 75 | 76 | 77 | ## License 78 | 79 | Provided under the terms of the [Apache License](LICENSE). 80 | 81 | Copyright © 2021-2023, [Byungjin Park](https://www.posquit0.com). 82 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.32.2 2 | -------------------------------------------------------------------------------- /examples/nat-gateway-private-secondary-ip-addresses/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | data "aws_vpc" "default" { 6 | default = true 7 | } 8 | 9 | data "aws_subnets" "default" { 10 | filter { 11 | name = "vpc-id" 12 | values = [data.aws_vpc.default.id] 13 | } 14 | } 15 | 16 | 17 | ################################################### 18 | # Public NAT Gateway 19 | ################################################### 20 | 21 | module "nat_gateway" { 22 | source = "../../modules/nat-gateway" 23 | # source = "tedilabs/network/aws//modules/nat-gateway" 24 | # version = "~> 0.2.0" 25 | 26 | name = "test-count" 27 | is_private = true 28 | subnet = data.aws_subnets.default.ids[0] 29 | 30 | 31 | ## Primary IP Address 32 | primary_ip_assignment = { 33 | # Automatically assign a public IP address to the NAT Gateway 34 | private_ip = null 35 | } 36 | 37 | 38 | ## Secondary IP Addresses 39 | secondary_ip_count = 7 40 | 41 | 42 | tags = { 43 | "project" = "terraform-aws-network-examples" 44 | } 45 | } 46 | 47 | module "nat_gateway_2" { 48 | source = "../../modules/nat-gateway" 49 | # source = "tedilabs/network/aws//modules/nat-gateway" 50 | # version = "~> 0.2.0" 51 | 52 | name = "test-assingments" 53 | is_private = true 54 | subnet = data.aws_subnets.default.ids[0] 55 | 56 | 57 | ## Primary IP Address 58 | primary_ip_assignment = { 59 | # Automatically assign a public IP address to the NAT Gateway 60 | private_ip = "172.31.51.100" 61 | } 62 | 63 | 64 | ## Secondary IP Addresses 65 | secondary_ip_assignments = [ 66 | { 67 | private_ip = "172.31.51.101" 68 | }, 69 | { 70 | private_ip = "172.31.51.102" 71 | }, 72 | { 73 | private_ip = "172.31.51.103" 74 | }, 75 | { 76 | private_ip = "172.31.51.104" 77 | }, 78 | ] 79 | 80 | 81 | tags = { 82 | "project" = "terraform-aws-network-examples" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /examples/nat-gateway-private-secondary-ip-addresses/outputs.tf: -------------------------------------------------------------------------------- 1 | output "nat_gateway" { 2 | description = "The NAT Gateways." 3 | value = { 4 | count = module.nat_gateway 5 | assignments = module.nat_gateway_2 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/nat-gateway-private-secondary-ip-addresses/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/nat-gateway-private/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | data "aws_vpc" "default" { 6 | default = true 7 | } 8 | 9 | data "aws_subnets" "default" { 10 | filter { 11 | name = "vpc-id" 12 | values = [data.aws_vpc.default.id] 13 | } 14 | } 15 | 16 | 17 | ################################################### 18 | # Public NAT Gateway 19 | ################################################### 20 | 21 | module "nat_gateway" { 22 | source = "../../modules/nat-gateway" 23 | # source = "tedilabs/network/aws//modules/nat-gateway" 24 | # version = "~> 0.2.0" 25 | 26 | name = "test/az1" 27 | is_private = true 28 | subnet = data.aws_subnets.default.ids[0] 29 | 30 | 31 | ## Primary IP Address 32 | primary_ip_assignment = { 33 | # Automatically assign a public IP address to the NAT Gateway 34 | private_ip = null 35 | } 36 | 37 | 38 | tags = { 39 | "project" = "terraform-aws-network-examples" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/nat-gateway-private/outputs.tf: -------------------------------------------------------------------------------- 1 | output "nat_gateway" { 2 | description = "The NAT Gateway." 3 | value = module.nat_gateway 4 | } 5 | -------------------------------------------------------------------------------- /examples/nat-gateway-private/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/nat-gateway-public/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | data "aws_vpc" "default" { 6 | default = true 7 | } 8 | 9 | data "aws_subnets" "default" { 10 | filter { 11 | name = "vpc-id" 12 | values = [data.aws_vpc.default.id] 13 | } 14 | } 15 | 16 | 17 | ################################################### 18 | # Elastic IP 19 | ################################################### 20 | 21 | module "elastic_ip" { 22 | source = "tedilabs/ipam/aws//modules/elastic-ip" 23 | version = "~> 0.3.0" 24 | 25 | name = "nat-gw-public" 26 | type = "AMAZON" 27 | 28 | tags = { 29 | "project" = "terraform-aws-network-examples" 30 | } 31 | } 32 | 33 | 34 | ################################################### 35 | # Public NAT Gateway 36 | ################################################### 37 | 38 | module "nat_gateway" { 39 | source = "../../modules/nat-gateway" 40 | # source = "tedilabs/network/aws//modules/nat-gateway" 41 | # version = "~> 0.2.0" 42 | 43 | name = "test/az1" 44 | is_private = false 45 | subnet = data.aws_subnets.default.ids[0] 46 | 47 | 48 | ## Primary IP Address 49 | primary_ip_assignment = { 50 | elastic_ip = module.elastic_ip.id 51 | } 52 | 53 | 54 | tags = { 55 | "project" = "terraform-aws-network-examples" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/nat-gateway-public/outputs.tf: -------------------------------------------------------------------------------- 1 | output "elastic_ip" { 2 | description = "The Elastic IP." 3 | value = module.elastic_ip 4 | } 5 | 6 | output "nat_gateway" { 7 | description = "The NAT Gateway." 8 | value = module.nat_gateway 9 | } 10 | -------------------------------------------------------------------------------- /examples/nat-gateway-public/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/security-group-simple/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | data "aws_vpc" "default" { 6 | default = true 7 | } 8 | 9 | 10 | ################################################### 11 | # Security Group 12 | ################################################### 13 | 14 | module "security_group" { 15 | source = "../../modules/security-group" 16 | # source = "tedilabs/ipam/aws//modules/security-group" 17 | # version = "~> 0.30.0" 18 | 19 | vpc_id = data.aws_vpc.default.id 20 | 21 | name = "hello-world" 22 | 23 | tags = { 24 | "project" = "terraform-aws-network-examples" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/security-group-simple/outputs.tf: -------------------------------------------------------------------------------- 1 | output "security_group" { 2 | description = "The Security Group." 3 | value = module.security_group 4 | } 5 | -------------------------------------------------------------------------------- /examples/security-group-simple/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/security-group-with-ipv4-cidrs/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | data "aws_vpc" "default" { 6 | default = true 7 | } 8 | 9 | 10 | ################################################### 11 | # Security Group 12 | ################################################### 13 | 14 | module "security_group" { 15 | source = "../../modules/security-group" 16 | # source = "tedilabs/ipam/aws//modules/security-group" 17 | # version = "~> 0.30.0" 18 | 19 | vpc_id = data.aws_vpc.default.id 20 | 21 | name = "hello-world-ipv4-cidrs" 22 | description = "Sample Security Group with IPv4 CIDRs." 23 | 24 | revoke_rules_on_delete = true 25 | 26 | ingress_rules = [ 27 | { 28 | id = "tcp/80" 29 | description = "Allow HTTP from VPC" 30 | from_port = 80 31 | to_port = 80 32 | protocol = "tcp" 33 | ipv4_cidrs = ["192.168.0.0/16", "10.0.0.0/8", "172.168.0.0/24"] 34 | }, 35 | ] 36 | egress_rules = [ 37 | { 38 | id = "all/all" 39 | description = "Allow all traffics to the internet" 40 | from_port = 0 41 | to_port = 0 42 | protocol = "-1" 43 | ipv4_cidrs = ["0.0.0.0/0"] 44 | }, 45 | ] 46 | 47 | tags = { 48 | "project" = "terraform-aws-network-examples" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/security-group-with-ipv4-cidrs/outputs.tf: -------------------------------------------------------------------------------- 1 | output "security_group" { 2 | description = "The Security Group." 3 | value = module.security_group 4 | } 5 | -------------------------------------------------------------------------------- /examples/security-group-with-ipv4-cidrs/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/vpc-full/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # VPC 8 | ################################################### 9 | 10 | module "vpc" { 11 | source = "../../modules/vpc" 12 | # source = "tedilabs/network/aws//modules/vpc" 13 | # version = "~> 0.2.0" 14 | 15 | name = "test" 16 | ipv4_cidrs = [ 17 | { 18 | cidr = "10.0.0.0/16" 19 | }, 20 | ] 21 | ipv6_cidrs = [ 22 | { 23 | type = "AMAZON" 24 | }, 25 | ] 26 | 27 | 28 | ## DHCP Option Set 29 | dhcp_options = { 30 | enabled = true 31 | domain_name = "example.com" 32 | domain_name_servers = ["4.4.4.4", "8.8.8.8"] 33 | } 34 | 35 | 36 | ## Gateways 37 | internet_gateway = { 38 | enabled = true 39 | } 40 | egress_only_internet_gateway = { 41 | enabled = true 42 | } 43 | vpn_gateway = { 44 | enabled = true 45 | } 46 | 47 | 48 | ## Defaults 49 | default_network_acl = { 50 | name = "test-default" 51 | ingress_rules = [ 52 | { 53 | priority = 200 54 | action = "ALLOW" 55 | protocol = "tcp" 56 | from_port = 443 57 | to_port = 443 58 | ipv4_cidr = "0.0.0.0/0" 59 | }, 60 | { 61 | priority = 201 62 | action = "ALLOW" 63 | protocol = "tcp" 64 | from_port = 443 65 | to_port = 443 66 | ipv6_cidr = "::/0" 67 | }, 68 | ] 69 | } 70 | default_security_group = { 71 | name = "test-default" 72 | ingress_rules = [ 73 | { 74 | protocol = "tcp" 75 | from_port = 80 76 | to_port = 80 77 | ipv4_cidrs = ["10.0.0.0/16"] 78 | }, 79 | { 80 | protocol = "tcp" 81 | from_port = 443 82 | to_port = 443 83 | self = true 84 | }, 85 | ] 86 | egress_rules = [ 87 | { 88 | protocol = "all" 89 | from_port = 0 90 | to_port = 0 91 | ipv4_cidrs = ["0.0.0.0/0"] 92 | ipv6_cidrs = ["::/0"] 93 | } 94 | ] 95 | } 96 | 97 | 98 | tags = { 99 | "project" = "terraform-aws-network-examples" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /examples/vpc-full/nacls.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # Network ACLs 3 | ################################################### 4 | 5 | module "private_network_acl" { 6 | source = "../../modules/nacl" 7 | # source = "tedilabs/network/aws//modules/nacl" 8 | # version = "~> 0.2.0" 9 | 10 | name = "test-private" 11 | vpc_id = module.vpc.id 12 | subnets = module.private_subnet_group.ids 13 | 14 | ingress_rules = { 15 | 900 = { 16 | action = "ALLOW" 17 | protocol = "-1" 18 | ipv4_cidr = "10.0.0.0/16" 19 | } 20 | } 21 | egress_rules = { 22 | 900 = { 23 | action = "ALLOW" 24 | protocol = "-1" 25 | ipv4_cidr = "10.0.0.0/16" 26 | } 27 | } 28 | 29 | tags = { 30 | "project" = "terraform-aws-network-examples" 31 | } 32 | } 33 | 34 | module "public_network_acl" { 35 | source = "../../modules/nacl" 36 | # source = "tedilabs/network/aws//modules/nacl" 37 | # version = "~> 0.2.0" 38 | 39 | name = "test-public" 40 | vpc_id = module.vpc.id 41 | subnets = module.public_subnet_group.ids 42 | 43 | ingress_rules = { 44 | 100 = { 45 | action = "ALLOW" 46 | protocol = "icmp" 47 | ipv4_cidr = "0.0.0.0/0" 48 | icmp_type = -1 49 | icmp_code = -1 50 | } 51 | 200 = { 52 | action = "ALLOW" 53 | protocol = "tcp" 54 | ipv4_cidr = "0.0.0.0/0" 55 | from_port = 22 56 | to_port = 22 57 | } 58 | 300 = { 59 | action = "ALLOW" 60 | protocol = "tcp" 61 | ipv4_cidr = "0.0.0.0/0" 62 | from_port = 80 63 | to_port = 80 64 | } 65 | 310 = { 66 | action = "ALLOW" 67 | protocol = "tcp" 68 | ipv4_cidr = "0.0.0.0/0" 69 | from_port = 443 70 | to_port = 443 71 | } 72 | 800 = { 73 | action = "ALLOW" 74 | protocol = "tcp" 75 | ipv4_cidr = "0.0.0.0/0" 76 | from_port = 1024 77 | to_port = 65535 78 | } 79 | 801 = { 80 | action = "ALLOW" 81 | protocol = "udp" 82 | ipv4_cidr = "0.0.0.0/0" 83 | from_port = 1024 84 | to_port = 65535 85 | } 86 | 900 = { 87 | action = "ALLOW" 88 | protocol = "-1" 89 | ipv4_cidr = "10.0.0.0/16" 90 | } 91 | } 92 | egress_rules = { 93 | 900 = { 94 | action = "ALLOW" 95 | protocol = "-1" 96 | ipv4_cidr = "0.0.0.0/0" 97 | } 98 | } 99 | 100 | tags = { 101 | "project" = "terraform-aws-network-examples" 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /examples/vpc-full/nat-gateways.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # Elastic IP 3 | ################################################### 4 | 5 | module "elastic_ip" { 6 | source = "tedilabs/ipam/aws//modules/elastic-ip" 7 | version = "~> 0.3.0" 8 | 9 | name = "nat-gw-test-public/az2" 10 | type = "AMAZON" 11 | 12 | tags = { 13 | "project" = "terraform-aws-network-examples" 14 | } 15 | } 16 | 17 | 18 | ################################################### 19 | # Public NAT Gateway 20 | ################################################### 21 | 22 | module "public_nat_gateway" { 23 | source = "../../modules/nat-gateway" 24 | # source = "tedilabs/network/aws//modules/nat-gateway" 25 | # version = "~> 0.2.0" 26 | 27 | name = "test-public/az2" 28 | is_private = false 29 | subnet = module.public_subnet_group.subnets_by_az["use1-az2"][0].id 30 | 31 | 32 | ## Primary IP Address 33 | primary_ip_assignment = { 34 | elastic_ip = module.elastic_ip.id 35 | } 36 | 37 | 38 | tags = { 39 | "project" = "terraform-aws-network-examples" 40 | } 41 | } 42 | 43 | 44 | ################################################### 45 | # Private NAT Gateway 46 | ################################################### 47 | 48 | module "private_nat_gateway" { 49 | source = "../../modules/nat-gateway" 50 | # source = "tedilabs/network/aws//modules/nat-gateway" 51 | # version = "~> 0.2.0" 52 | 53 | name = "test-private/az2" 54 | is_private = true 55 | subnet = module.private_subnet_group.subnets_by_az["use1-az2"][0].id 56 | 57 | 58 | ## Primary IP Address 59 | primary_ip_assignment = { 60 | private_ip = "10.0.200.7" 61 | } 62 | 63 | 64 | tags = { 65 | "project" = "terraform-aws-network-examples" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/vpc-full/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc" { 2 | description = "The VPC." 3 | value = module.vpc 4 | } 5 | 6 | output "subnet_groups" { 7 | description = "The Subnet Groups for the VPC." 8 | value = { 9 | private = module.private_subnet_group 10 | public = module.public_subnet_group 11 | } 12 | } 13 | 14 | output "nat_gateways" { 15 | description = "The NAT Gateways." 16 | value = { 17 | public = module.public_nat_gateway 18 | private = module.private_nat_gateway 19 | } 20 | } 21 | 22 | output "nacls" { 23 | description = "The Network ACLs." 24 | value = { 25 | public = module.public_network_acl 26 | private = module.private_network_acl 27 | } 28 | } 29 | 30 | output "route_tables" { 31 | description = "The Route Tables." 32 | value = { 33 | public = module.public_route_table 34 | private = module.private_route_table 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /examples/vpc-full/route-tables.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # Route Tables 3 | ################################################### 4 | 5 | module "private_route_table" { 6 | source = "../../modules/route-table" 7 | # source = "tedilabs/network/aws//modules/route-table" 8 | # version = "~> 0.2.0" 9 | 10 | name = "test-private" 11 | vpc_id = module.vpc.id 12 | subnets = module.private_subnet_group.ids 13 | gateways = [] 14 | 15 | 16 | ## Route Rules 17 | ipv4_routes = [ 18 | { 19 | destination = "0.0.0.0/0" 20 | target = { 21 | type = "NAT_GATEWAY" 22 | id = module.public_nat_gateway.id 23 | } 24 | }, 25 | ] 26 | ipv6_routes = [] 27 | prefix_list_routes = [] 28 | 29 | vpc_gateway_endpoints = [] 30 | propagating_vpn_gateways = [] 31 | 32 | 33 | tags = { 34 | "project" = "terraform-aws-network-examples" 35 | } 36 | } 37 | 38 | module "public_route_table" { 39 | source = "../../modules/route-table" 40 | # source = "tedilabs/network/aws//modules/route-table" 41 | # version = "~> 0.2.0" 42 | 43 | name = "test-public" 44 | vpc_id = module.vpc.id 45 | subnets = module.public_subnet_group.ids 46 | gateways = [] 47 | 48 | 49 | ## Route Rules 50 | ipv4_routes = [ 51 | { 52 | destination = "0.0.0.0/0" 53 | target = { 54 | type = "INTERNET_GATEWAY" 55 | id = module.vpc.internet_gateway.id 56 | } 57 | }, 58 | ] 59 | ipv6_routes = [] 60 | prefix_list_routes = [] 61 | 62 | vpc_gateway_endpoints = [] 63 | propagating_vpn_gateways = [] 64 | 65 | 66 | tags = { 67 | "project" = "terraform-aws-network-examples" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/vpc-full/subnet-groups.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # Subnet Groups 3 | ################################################### 4 | 5 | module "private_subnet_group" { 6 | source = "../../modules/subnet-group" 7 | # source = "tedilabs/network/aws//modules/subnet-group" 8 | # version = "~> 0.2.0" 9 | 10 | name = "test-private" 11 | 12 | vpc_id = module.vpc.id 13 | 14 | subnets = { 15 | "test-private/az2" = { 16 | availability_zone_id = "use1-az2" 17 | ipv4_cidr = "10.0.200.0/24" 18 | } 19 | "test-private/az4" = { 20 | availability_zone_id = "use1-az4" 21 | ipv4_cidr = "10.0.201.0/24" 22 | } 23 | } 24 | 25 | 26 | ## IP Assignments 27 | public_ipv4_address_assignment = { 28 | enabled = false 29 | } 30 | ipv6_address_assignment = { 31 | enabled = false 32 | } 33 | customer_owned_ipv4_address_assignment = { 34 | enabled = false 35 | } 36 | 37 | 38 | ## DNS Configurations 39 | dns_config = { 40 | hostname_type = "RESOURCE_NAME" 41 | dns_resource_name_ipv4_enabled = true 42 | dns_resource_name_ipv6_enabled = false 43 | dns64_enabled = false 44 | } 45 | 46 | ## Integrations 47 | dax_subnet_group = { 48 | enabled = true 49 | name = "test-dax" 50 | description = "Test DAX Subnet Group" 51 | } 52 | dms_replication_subnet_group = { 53 | enabled = true 54 | name = "test-dms-replication" 55 | description = "Test DMS Replication Subnet Group" 56 | } 57 | docdb_subnet_group = { 58 | enabled = true 59 | name = "test-docdb" 60 | description = "Test DocumentDB Subnet Group" 61 | } 62 | elasticache_subnet_group = { 63 | enabled = true 64 | name = "test-elasticache" 65 | description = "Test ElastiCache Subnet Group" 66 | } 67 | memorydb_subnet_group = { 68 | enabled = true 69 | name = "test-memorydb" 70 | description = "Test MemoryDB Subnet Group" 71 | } 72 | neptune_subnet_group = { 73 | enabled = true 74 | name = "test-neptune" 75 | description = "Test Neptune Subnet Group" 76 | } 77 | rds_subnet_group = { 78 | enabled = true 79 | name = "test-rds" 80 | description = "Test RDS Subnet Group" 81 | } 82 | redshift_subnet_group = { 83 | enabled = true 84 | name = "test-redshift" 85 | description = "Test Redshift Subnet Group" 86 | } 87 | 88 | 89 | ## Sharing 90 | shares = [ 91 | # { 92 | # name = "team1" 93 | # principals = ["123456789012"] 94 | # }, 95 | ] 96 | 97 | tags = { 98 | "project" = "terraform-aws-network-examples" 99 | } 100 | } 101 | 102 | module "public_subnet_group" { 103 | source = "../../modules/subnet-group" 104 | # source = "tedilabs/network/aws//modules/subnet-group" 105 | # version = "~> 0.2.0" 106 | 107 | name = "test-public" 108 | 109 | vpc_id = module.vpc.id 110 | 111 | subnets = { 112 | "test-public/az2" = { 113 | availability_zone_id = "use1-az2" 114 | ipv4_cidr = "10.0.100.0/24" 115 | } 116 | "test-public/az4" = { 117 | availability_zone_id = "use1-az4" 118 | ipv4_cidr = "10.0.101.0/24" 119 | } 120 | } 121 | 122 | 123 | ## IP Assignments 124 | public_ipv4_address_assignment = { 125 | enabled = true 126 | } 127 | ipv6_address_assignment = { 128 | enabled = false 129 | } 130 | customer_owned_ipv4_address_assignment = { 131 | enabled = false 132 | } 133 | 134 | 135 | ## DNS Configurations 136 | dns_config = { 137 | hostname_type = "RESOURCE_NAME" 138 | dns_resource_name_ipv4_enabled = true 139 | dns_resource_name_ipv6_enabled = false 140 | dns64_enabled = false 141 | } 142 | 143 | 144 | tags = { 145 | "project" = "terraform-aws-network-examples" 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /examples/vpc-full/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/vpc-ipv4-secondary-cidrs/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # VPC 8 | ################################################### 9 | 10 | module "vpc" { 11 | source = "../../modules/vpc" 12 | # source = "tedilabs/network/aws//modules/vpc" 13 | # version = "~> 0.2.0" 14 | 15 | name = "test" 16 | ipv4_cidrs = [ 17 | { 18 | cidr = "10.0.0.0/16" 19 | }, 20 | { 21 | cidr = "10.1.0.0/16" 22 | }, 23 | { 24 | cidr = "10.2.0.0/16" 25 | }, 26 | ] 27 | 28 | tags = { 29 | "project" = "terraform-aws-network-examples" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/vpc-ipv4-secondary-cidrs/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc" { 2 | description = "The VPC." 3 | value = module.vpc 4 | } 5 | -------------------------------------------------------------------------------- /examples/vpc-ipv4-secondary-cidrs/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/vpc-ipv6-cidrs/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # VPC 8 | ################################################### 9 | 10 | module "vpc" { 11 | source = "../../modules/vpc" 12 | # source = "tedilabs/network/aws//modules/vpc" 13 | # version = "~> 0.2.0" 14 | 15 | name = "test" 16 | ipv4_cidrs = [ 17 | { 18 | cidr = "10.0.0.0/16" 19 | }, 20 | ] 21 | ipv6_cidrs = [ 22 | { 23 | type = "AMAZON" 24 | }, 25 | ] 26 | 27 | tags = { 28 | "project" = "terraform-aws-network-examples" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/vpc-ipv6-cidrs/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc" { 2 | description = "The VPC." 3 | value = module.vpc 4 | } 5 | -------------------------------------------------------------------------------- /examples/vpc-ipv6-cidrs/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/vpc-simple/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # VPC 8 | ################################################### 9 | 10 | module "vpc" { 11 | source = "../../modules/vpc" 12 | # source = "tedilabs/network/aws//modules/vpc" 13 | # version = "~> 0.2.0" 14 | 15 | name = "test" 16 | ipv4_cidrs = [ 17 | { 18 | cidr = "10.0.0.0/16" 19 | }, 20 | ] 21 | 22 | tags = { 23 | "project" = "terraform-aws-network-examples" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/vpc-simple/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc" { 2 | description = "The VPC." 3 | value = module.vpc 4 | } 5 | -------------------------------------------------------------------------------- /examples/vpc-simple/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/vpc-with-ipam/ipam.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "this" {} 2 | 3 | locals { 4 | region = data.aws_region.this.name 5 | } 6 | 7 | 8 | ################################################### 9 | # IPAM 10 | ################################################### 11 | 12 | module "ipam" { 13 | source = "tedilabs/ipam/aws//modules/ipam" 14 | version = "~> 0.1.0" 15 | 16 | name = "test" 17 | description = "Managed by Terraform." 18 | 19 | operating_regions = [local.region] 20 | 21 | tags = { 22 | "project" = "terraform-aws-network-examples" 23 | } 24 | } 25 | 26 | 27 | ################################################### 28 | # IPAM Pools 29 | ################################################### 30 | 31 | resource "aws_vpc_ipam_pool" "ipv4" { 32 | address_family = "ipv4" 33 | ipam_scope_id = module.ipam.default_scopes["private"] 34 | locale = local.region 35 | } 36 | 37 | resource "aws_vpc_ipam_pool_cidr" "ipv4" { 38 | ipam_pool_id = aws_vpc_ipam_pool.ipv4.id 39 | cidr = "10.20.0.0/16" 40 | 41 | } 42 | 43 | resource "aws_vpc_ipam_pool" "ipv6" { 44 | address_family = "ipv6" 45 | ipam_scope_id = module.ipam.default_scopes["public"] 46 | locale = local.region 47 | publicly_advertisable = false 48 | public_ip_source = "amazon" 49 | aws_service = "ec2" 50 | } 51 | 52 | resource "aws_vpc_ipam_pool_cidr" "ipv6" { 53 | ipam_pool_id = aws_vpc_ipam_pool.ipv6.id 54 | netmask_length = 52 55 | } 56 | -------------------------------------------------------------------------------- /examples/vpc-with-ipam/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # VPC 8 | ################################################### 9 | 10 | module "vpc" { 11 | source = "../../modules/vpc" 12 | # source = "tedilabs/network/aws//modules/vpc" 13 | # version = "~> 0.2.0" 14 | 15 | name = "test" 16 | ipv4_cidrs = [ 17 | { 18 | type = "IPAM_POOL" 19 | ipam_pool = { 20 | id = aws_vpc_ipam_pool.ipv4.id 21 | netmask_length = 28 22 | } 23 | }, 24 | { 25 | cidr = "10.0.0.0/16" 26 | }, 27 | { 28 | type = "IPAM_POOL" 29 | ipam_pool = { 30 | id = aws_vpc_ipam_pool.ipv4.id 31 | netmask_length = 28 32 | } 33 | }, 34 | ] 35 | ipv6_cidrs = [ 36 | { 37 | type = "AMAZON" 38 | }, 39 | { 40 | type = "IPAM_POOL" 41 | ipam_pool = { 42 | id = aws_vpc_ipam_pool.ipv6.id 43 | netmask_length = 56 44 | } 45 | }, 46 | { 47 | type = "IPAM_POOL" 48 | ipam_pool = { 49 | id = aws_vpc_ipam_pool.ipv6.id 50 | cidr = "2600:1f28:7f:4100::/56" 51 | } 52 | }, 53 | ] 54 | 55 | tags = { 56 | "project" = "terraform-aws-network-examples" 57 | } 58 | 59 | depends_on = [ 60 | aws_vpc_ipam_pool_cidr.ipv4, 61 | aws_vpc_ipam_pool_cidr.ipv6, 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /examples/vpc-with-ipam/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc" { 2 | description = "The VPC." 3 | value = module.vpc 4 | } 5 | -------------------------------------------------------------------------------- /examples/vpc-with-ipam/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/nacl/README.md: -------------------------------------------------------------------------------- 1 | # nacl 2 | 3 | This module creates following resources. 4 | 5 | - `aws_network_acl` 6 | - `aws_network_acl_association` (optional) 7 | - `aws_network_acl_rule` (optional) 8 | 9 | 10 | ## Requirements 11 | 12 | | Name | Version | 13 | |------|---------| 14 | | [terraform](#requirement\_terraform) | >= 1.6 | 15 | | [aws](#requirement\_aws) | >= 4.59 | 16 | 17 | ## Providers 18 | 19 | | Name | Version | 20 | |------|---------| 21 | | [aws](#provider\_aws) | 5.22.0 | 22 | 23 | ## Modules 24 | 25 | | Name | Source | Version | 26 | |------|--------|---------| 27 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 28 | 29 | ## Resources 30 | 31 | | Name | Type | 32 | |------|------| 33 | | [aws_network_acl.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl) | resource | 34 | | [aws_network_acl_rule.egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource | 35 | | [aws_network_acl_rule.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource | 36 | 37 | ## Inputs 38 | 39 | | Name | Description | Type | Default | Required | 40 | |------|-------------|------|---------|:--------:| 41 | | [name](#input\_name) | (Required) Desired name for the network ACL resources. | `string` | n/a | yes | 42 | | [vpc\_id](#input\_vpc\_id) | (Required) The ID of the VPC to associate. | `string` | n/a | yes | 43 | | [egress\_rules](#input\_egress\_rules) | (Optional) A set of egress rules in the default Network ACL. Use the key of map as the rule number (priority). If not explicitly defined, the AWS default rules are applied. Each block of `egress_rules` as defined below.
(Required) `priority` - The rule priority. The rule number. Used for ordering.
(Required) `action` - The action to indicate whether to allow or deny the traffic that matches the rule. Valid values are `ALLOW` and `DENY`.
(Required) `protocol` - The protocol to match. If using the `-1` 'all' protocol, you must specify a from and to port of `0`.
(Optional) `from_port` - The from port to match.
(Optional) `to_port` - The to port to match.
(Optional) `ipv4_cidr` - The IPv4 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv6_cidr`.
(Optional) `ipv6_cidr` - The IPv6 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv4_cidr`.
(Optional) `icmp_type` - The ICMP type to be used. Defaults to `0`.
(Optional) `icmp_code` - The ICMP code to be used. Defaults to `0`. |
map(object({
action = string
protocol = string
from_port = optional(number)
to_port = optional(number)
ipv4_cidr = optional(string)
ipv6_cidr = optional(string)
icmp_type = optional(number, 0)
icmp_code = optional(number, 0)
}))
| `{}` | no | 44 | | [ingress\_rules](#input\_ingress\_rules) | (Optional) A map of ingress rules in the default Network ACL. Use the key of map as the rule number (priority). If not explicitly defined, the AWS default rules are applied. Each block of `ingress_rules` as defined below.
(Required) `priority` - The rule priority. The rule number. Used for ordering.
(Required) `action` - The action to indicate whether to allow or deny the traffic that matches the rule. Valid values are `ALLOW` and `DENY`.
(Required) `protocol` - The protocol to match. If using the `-1` `all` protocol, you must specify a from and to port of `0`.
(Optional) `from_port` - The from port to match.
(Optional) `to_port` - The to port to match.
(Optional) `ipv4_cidr` - The IPv4 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv6_cidr`.
(Optional) `ipv6_cidr` - The IPv6 network range to allow or deny, in CIDR notation. Cannot be specified with `ipv4_cidr`.
(Optional) `icmp_type` - The ICMP type to be used. Defaults to `0`.
(Optional) `icmp_code` - The ICMP code to be used. Defaults to `0`. |
map(object({
action = string
protocol = string
from_port = optional(number)
to_port = optional(number)
ipv4_cidr = optional(string)
ipv6_cidr = optional(string)
icmp_type = optional(number, 0)
icmp_code = optional(number, 0)
}))
| `{}` | no | 45 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 46 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 47 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 48 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 49 | | [subnets](#input\_subnets) | (Optional) A list of subnet IDs to apply the ACL to. | `list(string)` | `[]` | no | 50 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 51 | 52 | ## Outputs 53 | 54 | | Name | Description | 55 | |------|-------------| 56 | | [arn](#output\_arn) | The ARN of the network ACL. | 57 | | [id](#output\_id) | The ID of the network ACL. | 58 | | [name](#output\_name) | The name of the network ACL. | 59 | | [owner\_id](#output\_owner\_id) | The ID of the AWS account that owns the network ACL. | 60 | | [subnets](#output\_subnets) | A list of subnet IDs which is associated with the network ACL. | 61 | | [vpc\_id](#output\_vpc\_id) | The VPC ID of the network ACL. | 62 | 63 | -------------------------------------------------------------------------------- /modules/nacl/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-network" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | 18 | ################################################### 19 | # Network ACL 20 | ################################################### 21 | 22 | # INFO: Not supported attributes 23 | # - `ingress` 24 | # - `egress` 25 | resource "aws_network_acl" "this" { 26 | vpc_id = var.vpc_id 27 | subnet_ids = var.subnets 28 | 29 | tags = merge( 30 | { 31 | "Name" = local.metadata.name 32 | }, 33 | local.module_tags, 34 | var.tags, 35 | ) 36 | } 37 | 38 | 39 | ################################################### 40 | # Subnet Associations of Network ACL 41 | ################################################### 42 | 43 | # resource "aws_network_acl_association" "this" { 44 | # for_each = toset(var.subnets) 45 | # 46 | # network_acl_id = aws_network_acl.this.id 47 | # subnet_id = each.value 48 | # } 49 | 50 | 51 | ################################################### 52 | # Network ACL Rules 53 | ################################################### 54 | 55 | resource "aws_network_acl_rule" "ingress" { 56 | for_each = var.ingress_rules 57 | 58 | network_acl_id = aws_network_acl.this.id 59 | 60 | egress = false 61 | rule_number = each.key 62 | 63 | rule_action = lower(each.value.action) 64 | protocol = each.value.protocol 65 | from_port = each.value.from_port 66 | to_port = each.value.to_port 67 | icmp_type = each.value.icmp_type 68 | icmp_code = each.value.icmp_code 69 | cidr_block = each.value.ipv4_cidr 70 | ipv6_cidr_block = each.value.ipv6_cidr 71 | } 72 | 73 | resource "aws_network_acl_rule" "egress" { 74 | for_each = var.egress_rules 75 | 76 | network_acl_id = aws_network_acl.this.id 77 | 78 | egress = true 79 | rule_number = each.key 80 | 81 | rule_action = lower(each.value.action) 82 | protocol = each.value.protocol 83 | from_port = each.value.from_port 84 | to_port = each.value.to_port 85 | icmp_type = each.value.icmp_type 86 | icmp_code = each.value.icmp_code 87 | cidr_block = each.value.ipv4_cidr 88 | ipv6_cidr_block = each.value.ipv6_cidr 89 | } 90 | -------------------------------------------------------------------------------- /modules/nacl/migrations.tf: -------------------------------------------------------------------------------- 1 | # 2023-02-01 2 | moved { 3 | from = aws_resourcegroups_group.this[0] 4 | to = module.resource_group[0].aws_resourcegroups_group.this 5 | } 6 | -------------------------------------------------------------------------------- /modules/nacl/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the network ACL." 3 | value = aws_network_acl.this.id 4 | } 5 | 6 | output "arn" { 7 | description = "The ARN of the network ACL." 8 | value = aws_network_acl.this.arn 9 | } 10 | 11 | output "owner_id" { 12 | description = "The ID of the AWS account that owns the network ACL." 13 | value = aws_network_acl.this.owner_id 14 | } 15 | 16 | output "name" { 17 | description = "The name of the network ACL." 18 | value = var.name 19 | } 20 | 21 | output "vpc_id" { 22 | description = "The VPC ID of the network ACL." 23 | value = aws_network_acl.this.vpc_id 24 | } 25 | 26 | output "subnets" { 27 | description = "A list of subnet IDs which is associated with the network ACL." 28 | value = aws_network_acl.this.subnet_ids 29 | } 30 | -------------------------------------------------------------------------------- /modules/nacl/resource-group.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | resource_group_name = (var.resource_group_name != "" 3 | ? var.resource_group_name 4 | : join(".", [ 5 | local.metadata.package, 6 | local.metadata.module, 7 | replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), 8 | ]) 9 | ) 10 | } 11 | 12 | 13 | module "resource_group" { 14 | source = "tedilabs/misc/aws//modules/resource-group" 15 | version = "~> 0.10.0" 16 | 17 | count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 18 | 19 | name = local.resource_group_name 20 | description = var.resource_group_description 21 | 22 | query = { 23 | resource_tags = local.module_tags 24 | } 25 | 26 | module_tags_enabled = false 27 | tags = merge( 28 | local.module_tags, 29 | var.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/nacl/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "(Required) Desired name for the network ACL resources." 3 | type = string 4 | nullable = false 5 | } 6 | 7 | variable "vpc_id" { 8 | description = "(Required) The ID of the VPC to associate." 9 | type = string 10 | nullable = false 11 | } 12 | 13 | variable "subnets" { 14 | description = "(Optional) A list of subnet IDs to apply the ACL to." 15 | type = list(string) 16 | default = [] 17 | nullable = false 18 | } 19 | 20 | variable "ingress_rules" { 21 | description = < 9 | ## Requirements 10 | 11 | | Name | Version | 12 | |------|---------| 13 | | [terraform](#requirement\_terraform) | >= 1.6 | 14 | | [aws](#requirement\_aws) | >= 5.10 | 15 | 16 | ## Providers 17 | 18 | | Name | Version | 19 | |------|---------| 20 | | [aws](#provider\_aws) | 5.22.0 | 21 | 22 | ## Modules 23 | 24 | | Name | Source | Version | 25 | |------|--------|---------| 26 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 27 | 28 | ## Resources 29 | 30 | | Name | Type | 31 | |------|------| 32 | | [aws_nat_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource | 33 | | [aws_subnet.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source | 34 | 35 | ## Inputs 36 | 37 | | Name | Description | Type | Default | Required | 38 | |------|-------------|------|---------|:--------:| 39 | | [name](#input\_name) | (Required) Desired name for the NAT Gateway resources. | `string` | n/a | yes | 40 | | [subnet](#input\_subnet) | (Required) The Subnet ID of the subnet in which to place the NAT Gateway. | `string` | n/a | yes | 41 | | [is\_private](#input\_is\_private) | (Optional) Whether to create the NAT gateway as private or public connectivity type. Defaults to `false` (public). | `bool` | `false` | no | 42 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 43 | | [primary\_ip\_assignment](#input\_primary\_ip\_assignment) | (Optional) A configuration to assign primary ip address with the NAT Gateway. `primary_ip_assignment` as defined below.
(Optional) `elastic_ip` - The allocation ID of Elastic IP address to associate with the NAT Gateway.
(Optional) `private_ip` - The private IP address to associate with the NAT Gateway. If you dont't provide an address, a private IPv4 address will be automatically assigned. |
object({
elastic_ip = optional(string)
private_ip = optional(string)
})
| `{}` | no | 44 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 45 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 46 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 47 | | [secondary\_ip\_assignments](#input\_secondary\_ip\_assignments) | (Optional) A configuration to assign secondary ip addresses with the NAT Gateway. Each block of `secondary_ip_assignments` as defined below.
(Optional) `elastic_ip` - The allocation ID of Elastic IP address to associate with the NAT Gateway.
(Optional) `private_ip` - The private IP address to associate with the NAT Gateway. If you dont't provide an address, a private IPv4 address will be automatically assigned. |
list(object({
elastic_ip = optional(string)
private_ip = optional(string)
}))
| `[]` | no | 48 | | [secondary\_ip\_count](#input\_secondary\_ip\_count) | (Optional) The number of secondary private IPv4 addresses to assign to the NAT Gateway. Only used with private NAT Gateway. | `number` | `null` | no | 49 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 50 | | [timeouts](#input\_timeouts) | (Optional) How long to wait for the NAT Gateway to be created/updated/deleted. |
object({
create = optional(string, "10m")
update = optional(string, "10m")
delete = optional(string, "30m")
})
| `{}` | no | 51 | 52 | ## Outputs 53 | 54 | | Name | Description | 55 | |------|-------------| 56 | | [availability\_zone](#output\_availability\_zone) | The availability zone of the NAT Gateway.
`id` - The ID of the availability zone.
`name` - The name of the availability zone. | 57 | | [elastic\_ip](#output\_elastic\_ip) | The Allocation ID of the Elastic IP address for the gateway. | 58 | | [id](#output\_id) | The ID of the NAT Gateway. | 59 | | [is\_private](#output\_is\_private) | Whether the NAT Gateway supports public or private connectivity. | 60 | | [name](#output\_name) | The name of the NAT Gateway. | 61 | | [netework\_interface](#output\_netework\_interface) | The ENI ID of the network interface created by the NAT gateway. | 62 | | [primary\_private\_ip](#output\_primary\_private\_ip) | The private IP address of the NAT Gateway. | 63 | | [primary\_public\_ip](#output\_primary\_public\_ip) | The public IP address of the NAT Gateway. | 64 | | [secondary\_private\_ips](#output\_secondary\_private\_ips) | The secondary private IP addresses of the NAT Gateway. | 65 | | [subnet](#output\_subnet) | The subnet which the NAT Gateway belongs to.
`id` - The ID of the subnet.
`arn` - The ARN of the subnet. | 66 | | [vpc\_id](#output\_vpc\_id) | The VPC ID of the NAT Gateway. | 67 | 68 | -------------------------------------------------------------------------------- /modules/nat-gateway/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-network" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | data "aws_subnet" "this" { 18 | id = var.subnet 19 | } 20 | 21 | 22 | ################################################### 23 | # NAT Gateway 24 | ################################################### 25 | 26 | resource "aws_nat_gateway" "this" { 27 | connectivity_type = var.is_private ? "private" : "public" 28 | subnet_id = var.subnet 29 | 30 | 31 | ## Primary IP Addresse 32 | allocation_id = var.primary_ip_assignment.elastic_ip 33 | private_ip = var.primary_ip_assignment.private_ip 34 | 35 | 36 | ## Secondary IP Addresses 37 | secondary_allocation_ids = (!var.is_private 38 | ? [ 39 | for assignment in var.secondary_ip_assignments : 40 | assignment.elastic_ip 41 | ] 42 | : null 43 | ) 44 | secondary_private_ip_addresses = (var.secondary_ip_count == null 45 | ? [ 46 | for assignment in var.secondary_ip_assignments : 47 | assignment.private_ip 48 | ] 49 | : null 50 | ) 51 | secondary_private_ip_address_count = var.secondary_ip_count 52 | 53 | timeouts { 54 | create = var.timeouts.create 55 | update = var.timeouts.update 56 | delete = var.timeouts.delete 57 | } 58 | 59 | tags = merge( 60 | { 61 | "Name" = local.metadata.name 62 | }, 63 | local.module_tags, 64 | var.tags, 65 | ) 66 | 67 | lifecycle { 68 | precondition { 69 | condition = anytrue([ 70 | var.secondary_ip_count == null, 71 | var.secondary_ip_count != null && var.is_private == true, 72 | ]) 73 | error_message = "`secondary_ip_count` variable is only supported with private NAT Gateway." 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /modules/nat-gateway/migrations.tf: -------------------------------------------------------------------------------- 1 | # 2023-02-01 2 | moved { 3 | from = aws_resourcegroups_group.this[0] 4 | to = module.resource_group[0].aws_resourcegroups_group.this 5 | } 6 | -------------------------------------------------------------------------------- /modules/nat-gateway/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the NAT Gateway." 3 | value = aws_nat_gateway.this.id 4 | } 5 | 6 | output "name" { 7 | description = "The name of the NAT Gateway." 8 | value = var.name 9 | } 10 | 11 | output "is_private" { 12 | description = "Whether the NAT Gateway supports public or private connectivity." 13 | value = aws_nat_gateway.this.connectivity_type == "private" 14 | } 15 | 16 | output "availability_zone" { 17 | description = < 0 && var.secondary_ip_count < 32 68 | : true 69 | ) 70 | error_message = "`secondary_ip_count` must be greater than 0 and less than 32." 71 | } 72 | } 73 | 74 | variable "timeouts" { 75 | description = "(Optional) How long to wait for the NAT Gateway to be created/updated/deleted." 76 | type = object({ 77 | create = optional(string, "10m") 78 | update = optional(string, "10m") 79 | delete = optional(string, "30m") 80 | }) 81 | default = {} 82 | nullable = false 83 | } 84 | 85 | variable "tags" { 86 | description = "(Optional) A map of tags to add to all resources." 87 | type = map(string) 88 | default = {} 89 | nullable = false 90 | } 91 | 92 | variable "module_tags_enabled" { 93 | description = "(Optional) Whether to create AWS Resource Tags for the module informations." 94 | type = bool 95 | default = true 96 | nullable = false 97 | } 98 | 99 | 100 | ################################################### 101 | # Resource Group 102 | ################################################### 103 | 104 | variable "resource_group_enabled" { 105 | description = "(Optional) Whether to create Resource Group to find and group AWS resources which are created by this module." 106 | type = bool 107 | default = true 108 | nullable = false 109 | } 110 | 111 | variable "resource_group_name" { 112 | description = "(Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`." 113 | type = string 114 | default = "" 115 | nullable = false 116 | } 117 | 118 | variable "resource_group_description" { 119 | description = "(Optional) The description of Resource Group." 120 | type = string 121 | default = "Managed by Terraform." 122 | nullable = false 123 | } 124 | -------------------------------------------------------------------------------- /modules/nat-gateway/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.6" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.10" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/route-table/README.md: -------------------------------------------------------------------------------- 1 | # route-table 2 | 3 | This module creates following resources. 4 | 5 | - `aws_route_table` 6 | - `aws_route` (optional) 7 | - `aws_main_route_table_association` (optional) 8 | - `aws_route_table_association` (optional) 9 | - `aws_vpc_endpoint_route_table_association` (optional) 10 | - `aws_vpn_gateway_route_propagation` (optional) 11 | 12 | 13 | ## Requirements 14 | 15 | | Name | Version | 16 | |------|---------| 17 | | [terraform](#requirement\_terraform) | >= 1.6 | 18 | | [aws](#requirement\_aws) | >= 5.11 | 19 | 20 | ## Providers 21 | 22 | | Name | Version | 23 | |------|---------| 24 | | [aws](#provider\_aws) | 5.92.0 | 25 | 26 | ## Modules 27 | 28 | | Name | Source | Version | 29 | |------|--------|---------| 30 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 31 | 32 | ## Resources 33 | 34 | | Name | Type | 35 | |------|------| 36 | | [aws_main_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/main_route_table_association) | resource | 37 | | [aws_route.ipv4](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 38 | | [aws_route.ipv6](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 39 | | [aws_route.prefix_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 40 | | [aws_route_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 41 | | [aws_route_table_association.gateways](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 42 | | [aws_route_table_association.subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 43 | | [aws_vpc_endpoint_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint_route_table_association) | resource | 44 | | [aws_vpn_gateway_route_propagation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_gateway_route_propagation) | resource | 45 | 46 | ## Inputs 47 | 48 | | Name | Description | Type | Default | Required | 49 | |------|-------------|------|---------|:--------:| 50 | | [name](#input\_name) | (Required) Desired name for the route table resources. | `string` | n/a | yes | 51 | | [vpc\_id](#input\_vpc\_id) | (Required) The ID of the VPC which the route table belongs to. | `string` | n/a | yes | 52 | | [gateways](#input\_gateways) | (Optional) A list of gateway IDs to associate with the route table. Only support Internet Gateway and Virtual Private Gateway. | `list(string)` | `[]` | no | 53 | | [ipv4\_routes](#input\_ipv4\_routes) | (Optional) A list of route rules for destinations to IPv4 CIDRs. Each block of `ipv4_routes` as defined below.
(Required) `destination` - The destination IPv4 CIDR block of the route rule.
(Required) `target` - A configuration of the target of the route rule. `target` as defined below.
(Required) `type` - The type of the target of the route rule. Valid values are `CARRIER_GATEWAY`, `CORE_GATEWAY`, `EGRESS_ONLY_INTERNET_GATEWAY`, `INTERNET_GATEWAY`, `VPN_GATEWAY`, `LOCAL_GATEWAY`, `NAT_GATEWAY`, `NETWORK_INTERFACE`, `TRANSIT_GATEWAY`, `VPC_ENDPOINT`, `VPC_PEERING_CONNECTION`.
(Required) `id` - The ID of the target of the route rule. |
list(object({
destination = string

target = object({
type = string
id = string
})
}))
| `[]` | no | 54 | | [ipv6\_routes](#input\_ipv6\_routes) | (Optional) A list of route rules for destinations to IPv6 CIDRs. Each block of `ipv6_routes` as defined below.
(Required) `destination` - The destination IPv6 CIDR block of the route rule.
(Required) `target` - A configuration of the target of the route rule. `target` as defined below.
(Required) `type` - The type of the target of the route rule. Valid values are `CARRIER_GATEWAY`, `CORE_GATEWAY`, `EGRESS_ONLY_INTERNET_GATEWAY`, `INTERNET_GATEWAY`, `VPN_GATEWAY`, `LOCAL_GATEWAY`, `NAT_GATEWAY`, `NETWORK_INTERFACE`, `TRANSIT_GATEWAY`, `VPC_ENDPOINT`, `VPC_PEERING_CONNECTION`.
(Required) `id` - The ID of the target of the route rule. |
list(object({
destination = string

target = object({
type = string
id = string
})
}))
| `[]` | no | 55 | | [is\_main](#input\_is\_main) | (Optional) Whether to set this route table as the main route table. Defaults to `false`. | `bool` | `false` | no | 56 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 57 | | [prefix\_list\_routes](#input\_prefix\_list\_routes) | (Optional) A list of route rules for destinations to Prefix Lists. Each block of `prefix_list_routes` as defined below.
(Required) `name` - The name of the route rule.
(Required) `destination` - The destination Prefix List of the route rule.
(Required) `target` - A configuration of the target of the route rule. `target` as defined below.
(Required) `type` - The type of the target of the route rule. Valid values are `CARRIER_GATEWAY`, `CORE_GATEWAY`, `EGRESS_ONLY_INTERNET_GATEWAY`, `INTERNET_GATEWAY`, `VPN_GATEWAY`, `LOCAL_GATEWAY`, `NAT_GATEWAY`, `NETWORK_INTERFACE`, `TRANSIT_GATEWAY`, `VPC_ENDPOINT`, `VPC_PEERING_CONNECTION`.
(Required) `id` - The ID of the target of the route rule. |
list(object({
name = string
destination = string

target = object({
type = string
id = string
})
}))
| `[]` | no | 58 | | [propagating\_vpn\_gateways](#input\_propagating\_vpn\_gateways) | (Optional) A list of Virtual Private Gateway IDs to propagate routes from. | `list(string)` | `[]` | no | 59 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 60 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 61 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 62 | | [subnets](#input\_subnets) | (Optional) A list of subnet IDs to associate with the route table. | `list(string)` | `[]` | no | 63 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 64 | | [timeouts](#input\_timeouts) | (Optional) How long to wait for the route table to be created/updated/deleted. |
object({
create = optional(string, "5m")
update = optional(string, "2m")
delete = optional(string, "5m")
})
| `{}` | no | 65 | | [vpc\_gateway\_endpoints](#input\_vpc\_gateway\_endpoints) | (Optional) A list of the VPC Endpoint IDs with which the Route Table will be associated. | `list(string)` | `[]` | no | 66 | 67 | ## Outputs 68 | 69 | | Name | Description | 70 | |------|-------------| 71 | | [arn](#output\_arn) | The ARN of the routing table. | 72 | | [associated\_gateways](#output\_associated\_gateways) | A list of gateway IDs which is associated with the route table. | 73 | | [associated\_subnets](#output\_associated\_subnets) | A list of subnet IDs which is associated with the route table. | 74 | | [associated\_vpc\_gateway\_endpoints](#output\_associated\_vpc\_gateway\_endpoints) | A list of the VPC Gateway Endpoint IDs which is associated with the route table. | 75 | | [id](#output\_id) | The ID of the routing table. | 76 | | [ipv4\_routes](#output\_ipv4\_routes) | A list of route rules for destinations to IPv4 CIDRs. | 77 | | [ipv6\_routes](#output\_ipv6\_routes) | A list of route rules for destinations to IPv6 CIDRs. | 78 | | [is\_main](#output\_is\_main) | Whether to set this route table as the main route table. | 79 | | [owner](#output\_owner) | The ID of the AWS account that owns subnets in the routing table. | 80 | | [prefix\_list\_routes](#output\_prefix\_list\_routes) | A list of route rules for destinations to Prefix Lists. | 81 | | [propagated\_vpn\_gateways](#output\_propagated\_vpn\_gateways) | A list of Virtual Private Gateway IDs which propagate routes from. | 82 | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC which the route table belongs to. | 83 | 84 | -------------------------------------------------------------------------------- /modules/route-table/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-network" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | 18 | ################################################### 19 | # Route Table 20 | ################################################### 21 | 22 | resource "aws_route_table" "this" { 23 | vpc_id = var.vpc_id 24 | 25 | timeouts { 26 | create = var.timeouts.create 27 | update = var.timeouts.update 28 | delete = var.timeouts.delete 29 | } 30 | 31 | tags = merge( 32 | { 33 | "Name" = local.metadata.name 34 | }, 35 | local.module_tags, 36 | var.tags, 37 | ) 38 | 39 | lifecycle { 40 | create_before_destroy = true 41 | } 42 | } 43 | 44 | resource "aws_main_route_table_association" "this" { 45 | count = var.is_main ? 1 : 0 46 | 47 | vpc_id = var.vpc_id 48 | route_table_id = aws_route_table.this.id 49 | 50 | timeouts { 51 | create = var.timeouts.create 52 | update = var.timeouts.update 53 | delete = var.timeouts.delete 54 | } 55 | } 56 | 57 | 58 | ################################################### 59 | # Associations 60 | ################################################### 61 | 62 | resource "aws_route_table_association" "subnets" { 63 | count = length(var.subnets) 64 | 65 | route_table_id = aws_route_table.this.id 66 | subnet_id = var.subnets[count.index] 67 | } 68 | 69 | resource "aws_route_table_association" "gateways" { 70 | count = length(var.gateways) 71 | 72 | route_table_id = aws_route_table.this.id 73 | gateway_id = var.gateways[count.index] 74 | } 75 | 76 | 77 | ################################################### 78 | # VPC Gateway Endpoint Association 79 | ################################################### 80 | 81 | resource "aws_vpc_endpoint_route_table_association" "this" { 82 | for_each = toset(var.vpc_gateway_endpoints) 83 | 84 | route_table_id = aws_route_table.this.id 85 | vpc_endpoint_id = each.value 86 | } 87 | 88 | 89 | ################################################### 90 | # Route Propagations 91 | ################################################### 92 | 93 | resource "aws_vpn_gateway_route_propagation" "this" { 94 | for_each = toset(var.propagating_vpn_gateways) 95 | 96 | route_table_id = aws_route_table.this.id 97 | vpn_gateway_id = each.value 98 | } 99 | -------------------------------------------------------------------------------- /modules/route-table/migrations.tf: -------------------------------------------------------------------------------- 1 | # 2023-02-01 2 | moved { 3 | from = aws_resourcegroups_group.this[0] 4 | to = module.resource_group[0].aws_resourcegroups_group.this 5 | } 6 | -------------------------------------------------------------------------------- /modules/route-table/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | description = "The ID of the VPC which the route table belongs to." 3 | value = var.vpc_id 4 | } 5 | 6 | output "id" { 7 | description = "The ID of the routing table." 8 | value = aws_route_table.this.id 9 | } 10 | 11 | output "arn" { 12 | description = "The ARN of the routing table." 13 | value = aws_route_table.this.arn 14 | } 15 | 16 | output "owner" { 17 | description = "The ID of the AWS account that owns subnets in the routing table." 18 | value = aws_route_table.this.owner_id 19 | } 20 | 21 | output "is_main" { 22 | description = "Whether to set this route table as the main route table." 23 | value = var.is_main 24 | } 25 | 26 | output "ipv4_routes" { 27 | description = "A list of route rules for destinations to IPv4 CIDRs." 28 | value = [ 29 | for route in var.ipv4_routes : { 30 | id = aws_route.ipv4[route.destination].id, 31 | state = aws_route.ipv4[route.destination].state, 32 | destination = route.destination 33 | target = { 34 | type = route.target.type 35 | id = coalesce( 36 | aws_route.ipv4[route.destination].carrier_gateway_id, 37 | aws_route.ipv4[route.destination].core_network_arn, 38 | aws_route.ipv4[route.destination].egress_only_gateway_id, 39 | aws_route.ipv4[route.destination].gateway_id, 40 | aws_route.ipv4[route.destination].local_gateway_id, 41 | aws_route.ipv4[route.destination].nat_gateway_id, 42 | aws_route.ipv4[route.destination].network_interface_id, 43 | aws_route.ipv4[route.destination].transit_gateway_id, 44 | aws_route.ipv4[route.destination].vpc_endpoint_id, 45 | aws_route.ipv4[route.destination].vpc_peering_connection_id, 46 | ) 47 | } 48 | } 49 | ] 50 | } 51 | 52 | output "ipv6_routes" { 53 | description = "A list of route rules for destinations to IPv6 CIDRs." 54 | value = [ 55 | for route in var.ipv6_routes : { 56 | id = aws_route.ipv6[route.destination].id, 57 | state = aws_route.ipv6[route.destination].state, 58 | destination = route.destination 59 | target = { 60 | type = route.target.type 61 | id = coalesce( 62 | aws_route.ipv6[route.destination].carrier_gateway_id, 63 | aws_route.ipv6[route.destination].core_network_arn, 64 | aws_route.ipv6[route.destination].egress_only_gateway_id, 65 | aws_route.ipv6[route.destination].gateway_id, 66 | aws_route.ipv6[route.destination].local_gateway_id, 67 | aws_route.ipv6[route.destination].nat_gateway_id, 68 | aws_route.ipv6[route.destination].network_interface_id, 69 | aws_route.ipv6[route.destination].transit_gateway_id, 70 | aws_route.ipv6[route.destination].vpc_endpoint_id, 71 | aws_route.ipv6[route.destination].vpc_peering_connection_id, 72 | ) 73 | } 74 | } 75 | ] 76 | } 77 | 78 | output "prefix_list_routes" { 79 | description = "A list of route rules for destinations to Prefix Lists." 80 | value = [ 81 | for route in var.prefix_list_routes : { 82 | id = aws_route.prefix_list[route.name].id, 83 | state = aws_route.prefix_list[route.name].state, 84 | destination = route.destination 85 | target = { 86 | type = route.target.type 87 | id = coalesce( 88 | aws_route.prefix_list[route.name].carrier_gateway_id, 89 | aws_route.prefix_list[route.name].core_network_arn, 90 | aws_route.prefix_list[route.name].egress_only_gateway_id, 91 | aws_route.prefix_list[route.name].gateway_id, 92 | aws_route.prefix_list[route.name].local_gateway_id, 93 | aws_route.prefix_list[route.name].nat_gateway_id, 94 | aws_route.prefix_list[route.name].network_interface_id, 95 | aws_route.prefix_list[route.name].transit_gateway_id, 96 | aws_route.prefix_list[route.name].vpc_endpoint_id, 97 | aws_route.prefix_list[route.name].vpc_peering_connection_id, 98 | ) 99 | } 100 | } 101 | ] 102 | } 103 | 104 | output "associated_subnets" { 105 | description = "A list of subnet IDs which is associated with the route table." 106 | value = aws_route_table_association.subnets[*].subnet_id 107 | } 108 | 109 | output "associated_gateways" { 110 | description = "A list of gateway IDs which is associated with the route table." 111 | value = aws_route_table_association.gateways[*].gateway_id 112 | } 113 | 114 | output "associated_vpc_gateway_endpoints" { 115 | description = "A list of the VPC Gateway Endpoint IDs which is associated with the route table." 116 | value = var.vpc_gateway_endpoints 117 | } 118 | 119 | output "propagated_vpn_gateways" { 120 | description = "A list of Virtual Private Gateway IDs which propagate routes from." 121 | value = values(aws_vpn_gateway_route_propagation.this)[*].vpn_gateway_id 122 | } 123 | -------------------------------------------------------------------------------- /modules/route-table/resource-group.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | resource_group_name = (var.resource_group_name != "" 3 | ? var.resource_group_name 4 | : join(".", [ 5 | local.metadata.package, 6 | local.metadata.module, 7 | replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), 8 | ]) 9 | ) 10 | } 11 | 12 | 13 | module "resource_group" { 14 | source = "tedilabs/misc/aws//modules/resource-group" 15 | version = "~> 0.10.0" 16 | 17 | count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 18 | 19 | name = local.resource_group_name 20 | description = var.resource_group_description 21 | 22 | query = { 23 | resource_tags = local.module_tags 24 | } 25 | 26 | module_tags_enabled = false 27 | tags = merge( 28 | local.module_tags, 29 | var.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/route-table/routes.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # IPv4 Routes 3 | ################################################### 4 | 5 | # INFO: Not supported attributes 6 | # - `instance_id` (Deprecated) 7 | resource "aws_route" "ipv4" { 8 | for_each = { 9 | for route in var.ipv4_routes : 10 | route.destination => route 11 | } 12 | 13 | route_table_id = aws_route_table.this.id 14 | destination_cidr_block = each.key 15 | 16 | 17 | ## Targets 18 | carrier_gateway_id = (each.value.target.type == "CARRIER_GATEWAY" 19 | ? each.value.target.id 20 | : null 21 | ) 22 | core_network_arn = (each.value.target.type == "CORE_NETWORK" 23 | ? each.value.target.id 24 | : null 25 | ) 26 | egress_only_gateway_id = (each.value.target.type == "EGRESS_ONLY_INTERNET_GATEWAY" 27 | ? each.value.target.id 28 | : null 29 | ) 30 | gateway_id = (contains(["INTERNET_GATEWAY", "VPN_GATEWAY"], each.value.target.type) 31 | ? each.value.target.id 32 | : null 33 | ) 34 | local_gateway_id = (each.value.target.type == "LOCAL_GATEWAY" 35 | ? each.value.target.id 36 | : null 37 | ) 38 | nat_gateway_id = (each.value.target.type == "NAT_GATEWAY" 39 | ? each.value.target.id 40 | : null 41 | ) 42 | network_interface_id = (each.value.target.type == "NETWORK_INTERFACE" 43 | ? each.value.target.id 44 | : null 45 | ) 46 | transit_gateway_id = (each.value.target.type == "TRANSIT_GATEWAY" 47 | ? each.value.target.id 48 | : null 49 | ) 50 | vpc_endpoint_id = (each.value.target.type == "VPC_ENDPOINT" 51 | ? each.value.target.id 52 | : null 53 | ) 54 | vpc_peering_connection_id = (each.value.target.type == "VPC_PEERING_CONNECTION" 55 | ? each.value.target.id 56 | : null 57 | ) 58 | } 59 | 60 | 61 | ################################################### 62 | # IPv6 Routes 63 | ################################################### 64 | 65 | resource "aws_route" "ipv6" { 66 | for_each = { 67 | for route in var.ipv6_routes : 68 | route.destination => route 69 | } 70 | 71 | route_table_id = aws_route_table.this.id 72 | destination_ipv6_cidr_block = each.key 73 | 74 | 75 | ## Targets 76 | carrier_gateway_id = (each.value.target.type == "CARRIER_GATEWAY" 77 | ? each.value.target.id 78 | : null 79 | ) 80 | core_network_arn = (each.value.target.type == "CORE_NETWORK" 81 | ? each.value.target.id 82 | : null 83 | ) 84 | egress_only_gateway_id = (each.value.target.type == "EGRESS_ONLY_INTERNET_GATEWAY" 85 | ? each.value.target.id 86 | : null 87 | ) 88 | gateway_id = (contains(["INTERNET_GATEWAY", "VPN_GATEWAY"], each.value.target.type) 89 | ? each.value.target.id 90 | : null 91 | ) 92 | local_gateway_id = (each.value.target.type == "LOCAL_GATEWAY" 93 | ? each.value.target.id 94 | : null 95 | ) 96 | nat_gateway_id = (each.value.target.type == "NAT_GATEWAY" 97 | ? each.value.target.id 98 | : null 99 | ) 100 | network_interface_id = (each.value.target.type == "NETWORK_INTERFACE" 101 | ? each.value.target.id 102 | : null 103 | ) 104 | transit_gateway_id = (each.value.target.type == "TRANSIT_GATEWAY" 105 | ? each.value.target.id 106 | : null 107 | ) 108 | vpc_endpoint_id = (each.value.target.type == "VPC_ENDPOINT" 109 | ? each.value.target.id 110 | : null 111 | ) 112 | vpc_peering_connection_id = (each.value.target.type == "VPC_PEERING_CONNECTION" 113 | ? each.value.target.id 114 | : null 115 | ) 116 | } 117 | 118 | 119 | ################################################### 120 | # Prefix List Routes 121 | ################################################### 122 | 123 | resource "aws_route" "prefix_list" { 124 | for_each = { 125 | for route in var.prefix_list_routes : 126 | route.name => route 127 | } 128 | 129 | route_table_id = aws_route_table.this.id 130 | destination_prefix_list_id = each.value.destination 131 | 132 | 133 | ## Targets 134 | carrier_gateway_id = (each.value.target.type == "CARRIER_GATEWAY" 135 | ? each.value.target.id 136 | : null 137 | ) 138 | core_network_arn = (each.value.target.type == "CORE_NETWORK" 139 | ? each.value.target.id 140 | : null 141 | ) 142 | egress_only_gateway_id = (each.value.target.type == "EGRESS_ONLY_INTERNET_GATEWAY" 143 | ? each.value.target.id 144 | : null 145 | ) 146 | gateway_id = (contains(["INTERNET_GATEWAY", "VPN_GATEWAY"], each.value.target.type) 147 | ? each.value.target.id 148 | : null 149 | ) 150 | local_gateway_id = (each.value.target.type == "LOCAL_GATEWAY" 151 | ? each.value.target.id 152 | : null 153 | ) 154 | nat_gateway_id = (each.value.target.type == "NAT_GATEWAY" 155 | ? each.value.target.id 156 | : null 157 | ) 158 | network_interface_id = (each.value.target.type == "NETWORK_INTERFACE" 159 | ? each.value.target.id 160 | : null 161 | ) 162 | transit_gateway_id = (each.value.target.type == "TRANSIT_GATEWAY" 163 | ? each.value.target.id 164 | : null 165 | ) 166 | vpc_endpoint_id = (each.value.target.type == "VPC_ENDPOINT" 167 | ? each.value.target.id 168 | : null 169 | ) 170 | vpc_peering_connection_id = (each.value.target.type == "VPC_PEERING_CONNECTION" 171 | ? each.value.target.id 172 | : null 173 | ) 174 | } 175 | -------------------------------------------------------------------------------- /modules/route-table/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "(Required) Desired name for the route table resources." 3 | type = string 4 | nullable = false 5 | } 6 | 7 | variable "vpc_id" { 8 | description = "(Required) The ID of the VPC which the route table belongs to." 9 | type = string 10 | nullable = false 11 | } 12 | 13 | variable "is_main" { 14 | description = "(Optional) Whether to set this route table as the main route table. Defaults to `false`." 15 | type = bool 16 | default = false 17 | nullable = false 18 | } 19 | 20 | variable "subnets" { 21 | description = "(Optional) A list of subnet IDs to associate with the route table." 22 | type = list(string) 23 | default = [] 24 | nullable = false 25 | } 26 | 27 | variable "gateways" { 28 | description = "(Optional) A list of gateway IDs to associate with the route table. Only support Internet Gateway and Virtual Private Gateway." 29 | type = list(string) 30 | default = [] 31 | nullable = false 32 | } 33 | 34 | variable "vpc_gateway_endpoints" { 35 | description = "(Optional) A list of the VPC Endpoint IDs with which the Route Table will be associated." 36 | type = list(string) 37 | default = [] 38 | nullable = false 39 | } 40 | 41 | variable "propagating_vpn_gateways" { 42 | description = "(Optional) A list of Virtual Private Gateway IDs to propagate routes from." 43 | type = list(string) 44 | default = [] 45 | nullable = false 46 | } 47 | 48 | variable "ipv4_routes" { 49 | description = < 10 | ## Requirements 11 | 12 | | Name | Version | 13 | |------|---------| 14 | | [terraform](#requirement\_terraform) | >= 1.6 | 15 | | [aws](#requirement\_aws) | >= 5.3 | 16 | 17 | ## Providers 18 | 19 | | Name | Version | 20 | |------|---------| 21 | | [aws](#provider\_aws) | 5.24.0 | 22 | 23 | ## Modules 24 | 25 | | Name | Source | Version | 26 | |------|--------|---------| 27 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 28 | 29 | ## Resources 30 | 31 | | Name | Type | 32 | |------|------| 33 | | [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | 34 | | [aws_vpc_security_group_egress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource | 35 | | [aws_vpc_security_group_ingress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource | 36 | 37 | ## Inputs 38 | 39 | | Name | Description | Type | Default | Required | 40 | |------|-------------|------|---------|:--------:| 41 | | [name](#input\_name) | (Required) The name of the security group. | `string` | n/a | yes | 42 | | [vpc\_id](#input\_vpc\_id) | (Required) The ID of the associated VPC. | `string` | n/a | yes | 43 | | [description](#input\_description) | (Optional) The security group description. This field maps to the AWS `GroupDescription` attribute, for which there is no Update API. | `string` | `"Managed by Terraform."` | no | 44 | | [egress\_rules](#input\_egress\_rules) | (Optional) The configuration for egress rules of the security group. Each block of `egress_rules` as defined below.
(Required) `id` - The ID of the egress rule. This value is only used internally within Terraform code.
(Optional) `description` - The description of the rule.
(Required) `protocol` - The protocol to match. Note that if `protocol` is set to `-1`, it translates to all protocols, all port ranges, and `from_port` and `to_port` values should not be defined.
(Required) `from_port` - The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type.
(Required) `to_port` - The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code.
(Optional) `ipv4_cidrs` - The IPv4 network ranges to allow, in CIDR notation.
(Optional) `ipv6_cidrs` - The IPv6 network ranges to allow, in CIDR notation.
(Optional) `prefix_lists` - The prefix list IDs to allow.
(Optional) `security_groups` - The source security group IDs to allow.
(Optional) `self` - Whether the security group itself will be added as a source to this ingress rule. |
list(object({
id = string
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(list(string), [])
ipv6_cidrs = optional(list(string), [])
prefix_lists = optional(list(string), [])
security_groups = optional(list(string), [])
self = optional(bool, false)
}))
| `[]` | no | 45 | | [ingress\_rules](#input\_ingress\_rules) | (Optional) The configuration for ingress rules of the security group. Each block of `ingress_rules` as defined below.
(Required) `id` - The ID of the ingress rule. This value is only used internally within Terraform code.
(Optional) `description` - The description of the rule.
(Required) `protocol` - The protocol to match. Note that if `protocol` is set to `-1`, it translates to all protocols, all port ranges, and `from_port` and `to_port` values should not be defined.
(Required) `from_port` - The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 type.
(Required) `to_port` - The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code.
(Optional) `ipv4_cidrs` - The IPv4 network ranges to allow, in CIDR notation.
(Optional) `ipv6_cidrs` - The IPv6 network ranges to allow, in CIDR notation.
(Optional) `prefix_lists` - The prefix list IDs to allow.
(Optional) `security_groups` - The source security group IDs to allow.
(Optional) `self` - Whether the security group itself will be added as a source to this ingress rule. |
list(object({
id = string
description = optional(string, "Managed by Terraform.")
protocol = string
from_port = number
to_port = number
ipv4_cidrs = optional(list(string), [])
ipv6_cidrs = optional(list(string), [])
prefix_lists = optional(list(string), [])
security_groups = optional(list(string), [])
self = optional(bool, false)
}))
| `[]` | no | 46 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 47 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 48 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 49 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 50 | | [revoke\_rules\_on\_delete](#input\_revoke\_rules\_on\_delete) | (Optional) Instruct Terraform to revoke all of the Security Groups attached ingress and egress rules before deleting the rule itself. This is normally not needed. | `bool` | `false` | no | 51 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 52 | 53 | ## Outputs 54 | 55 | | Name | Description | 56 | |------|-------------| 57 | | [arn](#output\_arn) | The ARN of the security group. | 58 | | [description](#output\_description) | The description of the security group. | 59 | | [egress\_rules](#output\_egress\_rules) | The configuration of the security group egress rules. | 60 | | [id](#output\_id) | The ID of the security group. | 61 | | [ingress\_rules](#output\_ingress\_rules) | The configuration of the security group ingress rules. | 62 | | [name](#output\_name) | The name of the security group. | 63 | | [owner\_id](#output\_owner\_id) | The ID of the AWS account that owns the security group. | 64 | | [vpc\_id](#output\_vpc\_id) | The ID of the associated VPC. | 65 | 66 | -------------------------------------------------------------------------------- /modules/security-group/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-network" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | 18 | ################################################### 19 | # Security Group 20 | ################################################### 21 | 22 | # INFO: Not supported attributes 23 | # - `name_prefix` 24 | # INFO: Use a separate resource 25 | # - `egress` 26 | # - `ingress` 27 | resource "aws_security_group" "this" { 28 | vpc_id = var.vpc_id 29 | 30 | name = var.name 31 | # name_prefix = var.name_prefix 32 | description = var.description 33 | 34 | revoke_rules_on_delete = var.revoke_rules_on_delete 35 | 36 | tags = merge( 37 | { 38 | "Name" = local.metadata.name 39 | }, 40 | local.module_tags, 41 | var.tags, 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /modules/security-group/migrations.tf: -------------------------------------------------------------------------------- 1 | # 2023-02-01 2 | moved { 3 | from = aws_resourcegroups_group.this[0] 4 | to = module.resource_group[0].aws_resourcegroups_group.this 5 | } 6 | -------------------------------------------------------------------------------- /modules/security-group/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the security group." 3 | value = aws_security_group.this.id 4 | } 5 | 6 | output "arn" { 7 | description = "The ARN of the security group." 8 | value = aws_security_group.this.arn 9 | } 10 | 11 | output "name" { 12 | description = "The name of the security group." 13 | value = aws_security_group.this.name 14 | } 15 | 16 | output "description" { 17 | description = "The description of the security group." 18 | value = aws_security_group.this.description 19 | } 20 | 21 | output "owner_id" { 22 | description = "The ID of the AWS account that owns the security group." 23 | value = aws_security_group.this.owner_id 24 | } 25 | 26 | output "vpc_id" { 27 | description = "The ID of the associated VPC." 28 | value = aws_security_group.this.vpc_id 29 | } 30 | 31 | output "ingress_rules" { 32 | description = < { 38 | id = rule.id 39 | arn = rule.arn 40 | description = rule.description 41 | 42 | protocol = rule.ip_protocol 43 | from_port = rule.from_port 44 | to_port = rule.to_port 45 | } 46 | } 47 | } 48 | 49 | output "egress_rules" { 50 | description = < { 56 | id = rule.id 57 | arn = rule.arn 58 | description = rule.description 59 | 60 | protocol = rule.ip_protocol 61 | from_port = rule.from_port 62 | to_port = rule.to_port 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /modules/security-group/resource-group.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | resource_group_name = (var.resource_group_name != "" 3 | ? var.resource_group_name 4 | : join(".", [ 5 | local.metadata.package, 6 | local.metadata.module, 7 | replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), 8 | ]) 9 | ) 10 | } 11 | 12 | 13 | module "resource_group" { 14 | source = "tedilabs/misc/aws//modules/resource-group" 15 | version = "~> 0.10.0" 16 | 17 | count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 18 | 19 | name = local.resource_group_name 20 | description = var.resource_group_description 21 | 22 | query = { 23 | resource_tags = local.module_tags 24 | } 25 | 26 | module_tags_enabled = false 27 | tags = merge( 28 | local.module_tags, 29 | var.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/security-group/rules.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | normalized_ingress_rules = concat([], [ 3 | for rule in var.ingress_rules : 4 | concat( 5 | [ 6 | for idx, cidr in rule.ipv4_cidrs : 7 | { 8 | id = "${rule.id}/ipv4/${idx}" 9 | description = rule.description 10 | 11 | protocol = rule.protocol 12 | from_port = rule.from_port 13 | to_port = rule.to_port 14 | 15 | ipv4_cidr = cidr 16 | ipv6_cidr = null 17 | prefix_list = null 18 | security_group = null 19 | } 20 | ], 21 | [ 22 | for idx, cidr in rule.ipv6_cidrs : 23 | { 24 | id = "${rule.id}/ipv6/${idx}" 25 | description = rule.description 26 | 27 | protocol = rule.protocol 28 | from_port = rule.from_port 29 | to_port = rule.to_port 30 | 31 | ipv4_cidr = null 32 | ipv6_cidr = cidr 33 | prefix_list = null 34 | security_group = null 35 | } 36 | ], 37 | [ 38 | for idx, prefix_list in rule.prefix_lists : 39 | { 40 | id = "${rule.id}/prefix-list/${idx}" 41 | description = rule.description 42 | 43 | protocol = rule.protocol 44 | from_port = rule.from_port 45 | to_port = rule.to_port 46 | 47 | ipv4_cidr = null 48 | ipv6_cidr = null 49 | prefix_list = prefix_list 50 | security_group = null 51 | } 52 | ], 53 | [ 54 | for idx, security_group in rule.security_groups : 55 | { 56 | id = "${rule.id}/security-group/${idx}" 57 | description = rule.description 58 | 59 | protocol = rule.protocol 60 | from_port = rule.from_port 61 | to_port = rule.to_port 62 | 63 | ipv4_cidr = null 64 | ipv6_cidr = null 65 | prefix_list = null 66 | security_group = security_group 67 | } 68 | ], 69 | [ 70 | for self in [rule.self] : 71 | { 72 | id = "${rule.id}/self" 73 | description = rule.description 74 | 75 | protocol = rule.protocol 76 | from_port = rule.from_port 77 | to_port = rule.to_port 78 | 79 | ipv4_cidr = null 80 | ipv6_cidr = null 81 | prefix_list = null 82 | security_group = aws_security_group.this.id 83 | } 84 | if self 85 | ] 86 | ) 87 | ]...) 88 | normalized_egress_rules = concat([], [ 89 | for rule in var.egress_rules : 90 | concat( 91 | [ 92 | for idx, cidr in rule.ipv4_cidrs : 93 | { 94 | id = "${rule.id}/ipv4/${idx}" 95 | description = rule.description 96 | 97 | protocol = rule.protocol 98 | from_port = rule.from_port 99 | to_port = rule.to_port 100 | 101 | ipv4_cidr = cidr 102 | ipv6_cidr = null 103 | prefix_list = null 104 | security_group = null 105 | } 106 | ], 107 | [ 108 | for idx, cidr in rule.ipv6_cidrs : 109 | { 110 | id = "${rule.id}/ipv6/${idx}" 111 | description = rule.description 112 | 113 | protocol = rule.protocol 114 | from_port = rule.from_port 115 | to_port = rule.to_port 116 | 117 | ipv4_cidr = null 118 | ipv6_cidr = cidr 119 | prefix_list = null 120 | security_group = null 121 | } 122 | ], 123 | [ 124 | for idx, prefix_list in rule.prefix_lists : 125 | { 126 | id = "${rule.id}/prefix-list/${idx}" 127 | description = rule.description 128 | 129 | protocol = rule.protocol 130 | from_port = rule.from_port 131 | to_port = rule.to_port 132 | 133 | ipv4_cidr = null 134 | ipv6_cidr = null 135 | prefix_list = prefix_list 136 | security_group = null 137 | } 138 | ], 139 | [ 140 | for idx, security_group in rule.security_groups : 141 | { 142 | id = "${rule.id}/security-group/${idx}" 143 | description = rule.description 144 | 145 | protocol = rule.protocol 146 | from_port = rule.from_port 147 | to_port = rule.to_port 148 | 149 | ipv4_cidr = null 150 | ipv6_cidr = null 151 | prefix_list = null 152 | security_group = security_group 153 | } 154 | ], 155 | [ 156 | for self in [rule.self] : 157 | { 158 | id = "${rule.id}/self" 159 | description = rule.description 160 | 161 | protocol = rule.protocol 162 | from_port = rule.from_port 163 | to_port = rule.to_port 164 | 165 | ipv4_cidr = null 166 | ipv6_cidr = null 167 | prefix_list = null 168 | security_group = aws_security_group.this.id 169 | } 170 | if self 171 | ] 172 | ) 173 | ]...) 174 | } 175 | 176 | 177 | ################################################### 178 | # Ingress Rules for Security Group 179 | ################################################### 180 | 181 | resource "aws_vpc_security_group_ingress_rule" "this" { 182 | for_each = { 183 | for rule in local.normalized_ingress_rules : 184 | rule.id => rule 185 | } 186 | 187 | security_group_id = aws_security_group.this.id 188 | description = each.value.description 189 | 190 | ip_protocol = each.value.protocol 191 | from_port = (contains(["all", "-1"], each.value.protocol) 192 | ? null 193 | : each.value.from_port 194 | ) 195 | to_port = (contains(["all", "-1"], each.value.protocol) 196 | ? null 197 | : each.value.to_port 198 | ) 199 | 200 | cidr_ipv4 = each.value.ipv4_cidr 201 | cidr_ipv6 = each.value.ipv6_cidr 202 | prefix_list_id = each.value.prefix_list 203 | referenced_security_group_id = each.value.security_group 204 | 205 | tags = merge( 206 | { 207 | "Name" = each.key 208 | }, 209 | local.module_tags, 210 | var.tags, 211 | ) 212 | } 213 | 214 | 215 | ################################################### 216 | # Egress Rules for Security Group 217 | ################################################### 218 | 219 | resource "aws_vpc_security_group_egress_rule" "this" { 220 | for_each = { 221 | for rule in local.normalized_egress_rules : 222 | rule.id => rule 223 | } 224 | 225 | security_group_id = aws_security_group.this.id 226 | description = each.value.description 227 | 228 | ip_protocol = each.value.protocol 229 | from_port = (contains(["all", "-1"], each.value.protocol) 230 | ? null 231 | : each.value.from_port 232 | ) 233 | to_port = (contains(["all", "-1"], each.value.protocol) 234 | ? null 235 | : each.value.to_port 236 | ) 237 | 238 | cidr_ipv4 = each.value.ipv4_cidr 239 | cidr_ipv6 = each.value.ipv6_cidr 240 | prefix_list_id = each.value.prefix_list 241 | referenced_security_group_id = each.value.security_group 242 | 243 | tags = merge( 244 | { 245 | "Name" = each.key 246 | }, 247 | local.module_tags, 248 | var.tags, 249 | ) 250 | } 251 | -------------------------------------------------------------------------------- /modules/security-group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "(Required) The name of the security group." 3 | type = string 4 | nullable = false 5 | } 6 | 7 | # variable "name_prefix" { 8 | # description = "(Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`." 9 | # type = string 10 | # default = null 11 | # nullable = true 12 | # } 13 | 14 | variable "description" { 15 | description = "(Optional) The security group description. This field maps to the AWS `GroupDescription` attribute, for which there is no Update API." 16 | type = string 17 | default = "Managed by Terraform." 18 | nullable = false 19 | } 20 | 21 | variable "vpc_id" { 22 | description = "(Required) The ID of the associated VPC." 23 | type = string 24 | nullable = false 25 | } 26 | 27 | variable "revoke_rules_on_delete" { 28 | description = "(Optional) Instruct Terraform to revoke all of the Security Groups attached ingress and egress rules before deleting the rule itself. This is normally not needed." 29 | type = bool 30 | default = false 31 | nullable = false 32 | } 33 | 34 | variable "ingress_rules" { 35 | description = < 0, 68 | length(rule.ipv6_cidrs) > 0, 69 | length(rule.prefix_lists) > 0, 70 | length(rule.security_groups) > 0, 71 | rule.self, 72 | ]) 73 | ]) 74 | error_message = "At least one of `ipv4_cidrs`, `ipv6_cidrs`, `prefix_lists`, `security_groups` or `self` must be specified." 75 | } 76 | } 77 | 78 | variable "egress_rules" { 79 | description = < 0, 112 | length(rule.ipv6_cidrs) > 0, 113 | length(rule.prefix_lists) > 0, 114 | length(rule.security_groups) > 0, 115 | rule.self, 116 | ]) 117 | ]) 118 | error_message = "At least one of `ipv4_cidrs`, `ipv6_cidrs`, `prefix_lists`, `security_groups` or `self` must be specified." 119 | } 120 | } 121 | 122 | variable "tags" { 123 | description = "(Optional) A map of tags to add to all resources." 124 | type = map(string) 125 | default = {} 126 | nullable = false 127 | } 128 | 129 | variable "module_tags_enabled" { 130 | description = "(Optional) Whether to create AWS Resource Tags for the module informations." 131 | type = bool 132 | default = true 133 | nullable = false 134 | } 135 | 136 | 137 | ################################################### 138 | # Resource Group 139 | ################################################### 140 | 141 | variable "resource_group_enabled" { 142 | description = "(Optional) Whether to create Resource Group to find and group AWS resources which are created by this module." 143 | type = bool 144 | default = true 145 | nullable = false 146 | } 147 | 148 | variable "resource_group_name" { 149 | description = "(Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`." 150 | type = string 151 | default = "" 152 | nullable = false 153 | } 154 | 155 | variable "resource_group_description" { 156 | description = "(Optional) The description of Resource Group." 157 | type = string 158 | default = "Managed by Terraform." 159 | nullable = false 160 | } 161 | -------------------------------------------------------------------------------- /modules/security-group/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.6" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/subnet-group/integrations.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "this" {} 2 | 3 | locals { 4 | account_id = data.aws_caller_identity.this.account_id 5 | } 6 | 7 | 8 | ################################################### 9 | # VPC Attachments for Transit Gateway 10 | ################################################### 11 | 12 | data "aws_ec2_transit_gateway" "this" { 13 | for_each = { 14 | for attachment in var.transit_gateway_attachments : 15 | attachment.name => attachment.transit_gateway 16 | } 17 | 18 | filter { 19 | name = "transit-gateway-id" 20 | values = [each.value] 21 | } 22 | } 23 | 24 | resource "aws_ec2_transit_gateway_vpc_attachment" "this" { 25 | for_each = { 26 | for attachment in var.transit_gateway_attachments : 27 | attachment.name => attachment 28 | } 29 | 30 | vpc_id = var.vpc_id 31 | subnet_ids = values(aws_subnet.this)[*].id 32 | 33 | transit_gateway_id = each.value.transit_gateway 34 | 35 | appliance_mode_support = each.value.appliance_mode_enabled ? "enable" : "disable" 36 | dns_support = each.value.dns_support_enabled ? "enable" : "disable" 37 | ipv6_support = each.value.ipv6_enabled ? "enable" : "disable" 38 | transit_gateway_default_route_table_association = (local.account_id == data.aws_ec2_transit_gateway.this[each.key].owner_id 39 | ? each.value.default_association_route_table_enabled 40 | : null 41 | ) 42 | transit_gateway_default_route_table_propagation = (local.account_id == data.aws_ec2_transit_gateway.this[each.key].owner_id 43 | ? each.value.default_propagation_route_table_enabled 44 | : null 45 | ) 46 | 47 | tags = merge( 48 | { 49 | "Name" = each.key 50 | }, 51 | local.module_tags, 52 | var.tags, 53 | each.value.tags, 54 | ) 55 | } 56 | 57 | 58 | ################################################### 59 | # Subnet Group for DAX 60 | ################################################### 61 | 62 | resource "aws_dax_subnet_group" "this" { 63 | count = var.dax_subnet_group.enabled ? 1 : 0 64 | 65 | name = coalesce(var.dax_subnet_group.name, var.name) 66 | description = var.dax_subnet_group.description 67 | 68 | subnet_ids = values(aws_subnet.this)[*].id 69 | 70 | # INFO: Not support resource tags 71 | # tags = {} 72 | } 73 | 74 | 75 | ################################################### 76 | # Subnet Group for DMS Replication 77 | ################################################### 78 | 79 | resource "aws_dms_replication_subnet_group" "this" { 80 | count = var.dms_replication_subnet_group.enabled ? 1 : 0 81 | 82 | replication_subnet_group_id = coalesce(var.dms_replication_subnet_group.name, var.name) 83 | replication_subnet_group_description = var.dms_replication_subnet_group.description 84 | 85 | subnet_ids = values(aws_subnet.this)[*].id 86 | 87 | tags = merge( 88 | { 89 | "Name" = coalesce(var.dms_replication_subnet_group.name, var.name) 90 | }, 91 | local.module_tags, 92 | var.tags, 93 | ) 94 | } 95 | 96 | 97 | ################################################### 98 | # Subnet Group for DocumentDB 99 | ################################################### 100 | 101 | resource "aws_docdb_subnet_group" "this" { 102 | count = var.docdb_subnet_group.enabled ? 1 : 0 103 | 104 | name = coalesce(var.docdb_subnet_group.name, var.name) 105 | description = var.docdb_subnet_group.description 106 | 107 | subnet_ids = values(aws_subnet.this)[*].id 108 | 109 | tags = merge( 110 | { 111 | "Name" = coalesce(var.docdb_subnet_group.name, var.name) 112 | }, 113 | local.module_tags, 114 | var.tags, 115 | ) 116 | } 117 | 118 | 119 | ################################################### 120 | # Subnet Group for ElastiCache 121 | ################################################### 122 | 123 | resource "aws_elasticache_subnet_group" "this" { 124 | count = var.elasticache_subnet_group.enabled ? 1 : 0 125 | 126 | name = coalesce(var.elasticache_subnet_group.name, var.name) 127 | description = var.elasticache_subnet_group.description 128 | 129 | subnet_ids = values(aws_subnet.this)[*].id 130 | 131 | tags = merge( 132 | { 133 | "Name" = coalesce(var.elasticache_subnet_group.name, var.name) 134 | }, 135 | local.module_tags, 136 | var.tags, 137 | ) 138 | } 139 | 140 | 141 | ################################################### 142 | # Subnet Group for MemoryDB 143 | ################################################### 144 | 145 | resource "aws_memorydb_subnet_group" "this" { 146 | count = var.memorydb_subnet_group.enabled ? 1 : 0 147 | 148 | name = coalesce(var.memorydb_subnet_group.name, var.name) 149 | description = var.memorydb_subnet_group.description 150 | 151 | subnet_ids = values(aws_subnet.this)[*].id 152 | 153 | tags = merge( 154 | { 155 | "Name" = coalesce(var.memorydb_subnet_group.name, var.name) 156 | }, 157 | local.module_tags, 158 | var.tags, 159 | ) 160 | } 161 | 162 | 163 | ################################################### 164 | # Subnet Group for Neptune 165 | ################################################### 166 | 167 | resource "aws_neptune_subnet_group" "this" { 168 | count = var.neptune_subnet_group.enabled ? 1 : 0 169 | 170 | name = coalesce(var.neptune_subnet_group.name, var.name) 171 | description = var.neptune_subnet_group.description 172 | 173 | subnet_ids = values(aws_subnet.this)[*].id 174 | 175 | tags = merge( 176 | { 177 | "Name" = coalesce(var.neptune_subnet_group.name, var.name) 178 | }, 179 | local.module_tags, 180 | var.tags, 181 | ) 182 | } 183 | 184 | 185 | ################################################### 186 | # Subnet Group for RDS 187 | ################################################### 188 | 189 | resource "aws_db_subnet_group" "this" { 190 | count = var.rds_subnet_group.enabled ? 1 : 0 191 | 192 | name = coalesce(var.rds_subnet_group.name, var.name) 193 | description = var.rds_subnet_group.description 194 | 195 | subnet_ids = values(aws_subnet.this)[*].id 196 | 197 | tags = merge( 198 | { 199 | "Name" = coalesce(var.rds_subnet_group.name, var.name) 200 | }, 201 | local.module_tags, 202 | var.tags, 203 | ) 204 | } 205 | 206 | 207 | ################################################### 208 | # Subnet Group for Redshift 209 | ################################################### 210 | 211 | resource "aws_redshift_subnet_group" "this" { 212 | count = var.redshift_subnet_group.enabled ? 1 : 0 213 | 214 | name = coalesce(var.redshift_subnet_group.name, var.name) 215 | description = var.redshift_subnet_group.description 216 | 217 | subnet_ids = values(aws_subnet.this)[*].id 218 | 219 | tags = merge( 220 | { 221 | "Name" = coalesce(var.redshift_subnet_group.name, var.name) 222 | }, 223 | local.module_tags, 224 | var.tags, 225 | ) 226 | } 227 | -------------------------------------------------------------------------------- /modules/subnet-group/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-network" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | data "aws_availability_zones" "available" { 18 | state = "available" 19 | } 20 | 21 | locals { 22 | available_availablity_zones = data.aws_availability_zones.available.names 23 | available_availablity_zone_ids = data.aws_availability_zones.available.zone_ids 24 | 25 | az = { 26 | for idx, id in local.available_availablity_zone_ids : 27 | id => local.available_availablity_zones[idx] 28 | } 29 | 30 | hostname_types = { 31 | "RESOURCE_NAME" = "resource-name" 32 | "IP_NAME" = "ip-name" 33 | } 34 | } 35 | 36 | locals { 37 | availability_zones = distinct( 38 | values(aws_subnet.this)[*].availability_zone 39 | ) 40 | availability_zone_ids = distinct( 41 | values(aws_subnet.this)[*].availability_zone_id 42 | ) 43 | subnets = [ 44 | for name, subnet in aws_subnet.this : { 45 | id = subnet.id 46 | arn = subnet.arn 47 | name = name 48 | 49 | availability_zone = subnet.availability_zone 50 | availability_zone_id = subnet.availability_zone_id 51 | 52 | ipv4_cidr = subnet.cidr_block 53 | ipv6_cidr = subnet.ipv6_cidr_block 54 | } 55 | ] 56 | } 57 | 58 | 59 | ################################################### 60 | # Subnets of the Subnet Group 61 | ################################################### 62 | 63 | resource "aws_subnet" "this" { 64 | for_each = var.subnets 65 | 66 | vpc_id = var.vpc_id 67 | availability_zone = each.value.availability_zone 68 | availability_zone_id = each.value.availability_zone_id 69 | 70 | enable_lni_at_device_index = var.local_network_interface_device_index 71 | 72 | 73 | ## IP CIDR Blocks 74 | ipv6_native = each.value.type == "IPV6" 75 | 76 | cidr_block = each.value.ipv4_cidr 77 | ipv6_cidr_block = each.value.ipv6_cidr 78 | 79 | 80 | ## IP Assignments 81 | map_public_ip_on_launch = (each.value.type == "IPV6" 82 | ? false 83 | : var.public_ipv4_address_assignment.enabled 84 | ) 85 | assign_ipv6_address_on_creation = (each.value.type == "IPV6" 86 | ? true 87 | : var.ipv6_address_assignment.enabled 88 | ) 89 | map_customer_owned_ip_on_launch = (each.value.type == "IPV6" 90 | ? null 91 | : (var.customer_owned_ipv4_address_assignment.enabled 92 | ? true 93 | : null 94 | ) 95 | ) 96 | outpost_arn = (var.customer_owned_ipv4_address_assignment.enabled 97 | ? var.customer_owned_ipv4_address_assignment.outpost 98 | : null 99 | ) 100 | customer_owned_ipv4_pool = (var.customer_owned_ipv4_address_assignment.enabled 101 | ? var.customer_owned_ipv4_address_assignment.pool 102 | : null 103 | ) 104 | 105 | 106 | ## DNS Configurations 107 | private_dns_hostname_type_on_launch = (each.value.type == "IPV6" 108 | ? "resource-name" 109 | : local.hostname_types[var.dns_config.hostname_type] 110 | ) 111 | enable_resource_name_dns_a_record_on_launch = (each.value.type == "IPV6" 112 | ? false 113 | : var.dns_config.dns_resource_name_ipv4_enabled 114 | ) 115 | enable_resource_name_dns_aaaa_record_on_launch = (each.value.type == "IPV6" 116 | ? true 117 | : var.dns_config.dns_resource_name_ipv6_enabled 118 | ) 119 | enable_dns64 = var.dns_config.dns64_enabled 120 | 121 | 122 | timeouts { 123 | create = var.timeouts.create 124 | delete = var.timeouts.delete 125 | } 126 | 127 | tags = merge( 128 | { 129 | "Name" = each.key 130 | }, 131 | local.module_tags, 132 | var.tags, 133 | ) 134 | } 135 | -------------------------------------------------------------------------------- /modules/subnet-group/migrations.tf: -------------------------------------------------------------------------------- 1 | # 2023-02-01 2 | moved { 3 | from = aws_resourcegroups_group.this[0] 4 | to = module.resource_group[0].aws_resourcegroups_group.this 5 | } 6 | -------------------------------------------------------------------------------- /modules/subnet-group/outputs.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | description = "The name of the subnet group." 3 | value = var.name 4 | } 5 | 6 | output "vpc_id" { 7 | description = "The ID of the VPC which the subnet group belongs to." 8 | value = values(aws_subnet.this)[0].vpc_id 9 | } 10 | 11 | output "ids" { 12 | description = "A list of IDs of subnets" 13 | value = values(aws_subnet.this)[*].id 14 | } 15 | 16 | output "arns" { 17 | description = "A list of ARNs of subnets" 18 | value = values(aws_subnet.this)[*].arn 19 | } 20 | 21 | output "owner" { 22 | description = "The ID of the AWS account that owns subnets in the subnet group." 23 | value = values(aws_subnet.this)[0].owner_id 24 | } 25 | 26 | output "ipv4_cidrs" { 27 | description = "The IPv4 CIDR blocks of the subnet group." 28 | value = compact(values(aws_subnet.this)[*].cidr_block) 29 | } 30 | 31 | output "ipv6_cidrs" { 32 | description = "The IPv6 CIDR blocks of the subnet group." 33 | value = compact(values(aws_subnet.this)[*].ipv6_cidr_block) 34 | } 35 | 36 | output "availability_zones" { 37 | description = "A list of availability zones which the subnet group uses." 38 | value = local.availability_zones 39 | } 40 | 41 | output "availability_zone_ids" { 42 | description = "A list of availability zone IDs which the subnet group uses." 43 | value = local.availability_zone_ids 44 | } 45 | 46 | output "subnets" { 47 | description = "A list of subnets of the subnet group." 48 | value = local.subnets 49 | } 50 | 51 | output "subnets_by_az" { 52 | description = "A map of subnets of the subnet group which are grouped by availability zone id." 53 | value = { 54 | for subnet in local.subnets : 55 | subnet.availability_zone_id => subnet... 56 | } 57 | } 58 | 59 | output "local_network_interface_device_index" { 60 | description = "The device position for local network interfaces in this subnet." 61 | value = var.local_network_interface_device_index 62 | } 63 | 64 | output "public_ipv4_address_assignment" { 65 | description = < k 107 | }[values(aws_subnet.this)[0].private_dns_hostname_type_on_launch] 108 | dns_resource_name_ipv4_enabled = values(aws_subnet.this)[0].enable_resource_name_dns_a_record_on_launch 109 | dns_resource_name_ipv6_enabled = values(aws_subnet.this)[0].enable_resource_name_dns_aaaa_record_on_launch 110 | dns64_enabled = values(aws_subnet.this)[0].enable_dns64 111 | } 112 | } 113 | 114 | output "transit_gateway_attachments" { 115 | description = < { 121 | name = name 122 | transit_gateway = attachment.transit_gateway_id 123 | 124 | appliance_mode_enabled = attachment.appliance_mode_support == "enable" 125 | dns_support_enabled = attachment.dns_support == "enable" 126 | ipv6_enabled = attachment.ipv6_support == "enable" 127 | default_association_route_table_enabled = attachment.transit_gateway_default_route_table_association 128 | default_propagation_route_table_enabled = attachment.transit_gateway_default_route_table_propagation 129 | } 130 | } 131 | } 132 | 133 | output "dax_subnet_group" { 134 | description = < 0 ? "SHARED_BY_ME" : "NOT_SHARED" 293 | shares = module.share 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /modules/subnet-group/ram-share.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # Resource Sharing by RAM (Resource Access Manager) 3 | ################################################### 4 | 5 | module "share" { 6 | source = "tedilabs/account/aws//modules/ram-share" 7 | version = "~> 0.27.0" 8 | 9 | for_each = { 10 | for share in var.shares : 11 | share.name => share 12 | } 13 | 14 | name = "vpc.subnet-group.${var.name}.${each.key}" 15 | 16 | resources = values(aws_subnet.this)[*].arn 17 | 18 | permissions = each.value.permissions 19 | 20 | external_principals_allowed = each.value.external_principals_allowed 21 | principals = each.value.principals 22 | 23 | resource_group_enabled = false 24 | module_tags_enabled = false 25 | 26 | tags = merge( 27 | local.module_tags, 28 | var.tags, 29 | each.value.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/subnet-group/resource-group.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | resource_group_name = (var.resource_group_name != "" 3 | ? var.resource_group_name 4 | : join(".", [ 5 | local.metadata.package, 6 | local.metadata.module, 7 | replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), 8 | ]) 9 | ) 10 | } 11 | 12 | 13 | module "resource_group" { 14 | source = "tedilabs/misc/aws//modules/resource-group" 15 | version = "~> 0.10.0" 16 | 17 | count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 18 | 19 | name = local.resource_group_name 20 | description = var.resource_group_description 21 | 22 | query = { 23 | resource_tags = local.module_tags 24 | } 25 | 26 | module_tags_enabled = false 27 | tags = merge( 28 | local.module_tags, 29 | var.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/subnet-group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "(Required) The name of the subnet group." 3 | type = string 4 | nullable = false 5 | } 6 | 7 | variable "vpc_id" { 8 | description = "(Required) The ID of the VPC which the subnet group belongs to." 9 | type = string 10 | nullable = false 11 | } 12 | 13 | variable "subnets" { 14 | description = < 0 35 | error_message = "At least one subnet must be provided." 36 | } 37 | validation { 38 | condition = alltrue([ 39 | for subnet in values(var.subnets) : 40 | contains(["DUALSTACK", "IPV6"], subnet.type) 41 | ]) 42 | error_message = "Valid values for `type` of each subnet are `DUALSTACK` and `IPV6`." 43 | } 44 | validation { 45 | condition = alltrue([ 46 | for subnet in values(var.subnets) : 47 | subnet.ipv4_cidr != null 48 | if subnet.type == "DUALSTACK" 49 | ]) 50 | error_message = "IPv4 CIDR block must be provided for `DUALSTACK` subnet." 51 | } 52 | validation { 53 | condition = alltrue([ 54 | for subnet in values(var.subnets) : 55 | subnet.ipv6_cidr != null && subnet.ipv4_cidr == null 56 | if subnet.type == "IPV6" 57 | ]) 58 | error_message = "IPv6 CIDR block must be provided for `IPV6` subnet." 59 | } 60 | } 61 | 62 | variable "local_network_interface_device_index" { 63 | description = < 0 21 | ? var.dhcp_options.domain_name 22 | : local.default_dhcp_options_domain_name 23 | ) 24 | domain_name_servers = var.dhcp_options.domain_name_servers 25 | ipv6_address_preferred_lease_time = var.dhcp_options.ipv6_address_preferred_lease_time 26 | ntp_servers = var.dhcp_options.ntp_servers 27 | netbios_name_servers = var.dhcp_options.netbios_name_servers 28 | netbios_node_type = var.dhcp_options.netbios_node_type 29 | 30 | tags = merge( 31 | { 32 | "Name" = coalesce(var.dhcp_options.name, local.metadata.name) 33 | }, 34 | local.module_tags, 35 | var.tags, 36 | ) 37 | 38 | lifecycle { 39 | create_before_destroy = true 40 | } 41 | } 42 | 43 | resource "aws_vpc_dhcp_options_association" "this" { 44 | count = var.dhcp_options.enabled ? 1 : 0 45 | 46 | vpc_id = aws_vpc.this.id 47 | dhcp_options_id = aws_vpc_dhcp_options.this[0].id 48 | } 49 | -------------------------------------------------------------------------------- /modules/vpc/gateways.tf: -------------------------------------------------------------------------------- 1 | ################################################### 2 | # Internet Gateway 3 | ################################################### 4 | 5 | # INFO: Not supported attributes 6 | # - `vpc_id` 7 | resource "aws_internet_gateway" "this" { 8 | count = var.internet_gateway.enabled ? 1 : 0 9 | 10 | tags = merge( 11 | { 12 | "Name" = coalesce(var.internet_gateway.name, local.metadata.name) 13 | }, 14 | local.module_tags, 15 | var.tags, 16 | ) 17 | } 18 | 19 | resource "aws_internet_gateway_attachment" "this" { 20 | count = var.internet_gateway.enabled ? 1 : 0 21 | 22 | vpc_id = aws_vpc.this.id 23 | internet_gateway_id = aws_internet_gateway.this[0].id 24 | } 25 | 26 | 27 | ################################################### 28 | # Egress Only Internet Gateway (IPv6) 29 | ################################################### 30 | 31 | resource "aws_egress_only_internet_gateway" "this" { 32 | count = var.egress_only_internet_gateway.enabled ? 1 : 0 33 | 34 | vpc_id = aws_vpc.this.id 35 | 36 | tags = merge( 37 | { 38 | "Name" = coalesce(var.egress_only_internet_gateway.name, local.metadata.name) 39 | }, 40 | local.module_tags, 41 | var.tags, 42 | ) 43 | 44 | lifecycle { 45 | precondition { 46 | condition = local.ipv6_enabled 47 | error_message = "Egress Only Internet Gateway (IPv6) cannot be enabled if IPv6 is not enabled." 48 | } 49 | } 50 | } 51 | 52 | 53 | ################################################### 54 | # Virtual Private Gateway 55 | ################################################### 56 | 57 | # INFO: Not supported attributes 58 | # - `vpc_id` 59 | # - `availability_zone` 60 | resource "aws_vpn_gateway" "this" { 61 | count = var.vpn_gateway.enabled ? 1 : 0 62 | 63 | amazon_side_asn = var.vpn_gateway.asn 64 | 65 | tags = merge( 66 | { 67 | "Name" = coalesce(var.vpn_gateway.name, local.metadata.name) 68 | }, 69 | local.module_tags, 70 | var.tags, 71 | ) 72 | } 73 | 74 | resource "aws_vpn_gateway_attachment" "this" { 75 | count = var.vpn_gateway.enabled ? 1 : 0 76 | 77 | vpc_id = aws_vpc.this.id 78 | vpn_gateway_id = aws_vpn_gateway.this[0].id 79 | } 80 | -------------------------------------------------------------------------------- /modules/vpc/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-network" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | locals { 18 | ipv4_secondary_cidrs = slice(var.ipv4_cidrs, 1, length(var.ipv4_cidrs)) 19 | ipv6_enabled = length(var.ipv6_cidrs) > 0 20 | tenancy = { 21 | "DEFAULT" = "default" 22 | "DEDICATED" = "dedicated" 23 | } 24 | } 25 | 26 | 27 | ################################################### 28 | # VPC 29 | ################################################### 30 | 31 | resource "aws_vpc" "this" { 32 | ## IPv4 CIDR Blocks 33 | cidr_block = (var.ipv4_cidrs[0].type == "MANUAL" 34 | ? var.ipv4_cidrs[0].cidr 35 | : null 36 | ) 37 | ipv4_ipam_pool_id = (var.ipv4_cidrs[0].type == "IPAM_POOL" 38 | ? var.ipv4_cidrs[0].ipam_pool.id 39 | : null 40 | ) 41 | ipv4_netmask_length = (var.ipv4_cidrs[0].type == "IPAM_POOL" 42 | ? var.ipv4_cidrs[0].ipam_pool.netmask_length 43 | : null 44 | ) 45 | 46 | 47 | ## IPv6 CIDR Blocks 48 | # TODO: Want to manage IPv6 CIDRs with `aws_vpc_ipv6_cidr_block_association` resource. But, there are unsupported featrues yet. 49 | assign_generated_ipv6_cidr_block = (local.ipv6_enabled 50 | ? (var.ipv6_cidrs[0].type == "AMAZON" 51 | ? true 52 | : null 53 | ) 54 | : null 55 | ) 56 | ipv6_cidr_block_network_border_group = (local.ipv6_enabled 57 | ? (var.ipv6_cidrs[0].type == "AMAZON" 58 | ? var.ipv6_cidrs[0].amazon.network_border_group 59 | : null 60 | ) 61 | : null 62 | ) 63 | ipv6_ipam_pool_id = (local.ipv6_enabled 64 | ? (var.ipv6_cidrs[0].type == "IPAM_POOL" 65 | ? var.ipv6_cidrs[0].ipam_pool.id 66 | : null 67 | ) 68 | : null 69 | ) 70 | ipv6_cidr_block = (local.ipv6_enabled 71 | ? (var.ipv6_cidrs[0].type == "IPAM_POOL" 72 | ? var.ipv6_cidrs[0].ipam_pool.cidr 73 | : null 74 | ) 75 | : null 76 | ) 77 | ipv6_netmask_length = (local.ipv6_enabled 78 | ? (var.ipv6_cidrs[0].type == "IPAM_POOL" 79 | ? var.ipv6_cidrs[0].ipam_pool.netmask_length 80 | : null 81 | ) 82 | : null 83 | ) 84 | 85 | 86 | ## Attributes 87 | instance_tenancy = local.tenancy[var.tenancy] 88 | 89 | enable_network_address_usage_metrics = var.network_address_usage_metrics_enabled 90 | 91 | enable_dns_hostnames = var.dns_hostnames_enabled 92 | enable_dns_support = var.dns_resolution_enabled 93 | 94 | tags = merge( 95 | { 96 | "Name" = local.metadata.name 97 | }, 98 | local.module_tags, 99 | var.tags, 100 | ) 101 | } 102 | 103 | 104 | ################################################### 105 | # Additional CIDR Blocks for the VPC 106 | ################################################### 107 | 108 | resource "aws_vpc_ipv4_cidr_block_association" "this" { 109 | count = length(var.ipv4_cidrs) > 0 ? length(var.ipv4_cidrs) - 1 : 0 110 | 111 | vpc_id = aws_vpc.this.id 112 | cidr_block = (var.ipv4_cidrs[count.index + 1].type == "MANUAL" 113 | ? var.ipv4_cidrs[count.index + 1].cidr 114 | : null 115 | ) 116 | ipv4_ipam_pool_id = (var.ipv4_cidrs[count.index + 1].type == "IPAM_POOL" 117 | ? var.ipv4_cidrs[count.index + 1].ipam_pool.id 118 | : null 119 | ) 120 | ipv4_netmask_length = (var.ipv4_cidrs[count.index + 1].type == "IPAM_POOL" 121 | ? var.ipv4_cidrs[count.index + 1].ipam_pool.netmask_length 122 | : null 123 | ) 124 | } 125 | 126 | resource "aws_vpc_ipv6_cidr_block_association" "this" { 127 | count = length(var.ipv6_cidrs) > 0 ? length(var.ipv6_cidrs) - 1 : 0 128 | 129 | vpc_id = aws_vpc.this.id 130 | ipv6_cidr_block = (var.ipv6_cidrs[count.index + 1].type == "IPAM_POOL" 131 | ? var.ipv6_cidrs[count.index + 1].ipam_pool.cidr 132 | : null 133 | ) 134 | ipv6_ipam_pool_id = (var.ipv6_cidrs[count.index + 1].type == "IPAM_POOL" 135 | ? var.ipv6_cidrs[count.index + 1].ipam_pool.id 136 | : null 137 | ) 138 | ipv6_netmask_length = (var.ipv6_cidrs[count.index + 1].type == "IPAM_POOL" 139 | ? var.ipv6_cidrs[count.index + 1].ipam_pool.netmask_length 140 | : null 141 | ) 142 | } 143 | -------------------------------------------------------------------------------- /modules/vpc/migrations.tf: -------------------------------------------------------------------------------- 1 | # 2023-02-01 2 | moved { 3 | from = aws_resourcegroups_group.this[0] 4 | to = module.resource_group[0].aws_resourcegroups_group.this 5 | } 6 | -------------------------------------------------------------------------------- /modules/vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | description = "The name of the VPC." 3 | value = var.name 4 | } 5 | 6 | output "owner" { 7 | description = "The ID of the AWS account that owns the VPC." 8 | value = aws_vpc.this.owner_id 9 | } 10 | 11 | output "id" { 12 | description = "The ID of the VPC." 13 | value = aws_vpc.this.id 14 | } 15 | 16 | output "arn" { 17 | description = "The ARN (Amazon Resource Name) of the VPC." 18 | value = aws_vpc.this.arn 19 | } 20 | 21 | output "ipv4_cidrs" { 22 | description = "The list of IPv4 CIDR blocks for the VPC." 23 | value = concat( 24 | [aws_vpc.this.cidr_block], 25 | [ 26 | for association in aws_vpc_ipv4_cidr_block_association.this : 27 | association.cidr_block 28 | ] 29 | ) 30 | } 31 | 32 | output "ipv4_cidr_configurations" { 33 | description = "The list of IPv4 CIDR configurations for the VPC." 34 | value = merge({ 35 | (aws_vpc.this.cidr_block) = { 36 | type = aws_vpc.this.ipv4_ipam_pool_id != null ? "IPAM_POOL" : "MANUAL" 37 | 38 | ipam_pool = (aws_vpc.this.ipv4_ipam_pool_id != null 39 | ? { 40 | id = aws_vpc.this.ipv4_ipam_pool_id 41 | netmask_length = aws_vpc.this.ipv4_netmask_length 42 | } 43 | : null 44 | ) 45 | }, 46 | }, { 47 | for association in aws_vpc_ipv4_cidr_block_association.this : 48 | (association.cidr_block) => { 49 | type = association.ipv4_ipam_pool_id != null ? "IPAM_POOL" : "MANUAL" 50 | ipam_pool = (association.ipv4_ipam_pool_id != null 51 | ? { 52 | id = association.ipv4_ipam_pool_id 53 | netmask_length = association.ipv4_netmask_length 54 | } 55 | : null 56 | ) 57 | } 58 | }) 59 | } 60 | 61 | output "ipv6_cidrs" { 62 | description = "The list of IPv6 CIDR blocks for the VPC." 63 | value = (local.ipv6_enabled 64 | ? concat( 65 | [aws_vpc.this.ipv6_cidr_block], 66 | [ 67 | for association in aws_vpc_ipv6_cidr_block_association.this : 68 | association.ipv6_cidr_block 69 | ] 70 | ) 71 | : [] 72 | ) 73 | } 74 | 75 | output "ipv6_cidr_configurations" { 76 | description = "The list of IPv6 CIDR configurations for the VPC." 77 | value = (local.ipv6_enabled 78 | ? merge({ 79 | (aws_vpc.this.ipv6_cidr_block) = { 80 | type = length(compact([aws_vpc.this.ipv6_ipam_pool_id])) > 0 ? "IPAM_POOL" : "AMAZON" 81 | amazon = (length(compact([aws_vpc.this.ipv6_ipam_pool_id])) < 1 82 | ? { 83 | network_border_group = aws_vpc.this.ipv6_cidr_block_network_border_group 84 | } 85 | : null 86 | ) 87 | ipam_pool = (length(compact([aws_vpc.this.ipv6_ipam_pool_id])) > 0 88 | ? { 89 | id = aws_vpc.this.ipv6_ipam_pool_id 90 | netmask_length = aws_vpc.this.ipv6_netmask_length 91 | } 92 | : null 93 | ) 94 | }, 95 | }, { 96 | for association in aws_vpc_ipv6_cidr_block_association.this : 97 | (association.ipv6_cidr_block) => { 98 | type = length(compact([association.ipv6_ipam_pool_id])) > 0 ? "IPAM_POOL" : "AMAZON" 99 | amazon = (length(compact([association.ipv6_ipam_pool_id])) < 1 100 | ? { 101 | # TODO: Not supported yet 102 | network_border_group = null 103 | } 104 | : null 105 | ) 106 | ipam_pool = (length(compact([association.ipv6_ipam_pool_id])) > 0 107 | ? { 108 | id = association.ipv6_ipam_pool_id 109 | netmask_length = association.ipv6_netmask_length 110 | } 111 | : null 112 | ) 113 | } 114 | }) 115 | : {} 116 | ) 117 | } 118 | 119 | output "tenancy" { 120 | description = "A tenancy option for instances launched into the VPC." 121 | value = { 122 | for k, v in local.tenancy : 123 | v => k 124 | }[aws_vpc.this.instance_tenancy] 125 | } 126 | 127 | output "network_address_usage_metrics_enabled" { 128 | description = "Whether NAU (Network Address Usage) metrics are enabled for the VPC." 129 | value = aws_vpc.this.enable_network_address_usage_metrics 130 | } 131 | 132 | output "dns_hostnames_enabled" { 133 | description = "Whether instances launched in the VPC receive public DNS hostnames that correspond to their public IP addresses." 134 | value = aws_vpc.this.enable_dns_hostnames 135 | } 136 | 137 | output "dns_resolution_enabled" { 138 | description = "Whether DNS resolution through the Amazon DNS server is supported for the VPC." 139 | value = aws_vpc.this.enable_dns_support 140 | } 141 | 142 | output "dns_dnssec_validation_enabled" { 143 | description = "Whether or not the VPC has Route53 DNSSEC validation support." 144 | value = var.dns_dnssec_validation_enabled 145 | } 146 | 147 | output "dns_dnssec_validation_id" { 148 | description = "The ID of a configuration for DNSSEC validation." 149 | value = one(aws_route53_resolver_dnssec_config.this[*].id) 150 | } 151 | 152 | output "private_hosted_zones" { 153 | description = "List of associated private Hosted Zone IDs." 154 | value = values(aws_route53_zone_association.this)[*].zone_id 155 | } 156 | 157 | output "default_network_acl" { 158 | description = <