├── AUTHORS ├── LICENSE ├── README.md └── modules ├── aws ├── ami │ ├── centos │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── coreos-container-linux │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── main.tf │ ├── outputs.tf │ ├── ubuntu │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ └── variables.tf ├── availability-zones │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── version.tf ├── bastion │ ├── main.tf │ ├── outputs.tf │ ├── templates │ │ └── cloud-config.tpl │ └── variables.tf ├── cloudtrail │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── dhcp-options │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── ebs │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── eip │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── eni │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── flowlog │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── iam │ └── instance-profile │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf ├── internet-gateway │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── key-pair │ ├── Makefile │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── scripts │ │ └── public-key.sh │ ├── test │ │ ├── Makefile │ │ ├── fixtures │ │ │ └── id_rsa.pub │ │ ├── integration │ │ │ ├── main.tf │ │ │ └── test.bats │ │ └── test.bats │ ├── variables.tf │ └── version.tf ├── kms │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── nat-gateway │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── network-acl │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── route-table │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── route │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── route53 │ ├── main.tf │ ├── outputs.tf │ ├── private │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── reverse │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ └── variables.tf ├── s3-bucket │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── with-logging │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf ├── security-group │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── subnet │ ├── main.tf │ ├── outputs.tf │ ├── private │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── public │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ └── variables.tf ├── subnets │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── vpc-endpoint │ ├── README.md │ ├── dynamodb │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── main.tf │ ├── outputs.tf │ ├── s3 │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── variables.tf │ └── version.tf ├── vpc-peering │ ├── main.tf │ ├── outputs.tf │ └── variables.tf └── vpc │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── common ├── env │ ├── interface.tf │ ├── main.tf │ ├── outputs.tf │ └── scripts │ │ └── environment.sh ├── origin │ ├── interface.tf │ ├── main.tf │ ├── outputs.tf │ ├── scripts │ │ └── origin.sh │ └── version.tf ├── ptr-calculator │ ├── main.tf │ ├── outputs.tf │ └── variables.tf └── subnet-calculator │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── version.tf └── do ├── droplet ├── main.tf ├── outputs.tf ├── variables.tf └── version.tf ├── image ├── main.tf ├── outputs.tf ├── variables.tf └── version.tf └── ssh ├── main.tf ├── outputs.tf ├── variables.tf └── version.tf /AUTHORS: -------------------------------------------------------------------------------- 1 | Krzysztof Wilczynski 2 | Kamil Zabielski 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Terraform templates, examples, etc. 2 | -------------------------------------------------------------------------------- /modules/aws/ami/centos/main.tf: -------------------------------------------------------------------------------- 1 | module "ami" { 2 | source = "../" 3 | 4 | name = "${format(var.name, var.release)}" 5 | owners = ["${var.owners}"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/aws/ami/centos/outputs.tf: -------------------------------------------------------------------------------- 1 | output "image_id" { 2 | value = "${module.ami.image_id}" 3 | } 4 | 5 | output "name" { 6 | value = "${module.ami.name}" 7 | } 8 | 9 | output "creation_date" { 10 | value = "${module.ami.creation_date}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/centos/variables.tf: -------------------------------------------------------------------------------- 1 | variable "release" { 2 | default = "7" 3 | } 4 | 5 | variable "name" { 6 | default = "CentOS Linux %s *" 7 | } 8 | 9 | variable "owners" { 10 | default = ["679593333241"] 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/coreos-container-linux/main.tf: -------------------------------------------------------------------------------- 1 | module "ami" { 2 | source = "../" 3 | 4 | name = "${format(var.name, var.release)}" 5 | owners = ["${var.owners}"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/aws/ami/coreos-container-linux/outputs.tf: -------------------------------------------------------------------------------- 1 | output "image_id" { 2 | value = "${module.ami.image_id}" 3 | } 4 | 5 | output "name" { 6 | value = "${module.ami.name}" 7 | } 8 | 9 | output "creation_date" { 10 | value = "${module.ami.creation_date}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/coreos-container-linux/variables.tf: -------------------------------------------------------------------------------- 1 | variable "release" { 2 | default = "stable" 3 | } 4 | 5 | variable "name" { 6 | default = "CoreOS-%s-*" 7 | } 8 | 9 | variable "owners" { 10 | default = ["595879546273"] 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_ami" "mod" { 2 | most_recent = true 3 | 4 | owners = [ 5 | "${var.owners}" 6 | ] 7 | 8 | filter { 9 | name = "name" 10 | values = [ 11 | "${var.name}" 12 | ] 13 | } 14 | 15 | filter { 16 | name = "architecture" 17 | values = [ 18 | "x86_64" 19 | ] 20 | } 21 | 22 | filter { 23 | name = "virtualization-type" 24 | values = [ 25 | "hvm" 26 | ] 27 | } 28 | 29 | filter { 30 | name = "root-device-type" 31 | values = [ 32 | "${var.root_device_type}" 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /modules/aws/ami/outputs.tf: -------------------------------------------------------------------------------- 1 | output "image_id" { 2 | value = "${data.aws_ami.mod.image_id}" 3 | } 4 | 5 | output "name" { 6 | value = "${data.aws_ami.mod.name}" 7 | } 8 | 9 | output "creation_date" { 10 | value = "${data.aws_ami.mod.creation_date}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/ubuntu/main.tf: -------------------------------------------------------------------------------- 1 | module "ami" { 2 | source = "../" 3 | 4 | name = "${format(var.name, var.release)}" 5 | owners = ["${var.owners}"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/aws/ami/ubuntu/outputs.tf: -------------------------------------------------------------------------------- 1 | output "image_id" { 2 | value = "${module.ami.image_id}" 3 | } 4 | 5 | output "name" { 6 | value = "${module.ami.name}" 7 | } 8 | 9 | output "creation_date" { 10 | value = "${module.ami.creation_date}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/ubuntu/variables.tf: -------------------------------------------------------------------------------- 1 | variable "release" { 2 | default = "16.04" 3 | } 4 | 5 | variable "name" { 6 | default = "*/ubuntu-*-%s-amd64-server-*" 7 | } 8 | 9 | variable "owners" { 10 | default = ["099720109477"] 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/ami/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" {} 2 | 3 | variable "owners" { 4 | type = "list" 5 | } 6 | 7 | variable "root_device_type" { 8 | default = "ebs" 9 | } 10 | -------------------------------------------------------------------------------- /modules/aws/availability-zones/README.md: -------------------------------------------------------------------------------- 1 | # tf-aws-availability-zones 2 | 3 | This is a Terraform module to manage a list of Availability Zones in the current account which 4 | can be used to explicitly control access to a desired list of Availability Zones in a consistent 5 | and predictable manner. 6 | 7 | By default, this module returns all currently known Availability Zones in the current region, 8 | unless an Availability Zone is explicitly excluded from the results using the `exclude` variable. 9 | 10 | ## Requirements 11 | 12 | - Terraform 0.10.x or higher. 13 | 14 | ## Dependencies 15 | 16 | None. 17 | 18 | ## Usage 19 | 20 | #### Example of fetching Availability Zones in the "us-east-1" region with "us-east-1b" excluded using a single letter only: 21 | 22 | ```ruby 23 | module "availability_zones" { 24 | source = "./availability-zones" 25 | 26 | region = "us-east-1" 27 | exclude = ["b"] 28 | } 29 | ``` 30 | 31 | #### Example of fetching Availability Zones in the "us-east-1" region with "us-east-1b" excluded using full name of the zone: 32 | 33 | ```ruby 34 | module "availability_zones" { 35 | source = "./availability-zones" 36 | 37 | region = "us-east-1" 38 | exclude = ["us-east-1b"] 39 | } 40 | ``` 41 | 42 | #### Example of fetching Availability Zones in current region with all the zones shuffled around randomly: 43 | 44 | ```ruby 45 | module "availability_zones" { 46 | source = "./availability-zones" 47 | 48 | shuffle = true 49 | } 50 | ``` 51 | 52 | ## Variables 53 | 54 | | Name | Description | Type | Default | Required | 55 | |------|-------------|:-----:|:-----:|:-----:| 56 | | region | The name of the region for which to return the list of Availability Zones. | String | | No | 57 | | exclude | A list of Availability Zones to exclude from the results. Can be either a single letter or a full name of the zone (e.g. "b" or "us-east-1b"). | List | | No | 58 | | shuffle | | Boolean | false | No | 59 | 60 | ## Outputs 61 | 62 | | Name | Description | Type | 63 | |------|-------------|:----:| 64 | | region | The current region for which to return relevant Availability Zones. | String | 65 | | count | The number of all Availability Zones in the current region. | Integer | 66 | | all | The list of all Availability Zones in the current region. | List | 67 | | available | The list of Availability Zones in the current region without zones excluded using the `exclude` attribute. | List | 68 | | available_count | The number of Availability Zones in the current region without zones excluded using the `exclude` attribute. | Integer | 69 | 70 | ## Notes 71 | 72 | This module provides a static list of Regions and Availability Zones, and does not rely on the 73 | Terraform [aws_availability_zones](https://www.terraform.io/docs/providers/aws/d/availability_zones.html) 74 | data source. Since Terraform data sources are dynamic and always refresh to present up-to-date values, 75 | such behaviour can result in an undesirable change that might be introduced to the existing infrastructure 76 | due to either a new Availability Zone becoming available or retired in the current region. 77 | 78 | Additionally, this module outputs contain a static values such as e.g. number of Availability Zones, etc., 79 | which would alleviate an issue with dynamic resources interpolation and the `count` attribute. 80 | 81 | ## Known issues 82 | 83 | None. 84 | 85 | ## References 86 | 87 | A Pull Request against Terraform which contains implementation details regarding issues with reliable 88 | detection of Availability Zones: 89 | 90 | - [Add state filter to aws_availability_zones data source.](https://github.com/hashicorp/terraform/pull/7965) 91 | 92 | An issue which contains a discussion about a side effect of changes in the Terraform plan following 93 | an addition of a new Availability Zone: 94 | 95 | - [AWS Added an additional AZ to us-east-1 and now `terraform plan` causes a state change](https://github.com/hashicorp/terraform/issues/11928) 96 | 97 | ## Development 98 | 99 | Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for instructions regarding 100 | the contribution to this repository. 101 | -------------------------------------------------------------------------------- /modules/aws/availability-zones/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "mod" { 2 | count = "${var.region != "" ? 0 : 1}" 3 | 4 | current = true 5 | } 6 | 7 | data "null_data_source" "region" { 8 | inputs = { 9 | value = "${coalesce(var.region, join("", data.aws_region.mod.*.name))}" 10 | } 11 | } 12 | 13 | data "null_data_source" "padding" { 14 | count = "${length(var.exclude) > 0 ? length(var.regions[ 15 | data.null_data_source.region.outputs.value]) : 0}" 16 | 17 | inputs = { 18 | value = "" 19 | } 20 | } 21 | 22 | data "null_data_source" "indices" { 23 | count = "${length(var.exclude) > 0 ? length(var.regions[ 24 | data.null_data_source.region.outputs.value]) : 0}" 25 | 26 | inputs = { 27 | value = "${count.index}" 28 | } 29 | } 30 | 31 | data "null_data_source" "filter" { 32 | count = "${length(var.exclude) > 0 ? length(var.regions[ 33 | data.null_data_source.region.outputs.value]) : 0}" 34 | 35 | inputs = { 36 | value = "${index(split(",", length(element(concat(var.exclude, list("")), count.index)) > 1 37 | ? join(",", var.regions_long[data.null_data_source.region.outputs.value]) 38 | : join(",", var.regions[data.null_data_source.region.outputs.value])), 39 | element(var.exclude, count.index))}" 40 | } 41 | } 42 | 43 | data "null_data_source" "available" { 44 | count = "${length(var.exclude) > 0 ? 1 : 0}" 45 | 46 | inputs = { 47 | value = "${join(",", formatlist("%s%s", data.null_data_source.region.outputs.value, 48 | compact(values(merge(zipmap(data.null_data_source.indices.*.outputs.value, 49 | var.regions[data.null_data_source.region.outputs.value]), 50 | zipmap(data.null_data_source.filter.*.outputs.value, 51 | data.null_data_source.padding.*.outputs.value))))))}" 52 | } 53 | } 54 | 55 | resource "random_shuffle" "random" { 56 | count = "${var.shuffle ? 1 : 0}" 57 | 58 | input = [ 59 | "${data.null_data_source.available.*.outputs.value}" 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /modules/aws/availability-zones/outputs.tf: -------------------------------------------------------------------------------- 1 | output "region" { 2 | value = "${data.null_data_source.region.outputs.value}" 3 | } 4 | 5 | output "count" { 6 | value = "${length(var.regions[data.null_data_source.region.outputs.value])}" 7 | } 8 | 9 | output "all" { 10 | value = ["${formatlist("%s%s", data.null_data_source.region.outputs.value, 11 | var.regions[data.null_data_source.region.outputs.value])}"] 12 | } 13 | 14 | output "available" { 15 | value = ["${split(",", coalesce(join("", 16 | data.null_data_source.available.*.outputs.value), join(",", 17 | formatlist("%s%s", data.null_data_source.region.outputs.value, 18 | var.regions[data.null_data_source.region.outputs.value]))))}"] 19 | } 20 | 21 | output "available_count" { 22 | value = "${length(split(",", data.null_data_source.available.outputs.value))}" 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/availability-zones/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | default = "" 3 | } 4 | 5 | variable "exclude" { 6 | default = [] 7 | } 8 | 9 | variable "shuffle" { 10 | default = false 11 | } 12 | 13 | variable "regions" { 14 | default = { 15 | us-east-1 = ["a", "b", "c", "d", "e", "f"] 16 | us-east-2 = ["a", "b", "c"] 17 | us-west-1 = ["a", "b", "c"] 18 | us-west-2 = ["a", "b", "c"] 19 | ca-central-1 = ["a", "b"] 20 | eu-west-1 = ["a", "b", "c"] 21 | eu-west-2 = ["a", "b"] 22 | eu-central-1 = ["a", "b", "c"] 23 | ap-northeast-1 = ["a", "b", "c"] 24 | ap-northeast-2 = ["a", "c"] 25 | ap-southeast-1 = ["a", "b"] 26 | ap-southeast-2 = ["a", "b", "c"] 27 | ap-south-1 = ["a", "b"] 28 | sa-east-1 = ["a", "b", "c"] 29 | } 30 | } 31 | 32 | variable "regions_long" { 33 | default = { 34 | us-east-1 = [ 35 | "us-east-1a", 36 | "us-east-1b", 37 | "us-east-1c", 38 | "us-east-1d", 39 | "us-east-1e", 40 | "us-east-1f" 41 | ] 42 | us-east-2 = [ 43 | "us-east-2a", 44 | "us-east-2b", 45 | "us-east-2c" 46 | ] 47 | us-west-1 = [ 48 | "us-west-1a", 49 | "us-west-1b", 50 | "us-west-1c" 51 | ] 52 | us-west-2 = [ 53 | "us-west-2a", 54 | "us-west-2b", 55 | "us-west-2c" 56 | ] 57 | ca-central-1 = [ 58 | "ca-central-1a", 59 | "ca-central-1b" 60 | ] 61 | eu-west-1 = [ 62 | "eu-west-1a", 63 | "eu-west-1b", 64 | "eu-west-1c" 65 | ] 66 | eu-west-2 = [ 67 | "eu-west-2a", 68 | "eu-west-2b" 69 | ] 70 | eu-central-1 = [ 71 | "eu-central-1a", 72 | "eu-central-1b", 73 | "eu-central-1c" 74 | ] 75 | ap-northeast-1 = [ 76 | "ap-northeast-1a", 77 | "ap-northeast-1b", 78 | "ap-northeast-1c" 79 | ] 80 | ap-northeast-2 = [ 81 | "ap-northeast-2a", 82 | "ap-northeast-2c" 83 | ] 84 | ap-southeast-1 = [ 85 | "ap-southeast-1a", 86 | "ap-southeast-1b" 87 | ] 88 | ap-southeast-2 = [ 89 | "ap-southeast-2a", 90 | "ap-southeast-2b", 91 | "ap-southeast-2c" 92 | ] 93 | ap-south-1 = [ 94 | "ap-south-1a", 95 | "ap-south-1b" 96 | ] 97 | sa-east-1 = [ 98 | "sa-east-1a", 99 | "sa-east-1b", 100 | "sa-east-1c" 101 | ] 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /modules/aws/availability-zones/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/bastion/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_route53_zone" "mod" { 2 | count = "${var.zone_id != "" ? var.domain_name != "" ? 0 : 1 : 0}" 3 | 4 | zone_id = "${var.zone_id}" 5 | } 6 | 7 | data "template_file" "mod" { 8 | template = "${file(format("%s/templates/%s", path.module, "cloud-config.tpl"))}" 9 | 10 | vars { 11 | allocation_id = "${coalesce(var.eip_allocation_id, join("", 12 | aws_eip.mod.*.id))}" 13 | } 14 | } 15 | 16 | data "template_cloudinit_config" "mod" { 17 | gzip = false 18 | base64_encode = false 19 | 20 | part { 21 | filename = "cloud-config.cfg" 22 | content_type = "text/cloud-config" 23 | content = "${coalesce(var.cloud_config, join("", 24 | data.template_file.mod.*.rendered))}" 25 | } 26 | 27 | part { 28 | filename = "additional_user_data.sh" 29 | content_type = "text/x-shellscript" 30 | content = "${var.additional_user_data}" 31 | } 32 | } 33 | 34 | data "aws_iam_policy_document" "assume_role_policy" { 35 | count = "${var.iam_instance_profile != "" ? 0 : 1}" 36 | 37 | statement { 38 | principals { 39 | type = "Service" 40 | identifiers = [ 41 | "ec2.amazonaws.com" 42 | ] 43 | } 44 | 45 | actions = [ 46 | "sts:AssumeRole" 47 | ] 48 | } 49 | } 50 | 51 | data "aws_iam_policy_document" "associate_address_policy" { 52 | count = "${var.iam_instance_profile != "" ? 0 : 1}" 53 | 54 | statement { 55 | actions = [ 56 | "ec2:AssociateAddress", 57 | "ec2:DisassociateAddress" 58 | ] 59 | 60 | resources = [ 61 | "*" 62 | ] 63 | } 64 | } 65 | 66 | resource "null_resource" "depends_on" { 67 | triggers { 68 | depends_on = "${join("", var.depends_on)}" 69 | } 70 | } 71 | 72 | resource "aws_iam_role" "mod" { 73 | count = "${var.iam_instance_profile != "" ? 0 : 1}" 74 | 75 | name = "${format("%s-bastion-instance-role", var.stack_name)}" 76 | assume_role_policy = "${data.aws_iam_policy_document.assume_role_policy.json}" 77 | } 78 | 79 | resource "aws_iam_role_policy" "mod" { 80 | count = "${var.iam_instance_profile != "" ? 0 : 1}" 81 | 82 | name = "${format("%s-bastion-role-policy", var.stack_name)}" 83 | role = "${aws_iam_role.mod.id}" 84 | policy = "${data.aws_iam_policy_document.associate_address_policy.json}" 85 | } 86 | 87 | resource "aws_iam_instance_profile" "mod" { 88 | count = "${var.iam_instance_profile != "" ? 0 : 1}" 89 | 90 | name = "${format("%s-bastion-instance-profile", var.stack_name)}" 91 | role = "${aws_iam_role.mod.name}" 92 | 93 | // This is to resolve an issue with Instance Profile creation, 94 | // where the underlying profile is still being created, but other 95 | // resources that use it would try to access it already, see: 96 | // https://github.com/hashicorp/terraform/issues/1885 97 | provisioner "local-exec" { 98 | command = "sleep 30" 99 | } 100 | 101 | depends_on = ["aws_iam_role.mod"] 102 | } 103 | 104 | resource "aws_security_group" "mod" { 105 | count = "${length(var.security_groups) != 0 ? 0 : 1}" 106 | 107 | name = "${format("%s-bastion-security-group", var.stack_name)}" 108 | description = "${format("Security Group for Bastion - %s", var.stack_name)}" 109 | 110 | vpc_id = "${var.vpc_id}" 111 | 112 | tags = { 113 | Name = "${format("%s-bastion-security-group", var.stack_name)}" 114 | StackName = "${var.stack_name}" 115 | Environment = "${var.environment}" 116 | Version = "${var.version}" 117 | } 118 | } 119 | 120 | resource "aws_security_group_rule" "rule_ingress_allow_icmp" { 121 | count = "${length(var.security_groups) != 0 ? 0 : var.allow_icmp ? 1 : 0}" 122 | 123 | type = "ingress" 124 | 125 | protocol = "icmp" 126 | from_port = -1 127 | to_port = -1 128 | 129 | cidr_blocks = ["0.0.0.0/0"] 130 | 131 | security_group_id = "${aws_security_group.mod.id}" 132 | 133 | depends_on = ["aws_security_group.mod"] 134 | } 135 | 136 | resource "aws_security_group_rule" "rule_ingress_allow_icmp_destination_unreachable" { 137 | count = "${length(var.security_groups) != 0 ? 0 : var.allow_icmp ? 0 : 1}" 138 | 139 | type = "ingress" 140 | 141 | protocol = "icmp" 142 | from_port = 3 143 | to_port = 3 144 | 145 | cidr_blocks = ["0.0.0.0/0"] 146 | 147 | security_group_id = "${aws_security_group.mod.id}" 148 | 149 | depends_on = ["aws_security_group.mod"] 150 | } 151 | 152 | resource "aws_security_group_rule" "rule_ingress_allow_tcp_port_22_from_cidrs" { 153 | count = "${length(var.security_groups) != 0 ? 0 : 1}" 154 | 155 | type = "ingress" 156 | 157 | protocol = "tcp" 158 | from_port = 22 159 | to_port = 22 160 | 161 | cidr_blocks = ["${var.allowed_cidr_blocks}"] 162 | 163 | security_group_id = "${aws_security_group.mod.id}" 164 | 165 | depends_on = ["aws_security_group.mod"] 166 | } 167 | 168 | resource "aws_security_group_rule" "rule_ingress_allow_tcp_port_22_from_security_groups" { 169 | count = "${length(var.security_groups) != 0 170 | ? 0 : length(var.allowed_security_groups) == 0 171 | ? 0 : length(var.allowed_security_groups)}" 172 | 173 | type = "ingress" 174 | 175 | protocol = "tcp" 176 | from_port = 22 177 | to_port = 22 178 | 179 | source_security_group_id = "${element(var.allowed_security_groups, count.index)}" 180 | 181 | security_group_id = "${aws_security_group.mod.id}" 182 | 183 | depends_on = ["aws_security_group.mod"] 184 | } 185 | 186 | resource "aws_security_group_rule" "rule_egress_allow_everything" { 187 | count = "${length(var.security_groups) != 0 ? 0 : 1}" 188 | 189 | type = "egress" 190 | 191 | protocol = -1 192 | from_port = 0 193 | to_port = 0 194 | 195 | cidr_blocks = ["0.0.0.0/0"] 196 | 197 | security_group_id = "${aws_security_group.mod.id}" 198 | 199 | depends_on = ["aws_security_group.mod"] 200 | } 201 | 202 | resource "aws_eip" "mod" { 203 | count = "${var.eip_allocation_id != "" ? 0 : 1}" 204 | 205 | vpc = true 206 | } 207 | 208 | resource "aws_launch_configuration" "mod" { 209 | name_prefix = "${format("%s-bastion-launch-configuration-", var.stack_name)}" 210 | 211 | image_id = "${var.image_id}" 212 | instance_type = "${var.instance_type}" 213 | key_name = "${var.key_name}" 214 | 215 | iam_instance_profile = "${coalesce(var.iam_instance_profile, join("", 216 | aws_iam_instance_profile.mod.*.name))}" 217 | 218 | security_groups = ["${coalescelist(var.security_groups, aws_security_group.mod.*.id)}"] 219 | 220 | associate_public_ip_address = false 221 | 222 | user_data = "${coalesce(var.user_data, join("", 223 | data.template_cloudinit_config.mod.*.rendered))}" 224 | 225 | root_block_device { 226 | volume_type = "${var.volume_type}" 227 | volume_size = "${var.volume_size}" 228 | } 229 | 230 | lifecycle { 231 | create_before_destroy = true 232 | 233 | ignore_changes = [ 234 | "image_id", 235 | "user_data" 236 | ] 237 | } 238 | 239 | depends_on = [ 240 | "aws_eip.mod", 241 | "null_resource.depends_on" 242 | ] 243 | } 244 | 245 | resource "aws_autoscaling_group" "mod" { 246 | name = "${format("%s-bastion-autoscaling-group", var.stack_name)}" 247 | 248 | vpc_zone_identifier = ["${var.subnet_ids}"] 249 | 250 | force_delete = false 251 | 252 | min_size = 1 253 | max_size = 1 254 | desired_capacity = 1 255 | 256 | wait_for_capacity_timeout = 0 257 | 258 | health_check_type = "EC2" 259 | health_check_grace_period = 60 260 | 261 | launch_configuration = "${aws_launch_configuration.mod.name}" 262 | 263 | enabled_metrics = [ 264 | "GroupMinSize", 265 | "GroupMaxSize", 266 | "GroupDesiredCapacity", 267 | "GroupInServiceInstances", 268 | "GroupPendingInstances", 269 | "GroupStandbyInstances", 270 | "GroupTerminatingInstances", 271 | "GroupTotalInstances" 272 | ] 273 | 274 | tags = [ 275 | "${concat( 276 | list( 277 | map( 278 | "key", "Name", 279 | "value", "${format("%s-bastion-instance", var.stack_name)}", 280 | "propagate_at_launch", true 281 | ), 282 | map( 283 | "key", "StackName", 284 | "value", "${var.stack_name}", 285 | "propagate_at_launch", true 286 | ), 287 | map( 288 | "key", "Environment", 289 | "value", "${var.environment}", 290 | "propagate_at_launch", true 291 | ), 292 | map( 293 | "key", "Version", 294 | "value", "${var.version}", 295 | "propagate_at_launch", true 296 | ), 297 | map( 298 | "key", "Role", 299 | "value", "${var.role}", 300 | "propagate_at_launch", true 301 | ) 302 | ), 303 | var.tags)}" 304 | ] 305 | 306 | depends_on = ["aws_launch_configuration.mod"] 307 | } 308 | 309 | resource "aws_route53_record" "public_a" { 310 | count = "${var.zone_id == "" ? 0 : 1}" 311 | 312 | zone_id = "${coalesce(var.zone_id, "-")}" 313 | 314 | name = "${format("bastion-001.%s", coalesce(var.domain_name, 315 | join("", data.aws_route53_zone.mod.*.name)))}" 316 | 317 | type = "A" 318 | ttl = 60 319 | 320 | records = ["${aws_eip.mod.public_ip}"] 321 | 322 | depends_on = ["aws_eip.mod"] 323 | } 324 | 325 | resource "aws_route53_record" "public_cname" { 326 | count = "${var.zone_id == "" ? 0 : 1}" 327 | 328 | zone_id = "${coalesce(var.zone_id, "-")}" 329 | 330 | name = "${format("bastion.%s", coalesce(var.domain_name, 331 | join("", data.aws_route53_zone.mod.*.name)))}" 332 | 333 | type = "CNAME" 334 | ttl = 60 335 | 336 | records = ["${aws_route53_record.public_a.fqdn}"] 337 | 338 | depends_on = ["aws_route53_record.public_a"] 339 | } 340 | -------------------------------------------------------------------------------- /modules/aws/bastion/outputs.tf: -------------------------------------------------------------------------------- 1 | output "private_ip" { 2 | value = "${aws_eip.mod.private_ip}" 3 | } 4 | 5 | output "public_ip" { 6 | value = "${aws_eip.mod.public_ip}" 7 | } 8 | 9 | output "public_a" { 10 | value = "${aws_route53_record.public_a.fqdn}" 11 | } 12 | 13 | output "public_cname" { 14 | value = "${aws_route53_record.public_cname.fqdn}" 15 | } 16 | 17 | output "eip_allocation_id" { 18 | value = "${aws_eip.mod.id}" 19 | } 20 | 21 | output "role_id" { 22 | value = "${aws_iam_role.mod.id}" 23 | } 24 | 25 | output "role_arn" { 26 | value = "${aws_iam_role.mod.arn}" 27 | } 28 | 29 | output "security_group_id" { 30 | value = "${element(coalescelist(var.security_groups, aws_security_group.mod.*.id), 0)}" 31 | } 32 | 33 | output "security_groups" { 34 | value = ["${coalescelist(var.security_groups, aws_security_group.mod.*.id)}"] 35 | } 36 | -------------------------------------------------------------------------------- /modules/aws/bastion/templates/cloud-config.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | packages: 3 | - curl 4 | - awscli 5 | runcmd: 6 | - aws ec2 associate-address --instance-id $(curl -s http://169.254.169.254/latest/meta-data/instance-id) --allocation-id ${allocation_id} --region $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/\w$//') 7 | output: 8 | all: '| tee -a /var/log/cloud-init-output.log' 9 | -------------------------------------------------------------------------------- /modules/aws/bastion/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "image_id" {} 6 | variable "key_name" {} 7 | 8 | variable "vpc_id" { 9 | default = "" 10 | } 11 | 12 | variable "region" { 13 | default = "" 14 | } 15 | 16 | variable "iam_instance_profile" { 17 | default = "" 18 | } 19 | 20 | variable "instance_type" { 21 | default = "t2.micro" 22 | } 23 | 24 | variable "security_groups" { 25 | default = [] 26 | } 27 | 28 | variable "allowed_security_groups" { 29 | default = [] 30 | } 31 | 32 | variable "allowed_cidr_blocks" { 33 | default = ["0.0.0.0/0"] 34 | } 35 | 36 | variable "allow_icmp" { 37 | default = false 38 | } 39 | 40 | variable "subnet_ids" { 41 | type = "list" 42 | } 43 | 44 | variable "cloud_config" { 45 | default = "" 46 | } 47 | 48 | variable "user_data" { 49 | default = "" 50 | } 51 | 52 | variable "additional_user_data" { 53 | default = "" 54 | } 55 | 56 | variable "volume_type" { 57 | default = "gp2" 58 | } 59 | 60 | variable "volume_size" { 61 | default = 0 62 | } 63 | 64 | variable "role" { 65 | default = "bastion" 66 | } 67 | 68 | variable "eip_allocation_id" { 69 | default = "" 70 | } 71 | 72 | variable "domain_name" { 73 | default = "" 74 | } 75 | 76 | variable "zone_id" { 77 | default = "" 78 | } 79 | 80 | variable "tags" { 81 | default = [] 82 | } 83 | 84 | variable "depends_on" { 85 | default = [] 86 | } 87 | -------------------------------------------------------------------------------- /modules/aws/cloudtrail/main.tf: -------------------------------------------------------------------------------- 1 | data "null_data_source" "mod" { 2 | count = "${var.s3_bucket_name != "" ? 0 : 1}" 3 | 4 | inputs = { 5 | bucket = "${format("%s-%s-s3-bucket-cloudtrial", var.stack_name, var.name)}" 6 | } 7 | } 8 | 9 | data "aws_iam_policy_document" "mod" { 10 | count = "${var.s3_bucket_name != "" ? 0 : 1}" 11 | 12 | statement { 13 | actions = [ 14 | "s3:GetBucketAcl" 15 | ] 16 | 17 | resources = [ 18 | "${format("arn:aws:s3:::%s", data.null_data_source.mod.outputs.bucket)}" 19 | ] 20 | 21 | principals { 22 | type = "Service" 23 | identifiers = [ 24 | "cloudtrail.amazonaws.com" 25 | ] 26 | } 27 | } 28 | 29 | statement { 30 | actions = [ 31 | "s3:PutObject" 32 | ] 33 | 34 | resources = [ 35 | "${format("arn:aws:s3:::%s/*", data.null_data_source.mod.outputs.bucket)}" 36 | ] 37 | 38 | principals { 39 | type = "Service" 40 | identifiers = [ 41 | "cloudtrail.amazonaws.com" 42 | ] 43 | } 44 | 45 | condition { 46 | test = "StringEquals" 47 | variable = "s3:x-amz-acl" 48 | 49 | values = [ 50 | "bucket-owner-full-control" 51 | ] 52 | } 53 | } 54 | } 55 | 56 | resource "null_resource" "depends_on" { 57 | triggers { 58 | depends_on = "${join("", var.depends_on)}" 59 | } 60 | } 61 | 62 | resource "aws_s3_bucket" "mod" { 63 | count = "${var.s3_bucket_name != "" ? 0 : 1}" 64 | 65 | bucket = "${data.null_data_source.mod.outputs.bucket}" 66 | 67 | acl = "private" 68 | policy = "${data.aws_iam_policy_document.mod.json}" 69 | 70 | force_destroy = "${var.force_destroy}" 71 | 72 | lifecycle_rule { 73 | enabled = true 74 | 75 | id = "${format("%s-lifecycle", data.null_data_source.mod.outputs.bucket)}" 76 | prefix = "" 77 | 78 | expiration { 79 | days = "${var.expiration_days}" 80 | } 81 | } 82 | 83 | tags = "${merge(map( 84 | "Name", "${data.null_data_source.mod.outputs.bucket}", 85 | "StackName", "${var.stack_name}", 86 | "Environment", "${var.environment}", 87 | "Version", "${var.version}" 88 | ), var.tags)}" 89 | } 90 | 91 | resource "aws_cloudtrail" "mod" { 92 | name = "${format("%s-%s-cloudtrial", var.stack_name, var.name)}" 93 | 94 | kms_key_id = "${var.kms_key_id}" 95 | 96 | enable_logging = "${var.enable_logging}" 97 | enable_log_file_validation = "${var.enable_log_file_validation}" 98 | 99 | include_global_service_events = "${var.include_global_service_events}" 100 | is_multi_region_trail = "${var.is_multi_region_trail}" 101 | 102 | s3_bucket_name = "${coalesce(var.s3_bucket_name, join("", 103 | data.null_data_source.mod.*.outputs.bucket))}" 104 | s3_key_prefix = "${var.s3_key_prefix}" 105 | 106 | cloud_watch_logs_role_arn = "${var.cloud_watch_logs_role_arn}" 107 | cloud_watch_logs_group_arn = "${var.cloud_watch_logs_group_arn}" 108 | 109 | sns_topic_name = "${var.sns_topic_name}" 110 | 111 | tags = "${merge(map( 112 | "Name", "${format("%s-%s-cloudtrial", var.stack_name, var.name)}", 113 | "StackName", "${var.stack_name}", 114 | "Environment", "${var.environment}", 115 | "Version", "${var.version}" 116 | ), var.tags)}" 117 | 118 | depends_on = [ 119 | "aws_s3_bucket.mod", 120 | "null_resource.depends_on" 121 | ] 122 | } 123 | -------------------------------------------------------------------------------- /modules/aws/cloudtrail/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_cloudtrail.mod.id}" 3 | } 4 | 5 | output "home_region" { 6 | value = "${aws_cloudtrail.mod.home_region}" 7 | } 8 | output "arn" { 9 | value = "${aws_cloudtrail.mod.arn}" 10 | } 11 | 12 | output "bucket_id" { 13 | value = "${aws_s3_bucket.mod.id}" 14 | } 15 | 16 | output "bucket_arn" { 17 | value = "${aws_s3_bucket.mod.arn}" 18 | } 19 | 20 | output "bucket_name" { 21 | value = "${coalesce(var.s3_bucket_name, join("", 22 | data.null_data_source.mod.*.outputs.bucket))}" 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/cloudtrail/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | 7 | variable "kms_key_id" { 8 | default = "" 9 | } 10 | 11 | variable "enable_logging" { 12 | default = true 13 | } 14 | 15 | variable "enable_log_file_validation" { 16 | default = true 17 | } 18 | 19 | variable "include_global_service_events" { 20 | default = true 21 | } 22 | 23 | variable "is_multi_region_trail" { 24 | default = false 25 | } 26 | 27 | variable "s3_bucket_name" { 28 | default = "" 29 | } 30 | 31 | variable "s3_key_prefix" { 32 | default = "" 33 | } 34 | 35 | variable "force_destroy" { 36 | default = false 37 | } 38 | 39 | variable "expiration_days" { 40 | default = "30" 41 | } 42 | 43 | variable "cloud_watch_logs_role_arn" { 44 | default = "" 45 | } 46 | 47 | variable "cloud_watch_logs_group_arn" { 48 | default = "" 49 | } 50 | 51 | variable "sns_topic_name" { 52 | default = "" 53 | } 54 | 55 | variable "tags" { 56 | default = {} 57 | } 58 | 59 | variable "depends_on" { 60 | default = [] 61 | } 62 | -------------------------------------------------------------------------------- /modules/aws/dhcp-options/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "mod" { 2 | count = "${var.region != "" ? 0 : 1}" 3 | 4 | current = true 5 | } 6 | 7 | data "null_data_source" "mod" { 8 | inputs = { 9 | domain_name = "${coalesce(var.domain_name, coalesce(var.region, 10 | join("", data.aws_region.mod.*.name)) == "us-east-1" 11 | ? "ec2.internal" : format("%s.compute.internal", 12 | coalesce(var.region, join("", 13 | data.aws_region.mod.*.name))))}" 14 | } 15 | } 16 | 17 | resource "null_resource" "depends_on" { 18 | triggers { 19 | depends_on = "${join("", var.depends_on)}" 20 | } 21 | } 22 | 23 | resource "aws_vpc_dhcp_options" "mod" { 24 | domain_name = "${data.null_data_source.mod.outputs.domain_name}" 25 | 26 | domain_name_servers = ["${var.domain_name_servers}"] 27 | ntp_servers = ["${var.ntp_servers}"] 28 | 29 | tags = "${merge(map( 30 | "Name", "${format("%s-dhcp-options", var.stack_name)}", 31 | "StackName", "${var.stack_name}", 32 | "Environment", "${var.environment}", 33 | "Version", "${var.version}" 34 | ), var.tags)}" 35 | 36 | depends_on = ["null_resource.depends_on"] 37 | } 38 | 39 | resource "aws_vpc_dhcp_options_association" "mod" { 40 | vpc_id = "${var.vpc_id}" 41 | dhcp_options_id = "${aws_vpc_dhcp_options.mod.id}" 42 | 43 | depends_on = ["aws_vpc_dhcp_options.mod"] 44 | } 45 | -------------------------------------------------------------------------------- /modules/aws/dhcp-options/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_vpc_dhcp_options.mod.id}" 3 | } 4 | 5 | output "domain_name" { 6 | value = "${data.null_data_source.mod.outputs.domain_name}" 7 | } 8 | -------------------------------------------------------------------------------- /modules/aws/dhcp-options/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "vpc_id" {} 6 | 7 | variable "region" { 8 | default = "" 9 | } 10 | 11 | variable "domain_name" { 12 | default = "" 13 | } 14 | 15 | variable "domain_name_servers" { 16 | default = ["AmazonProvidedDNS"] 17 | } 18 | 19 | variable "ntp_servers" { 20 | default = [] 21 | } 22 | 23 | variable "tags" { 24 | default = {} 25 | } 26 | 27 | variable "depends_on" { 28 | default = [] 29 | } 30 | -------------------------------------------------------------------------------- /modules/aws/ebs/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_ebs_volume" "mod" { 8 | availability_zone = "${var.availability_zone}" 9 | 10 | encrypted = "${var.encrypted}" 11 | 12 | iops = "${var.iops}" 13 | size = "${var.size}" 14 | type = "${var.type}" 15 | 16 | kms_key_id = "${var.kms_key_id}" 17 | 18 | tags = "${merge(map( 19 | "Name", "${format("%s-%s-ebs-volume", var.stack_name, var.name)}", 20 | "StackName", "${var.stack_name}", 21 | "Environment", "${var.environment}", 22 | "Version", "${var.version}" 23 | ), var.tags)}" 24 | 25 | depends_on = ["null_resource.depends_on"] 26 | } 27 | -------------------------------------------------------------------------------- /modules/aws/ebs/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_ebs_volume.mod.id}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/ebs/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | variable "availability_zone" {} 7 | variable "size" {} 8 | 9 | variable "encrypted" { 10 | default = false 11 | } 12 | 13 | variable "iops" { 14 | default = 0 15 | } 16 | 17 | variable "type" { 18 | default = "gp2" 19 | } 20 | 21 | variable "kms_key_id" { 22 | default = "" 23 | } 24 | 25 | variable "tags" { 26 | default = {} 27 | } 28 | 29 | variable "depends_on" { 30 | default = [] 31 | } 32 | -------------------------------------------------------------------------------- /modules/aws/eip/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_eip" "mod" { 8 | vpc = "${var.vpc}" 9 | 10 | instance = "${var.instance}" 11 | network_interface = "${var.network_interface}" 12 | associate_with_private_ip = "${var.associate_with_private_ip}" 13 | 14 | depends_on = ["null_resource.depends_on"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/aws/eip/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_eip.mod.id}" 3 | } 4 | 5 | output "public_ip" { 6 | value = "${aws_eip.mod.public_ip}" 7 | } 8 | -------------------------------------------------------------------------------- /modules/aws/eip/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc" { 2 | default = false 3 | } 4 | 5 | variable "instance" { 6 | default = "" 7 | } 8 | 9 | variable "network_interface" { 10 | default = "" 11 | } 12 | 13 | variable "associate_with_private_ip" { 14 | default = "" 15 | } 16 | 17 | variable "depends_on" { 18 | default = [] 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/eni/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_network_interface" "mod" { 8 | subnet_id = "${var.subnet_id}" 9 | 10 | description = "${coalesce(var.description, format("Elastic Network Interface - %s", var.name))}" 11 | 12 | private_ips = ["${var.private_ips}"] 13 | private_ips_count = "${var.private_ips_count}" 14 | 15 | security_groups = ["${var.security_groups}"] 16 | 17 | source_dest_check = "${var.source_dest_check}" 18 | 19 | tags = "${merge(map( 20 | "Name", "${format("%s-%s-network-interface", var.stack_name, var.name)}", 21 | "StackName", "${var.stack_name}", 22 | "Environment", "${var.environment}", 23 | "Version", "${var.version}" 24 | ), var.tags)}" 25 | 26 | depends_on = ["null_resource.depends_on"] 27 | } 28 | 29 | resource "aws_network_interface_attachment" "mod" { 30 | count = "${var.instance_id == "" ? 0 : 1}" 31 | 32 | instance_id = "${var.instance_id}" 33 | device_index = "${var.device_index}" 34 | 35 | network_interface_id = "${aws_network_interface.mod.id}" 36 | 37 | depends_on = ["aws_network_interface.mod"] 38 | } 39 | -------------------------------------------------------------------------------- /modules/aws/eni/outputs.tf: -------------------------------------------------------------------------------- 1 | output "subnet_id" { 2 | value = "${aws_network_interface.mod.subnet_id}" 3 | } 4 | 5 | output "private_ip" { 6 | value = "${element(aws_network_interface.mod.private_ips, 0)}" 7 | } 8 | 9 | output "private_ips" { 10 | value = ["${aws_network_interface.mod.private_ips}"] 11 | } 12 | 13 | output "security_groups" { 14 | value = ["${aws_network_interface.mod.security_groups}"] 15 | } 16 | 17 | output "instance_id" { 18 | value = "${aws_network_interface_attachment.mod.instance_id}" 19 | } 20 | 21 | output "network_interface_id" { 22 | value = "${aws_network_interface_attachment.mod.network_interface_id}" 23 | } 24 | 25 | output "device_index" { 26 | value = "${aws_network_interface_attachment.mod.device_index}" 27 | } 28 | -------------------------------------------------------------------------------- /modules/aws/eni/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | variable "subnet_id" {} 7 | 8 | variable "description" { 9 | default = "" 10 | } 11 | 12 | variable "private_ips" { 13 | default = [] 14 | } 15 | 16 | variable "private_ips_count" { 17 | default = 0 18 | } 19 | 20 | variable "security_groups" { 21 | default = [] 22 | } 23 | 24 | variable "source_dest_check" { 25 | default = true 26 | } 27 | 28 | variable "tags" { 29 | default = {} 30 | } 31 | 32 | variable "instance_id" { 33 | default = "" 34 | } 35 | 36 | variable "device_index" { 37 | default = 0 38 | } 39 | 40 | variable "depends_on" { 41 | default = [] 42 | } 43 | -------------------------------------------------------------------------------- /modules/aws/flowlog/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "role" { 2 | statement { 3 | principals { 4 | type = "Service" 5 | identifiers = [ 6 | "vpc-flow-logs.amazonaws.com" 7 | ] 8 | } 9 | 10 | actions = [ 11 | "sts:AssumeRole" 12 | ] 13 | } 14 | } 15 | 16 | data "aws_iam_policy_document" "role_policy" { 17 | statement { 18 | actions = [ 19 | "logs:CreateLogGroup", 20 | "logs:CreateLogStream", 21 | "logs:PutLogEvents", 22 | "logs:DescribeLogGroups", 23 | "logs:DescribeLogStreams" 24 | ] 25 | 26 | resources = [ 27 | "*" 28 | ] 29 | } 30 | } 31 | 32 | resource "null_resource" "depends_on" { 33 | triggers { 34 | depends_on = "${join("", var.depends_on)}" 35 | } 36 | } 37 | 38 | resource "aws_iam_role" "mod" { 39 | name = "${format("%s-%s-flowlog-role", var.stack_name, var.name)}" 40 | assume_role_policy = "${coalesce(var.assume_role_policy, join("", 41 | data.aws_iam_policy_document.role.*.json))}" 42 | } 43 | 44 | resource "aws_iam_role_policy" "mod" { 45 | name = "${format("%s-%s-flowlog-role-policy", var.stack_name, var.name)}" 46 | role = "${aws_iam_role.mod.id}" 47 | 48 | policy = "${coalesce(var.policy, join("", 49 | data.aws_iam_policy_document.role_policy.*.json))}" 50 | 51 | depends_on = ["aws_iam_role.mod"] 52 | } 53 | 54 | resource "aws_cloudwatch_log_group" "mod" { 55 | name = "${format("%s-%s-flowlog", var.stack_name, var.name)}" 56 | 57 | retention_in_days = "${var.retention_in_days}" 58 | 59 | tags = "${merge(map( 60 | "Name", "${format("%s-%s-flowlog-cloudwatch-log-group", var.stack_name, var.name)}", 61 | "StackName", "${var.stack_name}", 62 | "Environment", "${var.environment}", 63 | "Version", "${var.version}" 64 | ), var.tags)}" 65 | } 66 | 67 | resource "aws_flow_log" "mod" { 68 | count = "${var.enable_logging ? 1 : 0}" 69 | 70 | log_group_name = "${aws_cloudwatch_log_group.mod.name}" 71 | iam_role_arn = "${aws_iam_role.mod.arn}" 72 | 73 | traffic_type = "${var.traffic_type}" 74 | 75 | vpc_id = "${var.vpc_id}" 76 | subnet_id = "${var.subnet_id}" 77 | eni_id = "${var.eni_id}" 78 | 79 | depends_on = [ 80 | "aws_cloudwatch_log_group.mod", 81 | "null_resource.depends_on" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /modules/aws/flowlog/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_flow_log.mod.id}" 3 | } 4 | 5 | output "role_unique_id" { 6 | value = "${aws_iam_role.mod.unique_id}" 7 | } 8 | 9 | output "role_arn" { 10 | value = "${aws_iam_role.mod.arn}" 11 | } 12 | 13 | output "role_name" { 14 | value = "${aws_iam_role.mod.name}" 15 | } 16 | 17 | output "policy_id" { 18 | value = "${aws_iam_role_policy.mod.id}" 19 | } 20 | 21 | output "policy_name" { 22 | value = "${aws_iam_role_policy.mod.id}" 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/flowlog/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | 7 | variable "enable_logging" { 8 | default = true 9 | } 10 | 11 | variable "assume_role_policy" { 12 | default = "" 13 | } 14 | 15 | variable "policy" { 16 | default = "" 17 | } 18 | 19 | variable "retention_in_days" { 20 | default = "14" 21 | } 22 | 23 | variable "vpc_id" { 24 | default = "" 25 | } 26 | 27 | variable "subnet_id" { 28 | default = "" 29 | } 30 | 31 | variable "eni_id" { 32 | default = "" 33 | } 34 | 35 | variable "traffic_type" { 36 | default = "ALL" 37 | } 38 | 39 | variable "tags" { 40 | default = {} 41 | } 42 | 43 | variable "depends_on" { 44 | default = [] 45 | } 46 | -------------------------------------------------------------------------------- /modules/aws/iam/instance-profile/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_iam_policy_document" "mod" { 2 | count = "${var.assume_role_policy != "" ? 0 : 1}" 3 | 4 | statement { 5 | principals { 6 | type = "Service" 7 | identifiers = [ 8 | "ec2.amazonaws.com" 9 | ] 10 | } 11 | 12 | actions = [ 13 | "sts:AssumeRole" 14 | ] 15 | } 16 | } 17 | 18 | resource "aws_iam_role" "mod" { 19 | name = "${format("%s-%s-instance-role", var.stack_name, var.name)}" 20 | 21 | assume_role_policy = "${coalesce(var.assume_role_policy, join("", 22 | data.aws_iam_policy_document.mod.*.json))}" 23 | } 24 | 25 | resource "aws_iam_instance_profile" "mod" { 26 | name = "${format("%s-%s-instance-profile", var.stack_name, var.name)}" 27 | role = "${aws_iam_role.mod.name}" 28 | 29 | // This is to resolve an issue with Instance Profile creation, 30 | // where the underlying profile is still being created, but other 31 | // resources that use it would try to access it already, see: 32 | // https://github.com/hashicorp/terraform/issues/1885 33 | provisioner "local-exec" { 34 | command = "sleep 30" 35 | } 36 | 37 | depends_on = ["aws_iam_role.mod"] 38 | } 39 | -------------------------------------------------------------------------------- /modules/aws/iam/instance-profile/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_iam_instance_profile.mod.id}" 3 | } 4 | 5 | output "arn" { 6 | value = "${aws_iam_instance_profile.mod.arn}" 7 | } 8 | 9 | output "name" { 10 | value = "${aws_iam_instance_profile.mod.name}" 11 | } 12 | 13 | output "role_id" { 14 | value = "${aws_iam_role.mod.id}" 15 | } 16 | 17 | output "role_arn" { 18 | value = "${aws_iam_role.mod.arn}" 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/iam/instance-profile/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | 3 | variable "name" {} 4 | 5 | variable "assume_role_policy" { 6 | default = "" 7 | } 8 | -------------------------------------------------------------------------------- /modules/aws/internet-gateway/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_internet_gateway" "mod" { 8 | vpc_id = "${var.vpc_id}" 9 | 10 | tags = "${merge(map( 11 | "Name", "${format("%s-internet-gateway", var.stack_name)}", 12 | "StackName", "${var.stack_name}", 13 | "Environment", "${var.environment}", 14 | "Version", "${var.version}" 15 | ), var.tags)}" 16 | 17 | depends_on = ["null_resource.depends_on"] 18 | } 19 | -------------------------------------------------------------------------------- /modules/aws/internet-gateway/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_internet_gateway.mod.id}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/internet-gateway/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "vpc_id" {} 6 | 7 | variable "tags" { 8 | default = {} 9 | } 10 | 11 | variable "depends_on" { 12 | default = [] 13 | } 14 | -------------------------------------------------------------------------------- /modules/aws/key-pair/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | 3 | FILES ?= $(shell find . -type f -name '*.sh') 4 | 5 | .SUFFIXES: 6 | 7 | .PHONY: help test static 8 | 9 | all: static 10 | 11 | help: 12 | @echo 'Usage: make ... ' 13 | @echo '' 14 | @echo 'Available targets are:' 15 | @echo '' 16 | @echo ' help Show this help screen.' 17 | @echo ' test Run unit tests.' 18 | @echo ' static Run shellcheck.' 19 | @echo '' 20 | @echo 'Target run by default is static.' 21 | @echo '' 22 | 23 | print-%: 24 | @echo $* = $($*) 25 | 26 | test: 27 | @$(MAKE) -C ./test all 28 | 29 | static: 30 | $(eval QUIET := $(shell test "$(MAKECMDGOALS)" == "static" || echo 1)) 31 | @shellcheck -s bash $(FILES) $(shell test -z "$(QUIET)" || echo '&>/dev/null'); \ 32 | if (( $$? > 0 )); then \ 33 | if [[ -n "$(QUIET)" ]]; then \ 34 | echo "shellcheck found number of issues. Run 'make static' to check directly."; \ 35 | else \ 36 | exit $$?; \ 37 | fi; \ 38 | fi 39 | -------------------------------------------------------------------------------- /modules/aws/key-pair/README.md: -------------------------------------------------------------------------------- 1 | # key-pair 2 | 3 | This is a Terraform module to create a key-pair in the current account which can be used when 4 | starting a standalone EC2 instances or as part of the Auto-Scaling Group launch configuration. 5 | 6 | By default, this module creates both the public and private keys automatically, and derives 7 | name of the key-pair to be created from the `stack_name` variable. An existing public key in 8 | the OpenSSH public key format can be provided using the `public_key` variable, whereas the 9 | key-pair name can be overridden using the `key_name` variable. 10 | 11 | ## Requirements 12 | 13 | - Terraform 0.10.x or higher; 14 | - Bash 4.0 or higher; 15 | - jq 1.5 or higher. 16 | 17 | This module requires a Bash shell and jq for its helper script, and assumes that the jq binary 18 | is available from within the current environment. 19 | 20 | ## Dependencies 21 | 22 | None. 23 | 24 | ## Usage 25 | 26 | #### Example of a key-pair with public and private keys created automatically: 27 | 28 | ```ruby 29 | module "example_key_pair" { 30 | source = "./key-pair" 31 | 32 | stack_name = "example-stack" 33 | } 34 | ``` 35 | 36 | #### Example of a key-pair using public key given as an inline value and a custom key-pair name: 37 | 38 | ```ruby 39 | module "deploy_key_pair" { 40 | source = "./key-pair" 41 | 42 | stack_name = "example-stack" 43 | public_key = "ssh-rsa AAAAB3NzaC1 (...)" 44 | key_name = "deploy" 45 | } 46 | ``` 47 | 48 | #### Example of a key-pair with an existing public key and a custom key-pair name: 49 | 50 | ```ruby 51 | module "jenkins_key_pair" { 52 | source = "./key-pair" 53 | 54 | stack_name = "example-stack" 55 | public_key = "./example/id_rsa.pub" 56 | key_name = "jenkins" 57 | } 58 | ``` 59 | 60 | ## Variables 61 | 62 | | Name | Description | Type | Default | Required | 63 | |------|-------------|:-----:|:-----:|:-----:| 64 | | stack_name | A custom stack name to use. | String || Yes | 65 | | algorithm | The name of the algorithm to use for the key, can be either "RSA" or "ECDSA". Note that the elliptic curve algorithm "ECDSA" is currently not supported by AWS.| String | RSA | No || 66 | | rsa_bits | The size of the generated RSA key in bits. | Integer | 4096 | No || 67 | | ecdsa_curve | The name of the elliptic curve to use, can be either "P224", "P256", "P384", or "P521". | String | P384 | No | 68 | | public_key | Either path to file containing public key in the OpenSSH public key format, or a value containing the public key. | String || No | 69 | | key_name | The name of the key-pair. | String || No | 70 | | depends_on | A list of dependencies to hook into the underlying `aws_key_pair` resource in this module. This value should be a list that contains interpolations from the resources you want to add as dependencies. | List || No | 71 | 72 | ## Outputs 73 | 74 | | Name | Description | Type | 75 | |------|-------------|:----:| 76 | | key_name | The name of the key-pair. | String | 77 | | algorithm | The name of the algorithm that was selected for the key. | String | 78 | | private_key_pem | The private key in the PEM format. | String | 79 | | public_key_pem | The public key in the PEM format. | String | 80 | | public_key | The public key in the OpenSSH public key format. | String | 81 | | fingerprint | The public key fingerprint as 128-bit MD5 value. | String | 82 | 83 | ## Notes 84 | 85 | This module uses am external data source and a helper script called `public-key.sh` in order to 86 | provide an ability for the module to handle the following two use cases: 87 | 88 | 1. Create a new key-pair automatically, when no public key has been provided; or 89 | 2. Use existing public key if a valid path to a file has been given. 90 | 91 | Unfortunately, this could not be implemented using the `file` helper from Terraform, as such 92 | helpers always execute (even if the resource block has `count` attribute set to 0), therefore 93 | passing an empty variable would result in a failure due to an inability for the `file` helper 94 | to locate and load a file from a given path. The external data source, which would also execute 95 | every time, contains a logic to check whether a file exists or not, and either return content 96 | of the file or an empty value otherwise. 97 | 98 | ## Known issues 99 | 100 | The fingerprint output value might not be immediately available after the key-pair has been 101 | created, which can be resolved by either running `terraform refresh` or `terraform apply` 102 | again in order to force Terraform to refresh dynamically computed values. 103 | 104 | In a case where the public and private keys were created automatically, then the private 105 | key will be stored unencrypted in the resulting Terraform state file. This should be taken 106 | into consideration as a possible security risk, therefore use of such key-pair for production 107 | deployments is generally _not_ recommended. 108 | 109 | ## References 110 | 111 | This module uses Terraform [aws_key_pair](https://www.terraform.io/docs/providers/aws/r/key_pair.html) and 112 | [tls_private_key](https://www.terraform.io/docs/providers/tls/r/private_key.html) resources, and the 113 | [External Data Source](https://www.terraform.io/docs/providers/external/data_source.html) internally. 114 | 115 | For the details about private and public keys formats, see the following documents: 116 | 117 | - "The Secure Shell (SSH) Transport Layer Protocol", [RFC4253](https://tools.ietf.org/html/rfc4253); and 118 | - "The Secure Shell (SSH) Public Key File Format", [RFC4716](https://tools.ietf.org/html/rfc4716). 119 | 120 | For latest jq binary, see the download section at the jq project [page](https://stedolan.github.io/jq/). 121 | -------------------------------------------------------------------------------- /modules/aws/key-pair/main.tf: -------------------------------------------------------------------------------- 1 | data "external" "mod" { 2 | count = "${var.public_key == "" ? 0 : 1}" 3 | 4 | program = ["bash", "${path.module}/scripts/public-key.sh"] 5 | 6 | query = { 7 | public_key = "${var.public_key}" 8 | } 9 | } 10 | 11 | resource "null_resource" "depends_on" { 12 | triggers { 13 | depends_on = "${join("", var.depends_on)}" 14 | } 15 | } 16 | 17 | resource "tls_private_key" "mod" { 18 | count = "${var.public_key != "" ? 0 : 1}" 19 | 20 | algorithm = "${var.algorithm}" 21 | rsa_bits = "${var.rsa_bits}" 22 | ecdsa_curve = "${var.ecdsa_curve}" 23 | } 24 | 25 | resource "aws_key_pair" "mod" { 26 | key_name = "${coalesce(var.key_name, format("%s-key-pair", var.stack_name))}" 27 | public_key = "${chomp(var.public_key != "" 28 | ? join("", data.external.mod.*.result.public_key) 29 | : join("", tls_private_key.mod.*.public_key_openssh))}" 30 | 31 | depends_on = ["null_resource.depends_on"] 32 | } 33 | -------------------------------------------------------------------------------- /modules/aws/key-pair/outputs.tf: -------------------------------------------------------------------------------- 1 | output "key_name" { 2 | value = "${aws_key_pair.mod.key_name}" 3 | } 4 | 5 | output "algorithm" { 6 | value = "${tls_private_key.mod.algorithm}" 7 | } 8 | 9 | output "private_key_pem" { 10 | value = "${tls_private_key.mod.private_key_pem}" 11 | } 12 | 13 | output "public_key_pem" { 14 | value = "${tls_private_key.mod.public_key_pem}" 15 | } 16 | 17 | output "public_key" { 18 | value = "${chomp(var.public_key != "" 19 | ? join("", data.external.mod.*.result.public_key) 20 | : join("", tls_private_key.mod.*.public_key_openssh))}" 21 | } 22 | 23 | output "fingerprint" { 24 | value = "${aws_key_pair.mod.fingerprint}" 25 | } 26 | -------------------------------------------------------------------------------- /modules/aws/key-pair/scripts/public-key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | print_public_key() { 8 | local key=$1 9 | 10 | if [[ -n "$key" ]]; then 11 | jq -c -n --arg public_key "$key" '{ "public_key": $public_key }' 12 | else 13 | echo '{"public_key":""}' 14 | fi 15 | } 16 | 17 | export PATH='/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin' 18 | 19 | PUBLIC_KEY=${PUBLIC_KEY-} 20 | 21 | if ! test -t 0; then 22 | eval "$(jq -r '@sh "PUBLIC_KEY=\(.public_key)"')" 23 | fi 24 | 25 | if [[ -f $PUBLIC_KEY ]]; then 26 | print_public_key "$(cat "${PUBLIC_KEY}")" 27 | else 28 | print_public_key "${PUBLIC_KEY}" 29 | fi 30 | -------------------------------------------------------------------------------- /modules/aws/key-pair/test/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @bats . 3 | -------------------------------------------------------------------------------- /modules/aws/key-pair/test/fixtures/id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDIdjL5gRciIvyohU3lk1tN9E0wKwJfX+eX8b7ajG+t05sn+D8W4i4QpdZ8MlIEtOtWh+BzfgFqnR3z4JhBPMzklIyhXBhCkmy/TDkeZdNCm52VPh5YifzgdeRMgcs8ZCwjr/wBBJaqxDxCx+el8qAhiACs/Xqs25nOpcWgfq5qsdxFStJKr5oMzf0IkuXGVImlzjdJaIbrjhfZ/CFM3W3+OHJlf21SPr+Ib9+aTLCfi59r3E3irUQ3/tfqCEDI7XXdbD418IRLB3S6R+/tpiWFML9qGvq2e45JTyrkBBe4qQq9Kql6MnLM9qGMk8z1sWsbOCCJlpN6zLImUp63m0hENEefghetwkaC/CTzZ0jc1aM0OCNfxB7xEv7Ny2RtQFDEBCxkLWwbTCSP06e5LKys2W0kAYGreWAHW3lbxt93xdT1laKso9MkX6/2nnHNv00sP6gseA0V33RLE0RS9u66ZxXLH5gU2q07VXFU0qQtU8PG80ktPT4aHTgm5QdOxSquwgbiY0h50r+PzHjj55hjha3WaUAsvY9cUTV4WRkQA8w40oVhlvLuHRjgVdoDVmdpraN642ds0nvLNlu1yg/4PfO4X31R1+U4HTg8MEfx6TtwMd9Q/fO+nSBQ1SwKj4F5FsoJCZH5goU6vjXDVP+cAUa/9YaBxZH6StrwCTYO3Q== 2 | -------------------------------------------------------------------------------- /modules/aws/key-pair/test/integration/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" {} 2 | 3 | module "key_pair_test_1" { 4 | source = "../../" 5 | 6 | stack_name = "test_1" 7 | } 8 | 9 | module "key_pair_test_2" { 10 | source = "../../" 11 | 12 | stack_name = "test_2" 13 | public_key = "../fixtures/id_rsa.pub" 14 | key_name = "key_pair_test_2" 15 | } 16 | 17 | output "key_pair_test_1_key_name" { 18 | value = "${module.key_pair_test_1.key_name}" 19 | } 20 | 21 | output "key_pair_test_1_algorithm" { 22 | value = "${module.key_pair_test_1.algorithm}" 23 | } 24 | 25 | output "key_pair_test_1_fingerprint" { 26 | value = "${module.key_pair_test_1.fingerprint}" 27 | } 28 | 29 | output "key_pair_test_2_key_name" { 30 | value = "${module.key_pair_test_2.key_name}" 31 | } 32 | 33 | output "key_pair_test_2_fingerprint" { 34 | value = "${module.key_pair_test_2.fingerprint}" 35 | } 36 | -------------------------------------------------------------------------------- /modules/aws/key-pair/test/integration/test.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | @test 'Check key-pair test_1 key_name' { 4 | run bash -c "terraform output | grep test_1_key_name" 5 | [[ ${lines[0]} =~ "test_1-key-pair" ]] 6 | } 7 | 8 | @test 'Check key-pair test_1 algorithm' { 9 | run bash -c "terraform output | grep test_1_algorithm" 10 | [[ ${lines[0]} =~ "RSA" ]] 11 | } 12 | 13 | @test 'Check key-pair test_1 fingerprint' { 14 | run bash -c "terraform output | grep test_1_fingerprint" 15 | [[ ${lines[0]} =~ [a-z0-9:]* ]] 16 | } 17 | 18 | @test 'Check key-pair test_2 key_name' { 19 | run bash -c "terraform output | grep test_2_key_name" 20 | [[ ${lines[0]} =~ "key_pair_test_2" ]] 21 | } 22 | 23 | @test 'Check key-pair test_2 algorithm' { 24 | run bash -c "terraform output | grep test_2_algorithm" 25 | [[ $status == 1 ]] 26 | } 27 | 28 | @test 'Check key-pair test_2 fingerprint' { 29 | run bash -c "terraform output | grep test_2_fingerprint" 30 | [[ ${lines[0]} =~ "7d:e0:81:e3:92:cc:79:81:6a:c3:37:03:aa:79:46:98" ]] 31 | } 32 | -------------------------------------------------------------------------------- /modules/aws/key-pair/test/test.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | @test 'Check public-key.sh without any input' { 4 | run bash -c "echo | bash ../scripts/public-key.sh" 5 | [[ ${lines[0]} == '{"public_key":""}' ]] 6 | } 7 | 8 | @test 'Check public-key.sh empty input' { 9 | run bash -c "echo | bash ../scripts/public-key.sh" 10 | [[ ${lines[0]} == '{"public_key":""}' ]] 11 | } 12 | 13 | @test 'Check public-key.sh non-existent public key file' { 14 | run bash -c "echo '{ \"public_key\": \"/nonexistent\" }' | bash ../scripts/public-key.sh" 15 | [[ ${lines[0]} == '{"public_key":"/nonexistent"}' ]] 16 | } 17 | 18 | @test 'Check public-key.sh valid public key file' { 19 | run bash -c "echo '{ \"public_key\": \"fixtures/id_rsa.pub\" }' | bash ../scripts/public-key.sh" 20 | [[ ${lines[0]} =~ "ssh-rsa" ]] 21 | } 22 | 23 | @test 'Check public-key.sh valid JSON output' { 24 | run bash -c "echo '{ \"public_key\": \"fixtures/id_rsa.pub\" }' | bash ../scripts/public-key.sh | jq ." 25 | [[ $status == 0 ]] 26 | } 27 | -------------------------------------------------------------------------------- /modules/aws/key-pair/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | 3 | variable "algorithm" { 4 | default = "RSA" 5 | } 6 | 7 | variable "rsa_bits" { 8 | default = 4096 9 | } 10 | 11 | variable "ecdsa_curve" { 12 | default = "P384" 13 | } 14 | 15 | variable "public_key" { 16 | default = "" 17 | } 18 | 19 | variable "key_name" { 20 | default = "" 21 | } 22 | 23 | variable "depends_on" { 24 | default = [] 25 | } 26 | -------------------------------------------------------------------------------- /modules/aws/key-pair/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/kms/main.tf: -------------------------------------------------------------------------------- 1 | data "null_data_source" "mod" { 2 | inputs { 3 | alias_name = "${format("alias/%s", element(split("alias/", coalesce(var.alias, 4 | format("%s-%s-kms-alias", var.stack_name, var.name))), 1))}" 5 | } 6 | } 7 | 8 | data "aws_caller_identity" "mod" { 9 | count = "${length(var.principal_arns) != 0 ? 0 : 1}" 10 | } 11 | 12 | data "aws_iam_policy_document" "mod" { 13 | count = "${var.policy != "" ? 0 : 1}" 14 | 15 | statement { 16 | actions = [ 17 | "kms:*" 18 | ] 19 | 20 | resources = [ 21 | "*" 22 | ] 23 | 24 | principals { 25 | type = "AWS" 26 | identifiers = [ 27 | "${coalescelist(var.principal_arns, list( 28 | format("arn:aws:iam::%s:root", join("", 29 | data.aws_caller_identity.mod.*.account_id))))}" 30 | ] 31 | } 32 | } 33 | } 34 | 35 | resource "null_resource" "depends_on" { 36 | triggers { 37 | depends_on = "${join("", var.depends_on)}" 38 | } 39 | } 40 | 41 | resource "aws_kms_key" "mod" { 42 | description = "${coalesce(var.description, format("KMS Key - %s", var.name))}" 43 | 44 | key_usage = "${var.key_usage}" 45 | policy = "${coalesce(var.policy, join("", 46 | data.aws_iam_policy_document.mod.*.json))}" 47 | 48 | deletion_window_in_days = "${var.deletion_window_in_days}" 49 | 50 | is_enabled = "${var.is_enabled}" 51 | enable_key_rotation = "${var.enable_key_rotation}" 52 | 53 | tags = "${merge(map( 54 | "Name", "${format("%s-%s-kms-key", var.stack_name, var.name)}", 55 | "StackName", "${var.stack_name}", 56 | "Environment", "${var.environment}", 57 | "Version", "${var.version}" 58 | ), var.tags)}" 59 | 60 | depends_on = ["null_resource.depends_on"] 61 | } 62 | 63 | resource "aws_kms_alias" "mod" { 64 | name = "${format("alias/%s", element(split("alias/", coalesce(var.alias, 65 | data.null_data_source.mod.outputs.alias_name)), 1))}" 66 | 67 | target_key_id = "${aws_kms_key.mod.key_id}" 68 | 69 | depends_on = ["aws_kms_key.mod"] 70 | } 71 | -------------------------------------------------------------------------------- /modules/aws/kms/outputs.tf: -------------------------------------------------------------------------------- 1 | output "key_id" { 2 | value = "${aws_kms_key.mod.key_id}" 3 | } 4 | 5 | output "arn" { 6 | value = "${aws_kms_key.mod.arn}" 7 | } 8 | 9 | output "alias_name" { 10 | value = "${data.null_data_source.mod.outputs.alias_name}" 11 | } 12 | 13 | output "alias_arn" { 14 | value = "${aws_kms_alias.mod.arn}" 15 | } 16 | -------------------------------------------------------------------------------- /modules/aws/kms/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | 7 | variable "destruction" { 8 | default = "" 9 | } 10 | 11 | variable "principal_arns" { 12 | default = [] 13 | } 14 | 15 | variable "key_usage" { 16 | default = "" 17 | } 18 | 19 | variable "policy" { 20 | default = "" 21 | } 22 | 23 | variable "deletion_window_in_days" { 24 | default = 7 25 | } 26 | 27 | variable "is_enabled" { 28 | default = true 29 | } 30 | 31 | variable "enable_key_rotation" { 32 | default = false 33 | } 34 | 35 | variable "alias" { 36 | default = "" 37 | } 38 | 39 | variable "tags" { 40 | default = {} 41 | } 42 | 43 | variable "depends_on" { 44 | default = [] 45 | } 46 | -------------------------------------------------------------------------------- /modules/aws/nat-gateway/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_route53_zone" "mod" { 2 | count = "${var.zone_id != "" ? var.domain_name != "" ? 0 : 1 : 0}" 3 | 4 | zone_id = "${var.zone_id}" 5 | } 6 | 7 | resource "null_resource" "depends_on" { 8 | triggers { 9 | depends_on = "${join("", var.depends_on)}" 10 | } 11 | } 12 | 13 | resource "aws_eip" "mod" { 14 | count = "${length(var.eip_allocation_ids) == 0 ? var.count : 0}" 15 | 16 | vpc = true 17 | } 18 | 19 | resource "aws_nat_gateway" "mod" { 20 | count = "${var.count}" 21 | 22 | allocation_id = "${element(coalescelist(var.eip_allocation_ids, aws_eip.mod.*.id), count.index)}" 23 | subnet_id = "${element(var.subnet_ids, count.index)}" 24 | 25 | depends_on = [ 26 | "aws_eip.mod", 27 | "null_resource.depends_on" 28 | ] 29 | } 30 | 31 | resource "aws_route53_record" "mod" { 32 | count = "${var.zone_id != "" ? var.count : 0}" 33 | 34 | zone_id = "${coalesce(var.zone_id, "-")}" 35 | 36 | name = "${format("nat-gateway-%03d.%s", count.index + 1, coalesce(var.domain_name, 37 | join("", data.aws_route53_zone.mod.*.name)))}" 38 | 39 | type = "A" 40 | ttl = 60 41 | 42 | records = ["${element(aws_nat_gateway.mod.*.public_ip, count.index)}"] 43 | 44 | depends_on = ["aws_nat_gateway.mod"] 45 | } 46 | -------------------------------------------------------------------------------- /modules/aws/nat-gateway/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ids" { 2 | value = ["${aws_nat_gateway.mod.*.id}"] 3 | } 4 | 5 | output "allocation_ids" { 6 | value = ["${aws_nat_gateway.mod.*.allocation_id}"] 7 | } 8 | 9 | output "subnet_ids" { 10 | value = ["${aws_nat_gateway.mod.*.subnet_id}"] 11 | } 12 | 13 | output "network_interface_ids" { 14 | value = ["${aws_nat_gateway.mod.*.network_interface_id}"] 15 | } 16 | 17 | output "public_ips" { 18 | value = ["${aws_nat_gateway.mod.*.public_ip}"] 19 | } 20 | 21 | output "private_ips" { 22 | value = ["${aws_nat_gateway.mod.*.private_ip}"] 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/nat-gateway/variables.tf: -------------------------------------------------------------------------------- 1 | variable "count" { 2 | default = 1 3 | } 4 | 5 | variable "subnet_ids" { 6 | type = "list" 7 | } 8 | 9 | variable "eip_allocation_ids" { 10 | default = [] 11 | } 12 | 13 | variable "domain_name" { 14 | default = "" 15 | } 16 | 17 | variable "zone_id" { 18 | default = "" 19 | } 20 | 21 | variable "depends_on" { 22 | default = [] 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/network-acl/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_vpc" "mod" { 2 | id = "${var.vpc_id}" 3 | } 4 | 5 | resource "null_resource" "depends_on" { 6 | triggers { 7 | depends_on = "${join("", var.depends_on)}" 8 | } 9 | } 10 | 11 | resource "aws_network_acl" "mod" { 12 | vpc_id = "${var.vpc_id}" 13 | 14 | subnet_ids = ["${var.subnet_ids}"] 15 | 16 | tags = "${merge(map( 17 | "Name", "${format("%s-%s-network-acl", var.stack_name, var.name)}", 18 | "StackName", "${var.stack_name}", 19 | "Environment", "${var.environment}", 20 | "Version", "${var.version}" 21 | ), var.tags)}" 22 | 23 | depends_on = ["null_resource.depends_on"] 24 | } 25 | 26 | resource "aws_network_acl_rule" "rule_ingress_allow_icmp_echo" { 27 | network_acl_id = "${aws_network_acl.mod.id}" 28 | 29 | rule_number = 10 30 | rule_action = "allow" 31 | 32 | protocol = "icmp" 33 | cidr_block = "0.0.0.0/0" 34 | 35 | icmp_type = 8 36 | icmp_code = -1 37 | 38 | depends_on = ["aws_network_acl.mod"] 39 | } 40 | 41 | resource "aws_network_acl_rule" "rule_ingress_allow_icmp_echo_reply" { 42 | network_acl_id = "${aws_network_acl.mod.id}" 43 | 44 | rule_number = 11 45 | rule_action = "allow" 46 | 47 | protocol = "icmp" 48 | cidr_block = "0.0.0.0/0" 49 | 50 | icmp_type = 0 51 | icmp_code = -1 52 | 53 | depends_on = ["aws_network_acl.mod"] 54 | } 55 | 56 | resource "aws_network_acl_rule" "rule_ingress_allow_icmp_destination_unreachable" { 57 | network_acl_id = "${aws_network_acl.mod.id}" 58 | 59 | rule_number = 12 60 | rule_action = "allow" 61 | 62 | protocol = "icmp" 63 | cidr_block = "0.0.0.0/0" 64 | 65 | icmp_type = 3 66 | icmp_code = -1 67 | 68 | depends_on = ["aws_network_acl.mod"] 69 | } 70 | 71 | resource "aws_network_acl_rule" "rule_ingress_allow_icmp_source_quench" { 72 | network_acl_id = "${aws_network_acl.mod.id}" 73 | 74 | rule_number = 13 75 | rule_action = "allow" 76 | 77 | protocol = "icmp" 78 | cidr_block = "0.0.0.0/0" 79 | 80 | icmp_type = 4 81 | icmp_code = -1 82 | 83 | depends_on = ["aws_network_acl.mod"] 84 | } 85 | 86 | resource "aws_network_acl_rule" "rule_ingress_allow_icmp_time_exceeded" { 87 | network_acl_id = "${aws_network_acl.mod.id}" 88 | 89 | rule_number = 14 90 | rule_action = "allow" 91 | 92 | protocol = "icmp" 93 | cidr_block = "0.0.0.0/0" 94 | 95 | icmp_type = 11 96 | icmp_code = -1 97 | 98 | depends_on = ["aws_network_acl.mod"] 99 | } 100 | 101 | resource "aws_network_acl_rule" "rule_ingress_allow_dns_tcp" { 102 | network_acl_id = "${aws_network_acl.mod.id}" 103 | 104 | rule_number = 100 105 | rule_action = "allow" 106 | 107 | protocol = "tcp" 108 | cidr_block = "0.0.0.0/0" 109 | 110 | from_port = 53 111 | to_port = 53 112 | 113 | depends_on = ["aws_network_acl.mod"] 114 | } 115 | 116 | resource "aws_network_acl_rule" "rule_ingress_allow_dns_udp" { 117 | network_acl_id = "${aws_network_acl.mod.id}" 118 | 119 | rule_number = 101 120 | rule_action = "allow" 121 | 122 | protocol = "udp" 123 | cidr_block = "0.0.0.0/0" 124 | 125 | from_port = 53 126 | to_port = 53 127 | 128 | depends_on = ["aws_network_acl.mod"] 129 | } 130 | 131 | resource "aws_network_acl_rule" "rule_ingress_allow_time" { 132 | network_acl_id = "${aws_network_acl.mod.id}" 133 | 134 | rule_number = 102 135 | rule_action = "allow" 136 | 137 | protocol = "udp" 138 | cidr_block = "0.0.0.0/0" 139 | 140 | from_port = 123 141 | to_port = 123 142 | 143 | depends_on = ["aws_network_acl.mod"] 144 | } 145 | 146 | resource "aws_network_acl_rule" "rule_ingress_allow_ssh" { 147 | network_acl_id = "${aws_network_acl.mod.id}" 148 | 149 | rule_number = 200 150 | rule_action = "allow" 151 | 152 | protocol = "tcp" 153 | cidr_block = "0.0.0.0/0" 154 | 155 | from_port = 22 156 | to_port = 22 157 | 158 | depends_on = ["aws_network_acl.mod"] 159 | } 160 | 161 | resource "aws_network_acl_rule" "rule_ingress_allow_http" { 162 | network_acl_id = "${aws_network_acl.mod.id}" 163 | 164 | rule_number = 201 165 | rule_action = "allow" 166 | 167 | protocol = "tcp" 168 | cidr_block = "0.0.0.0/0" 169 | 170 | from_port = 80 171 | to_port = 80 172 | 173 | depends_on = ["aws_network_acl.mod"] 174 | } 175 | 176 | resource "aws_network_acl_rule" "rule_ingress_allow_https" { 177 | network_acl_id = "${aws_network_acl.mod.id}" 178 | 179 | rule_number = 202 180 | rule_action = "allow" 181 | 182 | protocol = "tcp" 183 | cidr_block = "0.0.0.0/0" 184 | 185 | from_port = 443 186 | to_port = 443 187 | 188 | depends_on = ["aws_network_acl.mod"] 189 | } 190 | 191 | resource "aws_network_acl_rule" "rule_ingress_allow_tcp_ephemeral_ports" { 192 | network_acl_id = "${aws_network_acl.mod.id}" 193 | 194 | rule_number = 900 195 | rule_action = "allow" 196 | 197 | protocol = "tcp" 198 | cidr_block = "0.0.0.0/0" 199 | 200 | from_port = 1024 201 | to_port = 65535 202 | 203 | depends_on = ["aws_network_acl.mod"] 204 | } 205 | 206 | resource "aws_network_acl_rule" "rule_ingress_allow_udp_ephemeral_ports" { 207 | network_acl_id = "${aws_network_acl.mod.id}" 208 | 209 | rule_number = 1000 210 | rule_action = "allow" 211 | 212 | protocol = "udp" 213 | cidr_block = "0.0.0.0/0" 214 | 215 | from_port = 1024 216 | to_port = 65535 217 | 218 | depends_on = ["aws_network_acl.mod"] 219 | } 220 | 221 | resource "aws_network_acl_rule" "rule_egress_allow_icmp_echo" { 222 | network_acl_id = "${aws_network_acl.mod.id}" 223 | 224 | egress = true 225 | 226 | rule_number = 10 227 | rule_action = "allow" 228 | 229 | protocol = "icmp" 230 | cidr_block = "0.0.0.0/0" 231 | 232 | icmp_type = 8 233 | icmp_code = -1 234 | 235 | depends_on = ["aws_network_acl.mod"] 236 | } 237 | 238 | resource "aws_network_acl_rule" "rule_egress_allow_icmp_echo_reply" { 239 | network_acl_id = "${aws_network_acl.mod.id}" 240 | 241 | egress = true 242 | 243 | rule_number = 11 244 | rule_action = "allow" 245 | 246 | protocol = "icmp" 247 | cidr_block = "0.0.0.0/0" 248 | 249 | icmp_type = 0 250 | icmp_code = -1 251 | 252 | depends_on = ["aws_network_acl.mod"] 253 | } 254 | 255 | resource "aws_network_acl_rule" "rule_egress_allow_icmp_destination_unreachable" { 256 | network_acl_id = "${aws_network_acl.mod.id}" 257 | 258 | egress = true 259 | 260 | rule_number = 12 261 | rule_action = "allow" 262 | 263 | protocol = "icmp" 264 | cidr_block = "0.0.0.0/0" 265 | 266 | icmp_type = 3 267 | icmp_code = -1 268 | 269 | depends_on = ["aws_network_acl.mod"] 270 | } 271 | 272 | resource "aws_network_acl_rule" "rule_egress_allow_icmp_source_quench" { 273 | network_acl_id = "${aws_network_acl.mod.id}" 274 | 275 | egress = true 276 | 277 | rule_number = 13 278 | rule_action = "allow" 279 | 280 | protocol = "icmp" 281 | cidr_block = "0.0.0.0/0" 282 | 283 | icmp_type = 4 284 | icmp_code = -1 285 | 286 | depends_on = ["aws_network_acl.mod"] 287 | } 288 | 289 | resource "aws_network_acl_rule" "rule_egress_allow_icmp_time_exceeded" { 290 | network_acl_id = "${aws_network_acl.mod.id}" 291 | 292 | egress = true 293 | 294 | rule_number = 14 295 | rule_action = "allow" 296 | 297 | protocol = "icmp" 298 | cidr_block = "0.0.0.0/0" 299 | 300 | icmp_type = 11 301 | icmp_code = -1 302 | 303 | depends_on = ["aws_network_acl.mod"] 304 | } 305 | 306 | resource "aws_network_acl_rule" "rule_egress_allow_dns_tcp" { 307 | network_acl_id = "${aws_network_acl.mod.id}" 308 | 309 | egress = true 310 | 311 | rule_number = 100 312 | rule_action = "allow" 313 | 314 | protocol = "tcp" 315 | cidr_block = "0.0.0.0/0" 316 | 317 | from_port = 53 318 | to_port = 53 319 | 320 | depends_on = ["aws_network_acl.mod"] 321 | } 322 | 323 | resource "aws_network_acl_rule" "rule_egress_allow_dns_udp" { 324 | network_acl_id = "${aws_network_acl.mod.id}" 325 | 326 | egress = true 327 | 328 | rule_number = 101 329 | rule_action = "allow" 330 | 331 | protocol = "udp" 332 | cidr_block = "0.0.0.0/0" 333 | 334 | from_port = 53 335 | to_port = 53 336 | 337 | depends_on = ["aws_network_acl.mod"] 338 | } 339 | 340 | resource "aws_network_acl_rule" "rule_egress_allow_time" { 341 | network_acl_id = "${aws_network_acl.mod.id}" 342 | 343 | egress = true 344 | 345 | rule_number = 102 346 | rule_action = "allow" 347 | 348 | protocol = "udp" 349 | cidr_block = "0.0.0.0/0" 350 | 351 | from_port = 123 352 | to_port = 123 353 | 354 | depends_on = ["aws_network_acl.mod"] 355 | } 356 | 357 | resource "aws_network_acl_rule" "rule_egress_allow_ssh" { 358 | network_acl_id = "${aws_network_acl.mod.id}" 359 | 360 | egress = true 361 | 362 | rule_number = 200 363 | rule_action = "allow" 364 | 365 | protocol = "tcp" 366 | cidr_block = "${data.aws_vpc.mod.cidr_block}" 367 | 368 | from_port = 22 369 | to_port = 22 370 | 371 | depends_on = ["aws_network_acl.mod"] 372 | } 373 | 374 | resource "aws_network_acl_rule" "rule_egress_allow_http" { 375 | network_acl_id = "${aws_network_acl.mod.id}" 376 | 377 | egress = true 378 | 379 | rule_number = 201 380 | rule_action = "allow" 381 | 382 | protocol = "tcp" 383 | cidr_block = "0.0.0.0/0" 384 | 385 | from_port = 80 386 | to_port = 80 387 | 388 | depends_on = ["aws_network_acl.mod"] 389 | } 390 | 391 | resource "aws_network_acl_rule" "rule_egress_allow_https" { 392 | network_acl_id = "${aws_network_acl.mod.id}" 393 | 394 | egress = true 395 | 396 | rule_number = 202 397 | rule_action = "allow" 398 | 399 | protocol = "tcp" 400 | cidr_block = "0.0.0.0/0" 401 | 402 | from_port = 443 403 | to_port = 443 404 | 405 | depends_on = ["aws_network_acl.mod"] 406 | } 407 | 408 | resource "aws_network_acl_rule" "rule_egress_allow_tcp_ephemeral_ports" { 409 | network_acl_id = "${aws_network_acl.mod.id}" 410 | 411 | egress = true 412 | 413 | rule_number = 900 414 | rule_action = "allow" 415 | 416 | protocol = "tcp" 417 | cidr_block = "0.0.0.0/0" 418 | 419 | from_port = 1024 420 | to_port = 65535 421 | 422 | depends_on = ["aws_network_acl.mod"] 423 | } 424 | 425 | resource "aws_network_acl_rule" "rule_egress_allow_udp_ephemeral_ports" { 426 | network_acl_id = "${aws_network_acl.mod.id}" 427 | 428 | egress = true 429 | 430 | rule_number = 1000 431 | rule_action = "allow" 432 | 433 | protocol = "udp" 434 | cidr_block = "0.0.0.0/0" 435 | 436 | from_port = 1024 437 | to_port = 65535 438 | 439 | depends_on = ["aws_network_acl.mod"] 440 | } 441 | -------------------------------------------------------------------------------- /modules/aws/network-acl/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_network_acl.mod.id}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/network-acl/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | variable "vpc_id" {} 7 | 8 | variable "subnet_ids" { 9 | type = "list" 10 | } 11 | 12 | variable "tags" { 13 | default = {} 14 | } 15 | 16 | variable "depends_on" { 17 | default = [] 18 | } 19 | -------------------------------------------------------------------------------- /modules/aws/route-table/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_route_table" "mod" { 8 | vpc_id = "${var.vpc_id}" 9 | 10 | propagating_vgws = ["${var.propagating_vgws}"] 11 | 12 | tags = "${merge(map( 13 | "Name", "${format("%s-%s-route-table", var.stack_name, var.name)}", 14 | "StackName", "${var.stack_name}", 15 | "Environment", "${var.environment}", 16 | "Version", "${var.version}" 17 | ), var.tags)}" 18 | 19 | depends_on = ["null_resource.depends_on"] 20 | } 21 | -------------------------------------------------------------------------------- /modules/aws/route-table/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_route_table.mod.id}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/route-table/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | variable "vpc_id" {} 7 | 8 | variable "propagating_vgws" { 9 | default = [] 10 | } 11 | 12 | variable "tags" { 13 | default = {} 14 | } 15 | 16 | variable "depends_on" { 17 | default = [] 18 | } 19 | -------------------------------------------------------------------------------- /modules/aws/route/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_route" "mod" { 8 | route_table_id = "${var.route_table_id}" 9 | 10 | destination_cidr_block = "${var.destination_cidr_block}" 11 | vpc_peering_connection_id = "${var.vpc_peering_connection_id}" 12 | gateway_id = "${var.gateway_id}" 13 | nat_gateway_id = "${var.nat_gateway_id}" 14 | instance_id = "${var.instance_id}" 15 | network_interface_id = "${var.network_interface_id}" 16 | 17 | depends_on = ["null_resource.depends_on"] 18 | } 19 | 20 | resource "aws_route_table_association" "mod" { 21 | count = "${var.subnet_id == "" ? 0 : 1}" 22 | 23 | subnet_id = "${var.subnet_id}" 24 | route_table_id = "${var.route_table_id}" 25 | 26 | depends_on = ["aws_route.mod"] 27 | } 28 | -------------------------------------------------------------------------------- /modules/aws/route/outputs.tf: -------------------------------------------------------------------------------- 1 | output "route_table_id" { 2 | value = "${aws_route.mod.route_table_id}" 3 | } 4 | 5 | output "destination_cidr_block" { 6 | value = "${aws_route.mod.destination_cidr_block}" 7 | } 8 | 9 | output "vpc_peering_connection_id" { 10 | value = "${aws_route.mod.vpc_peering_connection_id}" 11 | } 12 | 13 | output "gateway_id" { 14 | value = "${aws_route.mod.gateway_id}" 15 | } 16 | 17 | output "nat_gateway_id" { 18 | value = "${aws_route.mod.nat_gateway_id}" 19 | } 20 | 21 | output "instance_id" { 22 | value = "${aws_route.mod.instance_id}" 23 | } 24 | 25 | output "network_interface_id" { 26 | value = "${aws_route.mod.network_interface_id}" 27 | } 28 | 29 | output "route_table_association_id" { 30 | value = "${aws_route_table_association.mod.id}" 31 | } 32 | 33 | output "subnet_id" { 34 | value = "${aws_route_table_association.mod.subnet_id}" 35 | } 36 | -------------------------------------------------------------------------------- /modules/aws/route/variables.tf: -------------------------------------------------------------------------------- 1 | variable "route_table_id" {} 2 | 3 | variable "subnet_id" { 4 | default = "" 5 | } 6 | 7 | variable "destination_cidr_block" { 8 | default = "" 9 | } 10 | 11 | variable "vpc_peering_connection_id" { 12 | default = "" 13 | } 14 | 15 | variable "gateway_id" { 16 | default = "" 17 | } 18 | 19 | variable "nat_gateway_id" { 20 | default = "" 21 | } 22 | 23 | variable "instance_id" { 24 | default = "" 25 | } 26 | 27 | variable "network_interface_id" { 28 | default = "" 29 | } 30 | 31 | variable "depends_on" { 32 | default = [] 33 | } 34 | -------------------------------------------------------------------------------- /modules/aws/route53/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_route53_zone" "mod" { 8 | name = "${var.name}" 9 | comment = "${coalesce(var.comment, format("Hosted Zone - %s", var.stack_name))}" 10 | 11 | vpc_id = "${var.vpc_id}" 12 | 13 | force_destroy = "${var.force_destroy}" 14 | 15 | tags = "${merge(map( 16 | "Name", "${format("%s-route53-zone", var.stack_name)}", 17 | "StackName", "${var.stack_name}", 18 | "Environment", "${var.environment}", 19 | "Version", "${var.version}", 20 | "${var.vpc_id == "" ? "Public" : "Private"}", "true" 21 | ), var.tags)}" 22 | 23 | depends_on = ["null_resource.depends_on"] 24 | } 25 | -------------------------------------------------------------------------------- /modules/aws/route53/outputs.tf: -------------------------------------------------------------------------------- 1 | output "zone_id" { 2 | value = "${aws_route53_zone.mod.zone_id}" 3 | } 4 | 5 | output "name_servers" { 6 | value = ["${aws_route53_zone.mod.name_servers}"] 7 | } 8 | -------------------------------------------------------------------------------- /modules/aws/route53/private/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_route53_zone" "mod" { 2 | count = "${var.name != "" ? 0 : 1}" 3 | 4 | zone_id = "${var.zone_id}" 5 | } 6 | 7 | module "route53_zone" { 8 | source = "../" 9 | 10 | stack_name = "${var.stack_name}" 11 | environment = "${var.environment}" 12 | version = "${var.version}" 13 | 14 | name = "${coalesce(var.name, join("", data.aws_route53_zone.mod.*.name))}" 15 | comment = "${coalesce(var.comment, format("Private Hosted Zone - %s", var.stack_name))}" 16 | 17 | vpc_id = "${var.vpc_id}" 18 | 19 | force_destroy = "${var.force_destroy}" 20 | 21 | tags = "${merge(map( 22 | "Name", "${format("%s-private-route53-zone", var.stack_name)}" 23 | ), var.tags)}" 24 | 25 | depends_on = ["${var.depends_on}"] 26 | } 27 | -------------------------------------------------------------------------------- /modules/aws/route53/private/outputs.tf: -------------------------------------------------------------------------------- 1 | output "zone_id" { 2 | value = "${module.route53_zone.zone_id}" 3 | } 4 | 5 | output "name_servers" { 6 | value = ["${module.route53_zone.name_servers}"] 7 | } 8 | -------------------------------------------------------------------------------- /modules/aws/route53/private/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "vpc_id" {} 6 | 7 | variable "name" { 8 | default = "" 9 | } 10 | 11 | variable "zone_id" { 12 | default = "" 13 | } 14 | 15 | variable "comment" { 16 | default = "" 17 | } 18 | 19 | variable "force_destroy" { 20 | default = false 21 | } 22 | 23 | variable "tags" { 24 | default = {} 25 | } 26 | 27 | variable "depends_on" { 28 | default = [] 29 | } 30 | -------------------------------------------------------------------------------- /modules/aws/route53/reverse/main.tf: -------------------------------------------------------------------------------- 1 | module "ptr" { 2 | source = "../../../common/ptr-calculator" 3 | 4 | host = "${var.cidr_block}" 5 | type = "network" 6 | } 7 | 8 | module "route53_zone" { 9 | source = "../" 10 | 11 | stack_name = "${var.stack_name}" 12 | environment = "${var.environment}" 13 | version = "${var.version}" 14 | 15 | name = "${module.ptr.ptr}" 16 | 17 | comment = "${coalesce(var.comment, format("Private Reverse Hosted Zone - %s (%s)", 18 | var.stack_name, var.cidr_block))}" 19 | 20 | vpc_id = "${var.vpc_id}" 21 | 22 | force_destroy = "${var.force_destroy}" 23 | 24 | tags = "${merge(map( 25 | "Name", "${format("%s-private-reverse-route53-zone", var.stack_name)}", 26 | "Reverse", "true" 27 | ), var.tags)}" 28 | 29 | depends_on = ["${var.depends_on}"] 30 | } 31 | -------------------------------------------------------------------------------- /modules/aws/route53/reverse/outputs.tf: -------------------------------------------------------------------------------- 1 | output "zone_id" { 2 | value = "${module.route53_zone.zone_id}" 3 | } 4 | 5 | output "name_servers" { 6 | value = ["${module.route53_zone.name_servers}"] 7 | } 8 | -------------------------------------------------------------------------------- /modules/aws/route53/reverse/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "cidr_block" {} 6 | variable "vpc_id" {} 7 | 8 | variable "comment" { 9 | default = "" 10 | } 11 | 12 | variable "force_destroy" { 13 | default = false 14 | } 15 | 16 | variable "tags" { 17 | default = {} 18 | } 19 | 20 | variable "depends_on" { 21 | default = [] 22 | } 23 | -------------------------------------------------------------------------------- /modules/aws/route53/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | 7 | variable "comment" { 8 | default = "" 9 | } 10 | 11 | variable "vpc_id" { 12 | default = "" 13 | } 14 | 15 | variable "force_destroy" { 16 | default = false 17 | } 18 | 19 | variable "tags" { 20 | default = {} 21 | } 22 | 23 | variable "depends_on" { 24 | default = [] 25 | } 26 | -------------------------------------------------------------------------------- /modules/aws/s3-bucket/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "mod" { 2 | count = "${length(var.principal_arns) != 0 ? 0 : 1}" 3 | } 4 | 5 | data "aws_region" "mod" { 6 | count = "${var.region != "" ? 0 : 1}" 7 | 8 | current = true 9 | } 10 | 11 | data "aws_iam_policy_document" "mod" { 12 | count = "${var.policy != "" ? 0 : 1}" 13 | 14 | statement { 15 | effect = "Deny" 16 | 17 | actions = [ 18 | "s3:PutObject", 19 | "s3:GetObject", 20 | "s3:GetObjectVersion" 21 | ] 22 | 23 | resources = [ 24 | "${format("arn:aws:s3:::%s/*", var.bucket)}" 25 | ] 26 | 27 | condition { 28 | test = "Bool" 29 | variable = "aws:SecureTransport" 30 | 31 | values = [ 32 | "false" 33 | ] 34 | } 35 | 36 | principals { 37 | type = "AWS" 38 | identifiers = [ 39 | "*" 40 | ] 41 | } 42 | } 43 | 44 | statement { 45 | effect = "Deny" 46 | 47 | actions = [ 48 | "s3:PutObject" 49 | ] 50 | 51 | resources = [ 52 | "${format("arn:aws:s3:::%s/*", var.bucket)}" 53 | ] 54 | 55 | condition { 56 | test = "StringEquals" 57 | variable = "s3:x-amz-acl" 58 | 59 | values = [ 60 | "public-read", 61 | "public-read-write" 62 | ] 63 | } 64 | 65 | principals { 66 | type = "AWS" 67 | identifiers = [ 68 | "*" 69 | ] 70 | } 71 | } 72 | 73 | statement { 74 | effect = "Deny" 75 | 76 | actions = [ 77 | "s3:PutObject" 78 | ] 79 | 80 | resources = [ 81 | "${format("arn:aws:s3:::%s/*", var.bucket)}" 82 | ] 83 | 84 | condition { 85 | test = "StringNotEquals" 86 | variable = "s3:x-amz-server-side-encryption" 87 | 88 | values = [ 89 | "${var.server_side_encryption}" 90 | ] 91 | } 92 | 93 | principals { 94 | type = "AWS" 95 | identifiers = [ 96 | "*" 97 | ] 98 | } 99 | } 100 | 101 | statement { 102 | effect = "Deny" 103 | 104 | actions = [ 105 | "s3:PutObject" 106 | ] 107 | 108 | resources = [ 109 | "${format("arn:aws:s3:::%s/*", var.bucket)}" 110 | ] 111 | 112 | condition { 113 | test = "Null" 114 | variable = "s3:x-amz-server-side-encryption" 115 | 116 | values = [ 117 | "true" 118 | ] 119 | } 120 | 121 | principals { 122 | type = "AWS" 123 | identifiers = [ 124 | "*" 125 | ] 126 | } 127 | } 128 | 129 | statement { 130 | actions = [ 131 | "s3:ListBucket" 132 | ] 133 | 134 | resources = [ 135 | "${format("arn:aws:s3:::%s", var.bucket)}" 136 | ] 137 | 138 | principals { 139 | type = "AWS" 140 | identifiers = [ 141 | "${coalescelist(var.principal_arns, list( 142 | format("arn:aws:iam::%s:root", join("", 143 | data.aws_caller_identity.mod.*.account_id))))}" 144 | ] 145 | } 146 | } 147 | 148 | statement { 149 | actions = [ 150 | "s3:PutObject", 151 | "s3:GetObject", 152 | "s3:GetObjectVersion", 153 | "s3:DeleteObject", 154 | "s3:DeleteObjectVersion", 155 | "s3:ListMultipartUploadParts", 156 | "s3:AbortMultipartUpload" 157 | ] 158 | 159 | resources = [ 160 | "${format("arn:aws:s3:::%s/*", var.bucket)}" 161 | ] 162 | 163 | principals { 164 | type = "AWS" 165 | identifiers = [ 166 | "${coalescelist(var.principal_arns, list( 167 | format("arn:aws:iam::%s:root", join("", 168 | data.aws_caller_identity.mod.*.account_id))))}" 169 | ] 170 | } 171 | } 172 | } 173 | 174 | resource "null_resource" "depends_on" { 175 | triggers { 176 | depends_on = "${join("", var.depends_on)}" 177 | } 178 | } 179 | 180 | resource "aws_s3_bucket" "mod" { 181 | bucket = "${var.bucket}" 182 | 183 | acl = "${var.acl}" 184 | policy = "${coalesce(var.policy, join("", 185 | data.aws_iam_policy_document.mod.*.json))}" 186 | 187 | force_destroy = "${var.force_destroy}" 188 | 189 | versioning { 190 | enabled = "${var.versioning}" 191 | } 192 | 193 | logging = ["${var.logging}"] 194 | 195 | tags = "${merge(map( 196 | "Name", "${format("%s-%s-s3-bucket", var.stack_name, var.bucket)}", 197 | "StackName", "${var.stack_name}", 198 | "Environment", "${var.environment}", 199 | "Version", "${var.version}" 200 | ), var.tags)}" 201 | 202 | depends_on = ["null_resource.depends_on"] 203 | } 204 | -------------------------------------------------------------------------------- /modules/aws/s3-bucket/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_s3_bucket.mod.id}" 3 | } 4 | 5 | output "arn" { 6 | value = "${aws_s3_bucket.mod.arn}" 7 | } 8 | 9 | output "hosted_zone_id" { 10 | value = "${aws_s3_bucket.mod.hosted_zone_id}" 11 | } 12 | 13 | output "bucket_domain_name" { 14 | value = "${aws_s3_bucket.mod.bucket_domain_name}" 15 | } 16 | 17 | output "bucket_url" { 18 | value = "${format("https://s3.%s.amazonaws.com/%s", 19 | coalesce(var.region, join("", 20 | data.aws_region.mod.*.name)), 21 | var.bucket)}" 22 | } 23 | 24 | output "principal_arns" { 25 | value = ["${var.principal_arns}"] 26 | } 27 | -------------------------------------------------------------------------------- /modules/aws/s3-bucket/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "bucket" {} 6 | 7 | variable "region" { 8 | default = "" 9 | } 10 | 11 | variable "server_side_encryption" { 12 | default = "AES256" 13 | } 14 | 15 | variable "principal_arns" { 16 | default = [] 17 | } 18 | 19 | variable "acl" { 20 | default = "private" 21 | } 22 | 23 | variable "policy" { 24 | default = "" 25 | } 26 | 27 | variable "force_destroy" { 28 | default = false 29 | } 30 | 31 | variable "versioning" { 32 | default = false 33 | } 34 | 35 | variable "logging" { 36 | default = [] 37 | } 38 | 39 | variable "tags" { 40 | default = {} 41 | } 42 | 43 | variable "depends_on" { 44 | default = [] 45 | } 46 | -------------------------------------------------------------------------------- /modules/aws/s3-bucket/with-logging/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "mod" { 2 | bucket = "${format("%s-log", var.bucket)}" 3 | 4 | acl = "log-delivery-write" 5 | 6 | force_destroy = "${var.force_destroy}" 7 | 8 | lifecycle_rule { 9 | enabled = true 10 | 11 | id = "${format("%s-log-lifecycle", var.bucket)}" 12 | prefix = "" 13 | 14 | transition { 15 | days = 30 16 | storage_class = "STANDARD_IA" 17 | } 18 | 19 | transition { 20 | days = 60 21 | storage_class = "GLACIER" 22 | } 23 | 24 | expiration { 25 | days = 90 26 | } 27 | } 28 | 29 | tags = "${merge(map( 30 | "Name", "${format("%s-%s-log-s3-bucket", var.stack_name, var.bucket)}", 31 | "StackName", "${var.stack_name}", 32 | "Environment", "${var.environment}", 33 | "Version", "${var.version}" 34 | ), var.tags)}" 35 | 36 | provisioner "local-exec" { 37 | command = "sleep 30" 38 | } 39 | } 40 | 41 | module "s3_bucket" { 42 | source = "../" 43 | 44 | stack_name = "${var.stack_name}" 45 | environment = "${var.environment}" 46 | version = "${var.version}" 47 | 48 | region = "${var.region}" 49 | 50 | server_side_encryption = "${var.server_side_encryption}" 51 | principal_arns = ["${var.principal_arns}"] 52 | 53 | bucket = "${var.bucket}" 54 | acl = "${var.acl}" 55 | policy = "${var.policy}" 56 | 57 | force_destroy = "${var.force_destroy}" 58 | 59 | versioning = true 60 | 61 | logging = "${list(map( 62 | "target_bucket", "${format("%s-log", var.bucket)}" 63 | ))}" 64 | 65 | tags = "${var.tags}" 66 | 67 | depends_on = [ 68 | "aws_s3_bucket.mod", 69 | "${var.depends_on}" 70 | ] 71 | } -------------------------------------------------------------------------------- /modules/aws/s3-bucket/with-logging/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${module.s3_bucket.id}" 3 | } 4 | 5 | output "arn" { 6 | value = "${module.s3_bucket.arn}" 7 | } 8 | 9 | output "hosted_zone_id" { 10 | value = "${module.s3_bucket.hosted_zone_id}" 11 | } 12 | 13 | output "bucket_domain_name" { 14 | value = "${module.s3_bucket.bucket_domain_name}" 15 | } 16 | 17 | output "bucket_url" { 18 | value = "${module.s3_bucket.bucket_url}" 19 | } 20 | 21 | output "principal_arns" { 22 | value = ["${module.s3_bucket.principal_arns}"] 23 | } 24 | -------------------------------------------------------------------------------- /modules/aws/s3-bucket/with-logging/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "bucket" {} 6 | 7 | variable "region" { 8 | default = "" 9 | } 10 | 11 | variable "server_side_encryption" { 12 | default = "AES256" 13 | } 14 | 15 | variable "principal_arns" { 16 | default = [] 17 | } 18 | 19 | variable "acl" { 20 | default = "private" 21 | } 22 | 23 | variable "policy" { 24 | default = "" 25 | } 26 | 27 | variable "force_destroy" { 28 | default = false 29 | } 30 | 31 | variable "tags" { 32 | default = {} 33 | } 34 | 35 | variable "depends_on" { 36 | default = [] 37 | } 38 | -------------------------------------------------------------------------------- /modules/aws/security-group/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "aws_security_group" "mod" { 8 | name = "${format("%s-%s-security-group", var.stack_name, var.name)}" 9 | description = "${coalesce(var.description, format("Security Group - %s", var.name))}" 10 | 11 | vpc_id = "${var.vpc_id}" 12 | 13 | tags = "${merge(map( 14 | "Name", "${format("%s-%s-security-group", var.stack_name, var.name)}", 15 | "StackName", "${var.stack_name}", 16 | "Environment", "${var.environment}", 17 | "Version", "${var.version}" 18 | ), var.tags)}" 19 | 20 | depends_on = ["null_resource.depends_on"] 21 | } 22 | 23 | resource "aws_security_group_rule" "rule_ingress_allow_icmp" { 24 | count = "${var.allow_icmp ? 1 : 0}" 25 | 26 | type = "ingress" 27 | 28 | protocol = "icmp" 29 | from_port = -1 30 | to_port = -1 31 | 32 | cidr_blocks = ["0.0.0.0/0"] 33 | 34 | security_group_id = "${aws_security_group.mod.id}" 35 | 36 | depends_on = ["aws_security_group.mod"] 37 | } 38 | 39 | resource "aws_security_group_rule" "rule_egress_allow_icmp" { 40 | count = "${var.allow_icmp ? 1 : 0}" 41 | 42 | type = "egress" 43 | 44 | protocol = "icmp" 45 | from_port = -1 46 | to_port = -1 47 | 48 | cidr_blocks = ["0.0.0.0/0"] 49 | 50 | security_group_id = "${aws_security_group.mod.id}" 51 | 52 | depends_on = ["aws_security_group.mod"] 53 | } 54 | 55 | resource "aws_security_group_rule" "rule_ingress_allow_icmp_destination_unreachable" { 56 | count = "${var.allow_icmp ? 0 : 1}" 57 | 58 | type = "ingress" 59 | 60 | protocol = "icmp" 61 | from_port = 3 62 | to_port = 3 63 | 64 | cidr_blocks = ["0.0.0.0/0"] 65 | 66 | security_group_id = "${aws_security_group.mod.id}" 67 | 68 | depends_on = ["aws_security_group.mod"] 69 | } 70 | 71 | resource "aws_security_group_rule" "rule_egress_allow_icmp_destination_unreachable" { 72 | count = "${var.allow_icmp ? 0 : 1}" 73 | 74 | type = "egress" 75 | 76 | protocol = "icmp" 77 | from_port = 3 78 | to_port = 3 79 | 80 | cidr_blocks = ["0.0.0.0/0"] 81 | 82 | security_group_id = "${aws_security_group.mod.id}" 83 | 84 | depends_on = ["aws_security_group.mod"] 85 | } -------------------------------------------------------------------------------- /modules/aws/security-group/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_security_group.mod.id}" 3 | } 4 | 5 | output "owner_id" { 6 | value = "${aws_security_group.mod.owner_id}" 7 | } 8 | 9 | output "name" { 10 | value = "${aws_security_group.mod.name}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/security-group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "name" {} 6 | variable "vpc_id" {} 7 | 8 | variable "description" { 9 | default = "" 10 | } 11 | 12 | variable "allow_icmp" { 13 | default = false 14 | } 15 | 16 | variable "tags" { 17 | default = {} 18 | } 19 | 20 | variable "depends_on" { 21 | default = [] 22 | } 23 | -------------------------------------------------------------------------------- /modules/aws/subnet/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "mod" { 2 | count = "${var.region != "" ? 0 : 1}" 3 | 4 | current = true 5 | } 6 | 7 | resource "null_resource" "depends_on" { 8 | triggers { 9 | depends_on = "${join("", var.depends_on)}" 10 | } 11 | } 12 | 13 | resource "aws_subnet" "mod" { 14 | count = "${length(var.cidr_blocks)}" 15 | 16 | vpc_id = "${var.vpc_id}" 17 | 18 | cidr_block = "${element(var.cidr_blocks, count.index)}" 19 | availability_zone = "${element(var.availability_zones, count.index)}" 20 | 21 | map_public_ip_on_launch = "${var.map_public_ip_on_launch}" 22 | 23 | tags = "${merge(map( 24 | "Name", "${format("%s-%s-%s-%s-subnet", var.stack_name, 25 | coalesce(var.region, join("", data.aws_region.mod.*.name)), 26 | var.map_public_ip_on_launch ? "public" : "private", 27 | substr(element(var.availability_zones, count.index), -1, 1))}", 28 | "StackName", "${var.stack_name}", 29 | "Environment", "${var.environment}", 30 | "Version", "${var.version}" 31 | ), var.tags)}" 32 | 33 | depends_on = ["null_resource.depends_on"] 34 | } 35 | -------------------------------------------------------------------------------- /modules/aws/subnet/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | value = "${aws_subnet.mod.vpc_id}" 3 | } 4 | 5 | output "ids" { 6 | value = ["${aws_subnet.mod.*.id}"] 7 | } 8 | 9 | output "cidr_blocks" { 10 | value = ["${aws_subnet.mod.*.cidr_block}"] 11 | } 12 | 13 | output "availability_zones" { 14 | value = ["${aws_subnet.mod.*.availability_zone}"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/aws/subnet/private/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "mod" { 2 | count = "${var.region != "" ? 0 : 1}" 3 | 4 | current = true 5 | } 6 | 7 | module "subnet" { 8 | source = "../" 9 | 10 | stack_name = "${var.stack_name}" 11 | environment = "${var.environment}" 12 | version = "${var.version}" 13 | 14 | region = "${coalesce(var.region, join("", data.aws_region.mod.*.name))}" 15 | vpc_id = "${var.vpc_id}" 16 | 17 | cidr_blocks = ["${var.cidr_blocks}"] 18 | availability_zones = ["${var.availability_zones}"] 19 | 20 | tags = "${merge(map( 21 | "Private", "true" 22 | ), var.tags)}" 23 | 24 | depends_on = ["${var.depends_on}"] 25 | } 26 | 27 | resource "aws_route_table" "mod" { 28 | count = "${length(var.cidr_blocks)}" 29 | 30 | vpc_id = "${var.vpc_id}" 31 | 32 | tags = "${merge(map( 33 | "Name", "${format("%s-%s-private-%s-route-table", var.stack_name, 34 | coalesce(var.region, join("", data.aws_region.mod.*.name)), 35 | substr(element(var.availability_zones, count.index), -1, 1))}", 36 | "StackName", "${var.stack_name}", 37 | "Environment", "${var.environment}", 38 | "Version", "${var.version}", 39 | "Private", "true" 40 | ), var.tags)}" 41 | 42 | depends_on = ["module.subnet"] 43 | } 44 | 45 | resource "aws_route" "mod" { 46 | count = "${length(var.cidr_blocks)}" 47 | 48 | destination_cidr_block = "0.0.0.0/0" 49 | 50 | route_table_id = "${element(aws_route_table.mod.*.id, count.index)}" 51 | nat_gateway_id = "${element(var.nat_gateway_ids, count.index)}" 52 | 53 | depends_on = ["aws_route_table.mod"] 54 | } 55 | 56 | resource "aws_route_table_association" "mod" { 57 | count = "${length(var.cidr_blocks)}" 58 | 59 | route_table_id = "${element(aws_route_table.mod.*.id, count.index)}" 60 | subnet_id = "${element(module.subnet.ids, count.index)}" 61 | 62 | depends_on = ["aws_route.mod"] 63 | } 64 | -------------------------------------------------------------------------------- /modules/aws/subnet/private/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | value = "${module.subnet.vpc_id}" 3 | } 4 | 5 | output "ids" { 6 | value = ["${module.subnet.ids}"] 7 | } 8 | 9 | output "route_table_ids" { 10 | value = ["${aws_route_table.mod.*.id}"] 11 | } 12 | 13 | output "cidr_blocks" { 14 | value = ["${module.subnet.cidr_blocks}"] 15 | } 16 | 17 | output "availability_zones" { 18 | value = ["${module.subnet.availability_zones}"] 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/subnet/private/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "vpc_id" {} 6 | 7 | variable "region" { 8 | default = "" 9 | } 10 | 11 | variable "cidr_blocks" { 12 | type = "list" 13 | } 14 | 15 | variable "availability_zones" { 16 | type = "list" 17 | } 18 | 19 | variable "nat_gateway_ids" { 20 | type = "list" 21 | } 22 | 23 | variable "tags" { 24 | default = {} 25 | } 26 | 27 | variable "depends_on" { 28 | default = [] 29 | } 30 | -------------------------------------------------------------------------------- /modules/aws/subnet/public/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "mod" { 2 | count = "${var.region != "" ? 0 : 1}" 3 | 4 | current = true 5 | } 6 | 7 | module "subnet" { 8 | source = "../" 9 | 10 | stack_name = "${var.stack_name}" 11 | environment = "${var.environment}" 12 | version = "${var.version}" 13 | 14 | region = "${coalesce(var.region, join("", data.aws_region.mod.*.name))}" 15 | vpc_id = "${var.vpc_id}" 16 | 17 | cidr_blocks = ["${var.cidr_blocks}"] 18 | availability_zones = ["${var.availability_zones}"] 19 | 20 | map_public_ip_on_launch = true 21 | 22 | tags = "${merge(map( 23 | "Public", "true" 24 | ), var.tags)}" 25 | 26 | depends_on = ["${var.depends_on}"] 27 | } 28 | 29 | module "route_table" { 30 | source = "../../route-table" 31 | 32 | stack_name = "${var.stack_name}" 33 | environment = "${var.environment}" 34 | version = "${var.version}" 35 | 36 | name = "${format("%s-public", coalesce(var.region, join("", 37 | data.aws_region.mod.*.name)))}" 38 | 39 | vpc_id = "${var.vpc_id}" 40 | 41 | tags = "${merge(map( 42 | "Public", "true" 43 | ), var.tags)}" 44 | 45 | depends_on = ["${module.subnet.ids}"] 46 | } 47 | 48 | module "route" { 49 | source = "../../route" 50 | 51 | destination_cidr_block = "0.0.0.0/0" 52 | 53 | route_table_id = "${module.route_table.id}" 54 | gateway_id = "${var.gateway_id}" 55 | 56 | depends_on = ["${module.route_table.id}"] 57 | } 58 | 59 | resource "aws_route_table_association" "mod" { 60 | count = "${length(var.cidr_blocks)}" 61 | 62 | route_table_id = "${module.route_table.id}" 63 | subnet_id = "${element(module.subnet.ids, count.index)}" 64 | 65 | depends_on = ["module.route"] 66 | } 67 | -------------------------------------------------------------------------------- /modules/aws/subnet/public/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vpc_id" { 2 | value = "${module.subnet.vpc_id}" 3 | } 4 | 5 | output "route_table_id" { 6 | value = "${module.route_table.id}" 7 | } 8 | 9 | output "ids" { 10 | value = ["${module.subnet.ids}"] 11 | } 12 | 13 | output "cidr_blocks" { 14 | value = ["${module.subnet.cidr_blocks}"] 15 | } 16 | 17 | output "availability_zones" { 18 | value = ["${module.subnet.availability_zones}"] 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/subnet/public/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "vpc_id" {} 6 | variable "gateway_id" {} 7 | 8 | variable "region" { 9 | default = "" 10 | } 11 | 12 | variable "cidr_blocks" { 13 | type = "list" 14 | } 15 | 16 | variable "availability_zones" { 17 | type = "list" 18 | } 19 | 20 | variable "tags" { 21 | default = {} 22 | } 23 | 24 | variable "depends_on" { 25 | default = [] 26 | } 27 | -------------------------------------------------------------------------------- /modules/aws/subnet/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "vpc_id" {} 6 | 7 | variable "region" { 8 | default = "" 9 | } 10 | 11 | variable "cidr_blocks" { 12 | type = "list" 13 | } 14 | 15 | variable "availability_zones" { 16 | type = "list" 17 | } 18 | 19 | variable "map_public_ip_on_launch" { 20 | default = false 21 | } 22 | 23 | variable "tags" { 24 | default = {} 25 | } 26 | 27 | variable "depends_on" { 28 | default = [] 29 | } 30 | -------------------------------------------------------------------------------- /modules/aws/subnets/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | data "aws_subnet_ids" "public" { 8 | count = "${var.public ? 1 : 0}" 9 | 10 | vpc_id = "${var.vpc_id}" 11 | 12 | tags { 13 | Public = "true" 14 | } 15 | 16 | depends_on = ["null_resource.depends_on"] 17 | } 18 | 19 | data "aws_subnet_ids" "private" { 20 | count = "${var.private ? 1 : 0}" 21 | 22 | vpc_id = "${var.vpc_id}" 23 | 24 | tags { 25 | Private = "true" 26 | } 27 | 28 | depends_on = ["null_resource.depends_on"] 29 | } 30 | -------------------------------------------------------------------------------- /modules/aws/subnets/outputs.tf: -------------------------------------------------------------------------------- 1 | output "public_ids" { 2 | value = ["${data.aws_subnet_ids.public.ids}"] 3 | } 4 | 5 | output "public_count" { 6 | value = "${length(data.aws_subnet_ids.public.ids)}" 7 | } 8 | 9 | output "private_ids" { 10 | value = ["${data.aws_subnet_ids.private.ids}"] 11 | } 12 | 13 | output "private_count" { 14 | value = "${length(data.aws_subnet_ids.private.ids)}" 15 | } 16 | -------------------------------------------------------------------------------- /modules/aws/subnets/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" {} 2 | 3 | variable "public" { 4 | default = true 5 | } 6 | 7 | variable "private" { 8 | default = true 9 | } 10 | 11 | variable "depends_on" { 12 | default = [] 13 | } 14 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/README.md: -------------------------------------------------------------------------------- 1 | # tf-aws-vpc-endpoint 2 | 3 | This is a Terraform module to create a VPC Endpoint between a VPC and an AWS service, 4 | for all the instances running inside associated subnets. 5 | 6 | By default, this module creates a VPC Endpoint for the S3 service, and a two sub-modules 7 | are available for convenience that can be included in order to create a VPC Endpoint for 8 | either the S3 or/and DynamoDB services. 9 | 10 | ## Requirements 11 | 12 | - Terraform 0.10.x or higher. 13 | 14 | ## Dependencies 15 | 16 | None. 17 | 18 | ## Usage 19 | 20 | #### Example of a VPC Endpoint for S3 added to two route tables, and using default policy: 21 | 22 | ```ruby 23 | module "vpc_endpoint_s3" { 24 | source = "../vpc-endpoint" 25 | 26 | vpc_id = "${aws_vpc.vpc.id}" 27 | 28 | route_table_ids = [ 29 | "${aws_route_table.public.id}", 30 | "${aws_route_table.private.id}" 31 | ] 32 | } 33 | ``` 34 | 35 | #### Example of a VPC Endpoint for DynamoDB added to a single route table, and using default policy: 36 | 37 | ```ruby 38 | module "vpc_endpoint_dynamodb" { 39 | source = "../vpc-endpoint/dynamodb" 40 | 41 | vpc_id = "${aws_vpc.vpc.id}" 42 | 43 | route_table_ids = ["${aws_route_table.private.id}"] 44 | } 45 | ``` 46 | 47 | ## Variables 48 | 49 | | Name | Description | Type | Default | Required | 50 | |------|-------------|:-----:|:-----:|:-----:| 51 | | vpc_id | The ID of the VPC in which the endpoint will be created. | String | | Yes | 52 | | route_table_ids | A list of route table IDs to associate the endpoint with. | List | | Yes | 53 | | service | The AWS service name for which to create the endpoint, can be either "s3" or "dynamodb". | String | s3 | No | 54 | | policy | A policy to attach to the VPC Endpoint that controls access to the underlying AWS service. | String | | No | 55 | | depends_on | A list of dependencies to hook into the underlying `aws_vpc_endpoint` resource in this module. This value should be a list that contains interpolations from the resources you want to add as dependencies. | List || No | 56 | 57 | ## Outputs 58 | 59 | | Name | Description | Type | 60 | |------|-------------|:----:| 61 | | id | The ID of the VPC Endpoint. | String | 62 | | vpc_id | The ID of the VPC where the endpoint was created. | String | 63 | | prefix_list_id | The prefix list ID of AWS service exposed through the endpoint. | String | 64 | | cidr_blocks | The list of CIDR blocks for AWS service exposed through the endpoint. | List | 65 | | route_table_ids | The list of route table IDs associated with the endpoint. | List | 66 | 67 | ## Notes 68 | 69 | None. 70 | 71 | ## Known issues 72 | 73 | None. 74 | 75 | ## References 76 | 77 | This module uses Terraform [aws_vpc_endpoint](https://www.terraform.io/docs/providers/aws/r/vpc_endpoint.html) 78 | resource, and also [aws_vpc_endpoint_service](https://www.terraform.io/docs/providers/aws/d/vpc_endpoint_service.html) 79 | and [aws_iam_policy_document](https://www.terraform.io/docs/providers/aws/d/iam_policy_document.html) data sources. 80 | 81 | ## Development 82 | 83 | Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for instructions regarding 84 | the contribution to this repository. 85 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/dynamodb/main.tf: -------------------------------------------------------------------------------- 1 | module "vpc_endpoint" { 2 | source = "../" 3 | 4 | service = "dynamodb" 5 | 6 | vpc_id = "${var.vpc_id}" 7 | route_table_ids = ["${var.route_table_ids}"] 8 | policy = "${var.policy}" 9 | 10 | depends_on = ["${var.depends_on}"] 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/dynamodb/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${module.vpc_endpoint.id}" 3 | } 4 | 5 | output "vpc_id" { 6 | value = "${module.vpc_endpoint.vpc_id}" 7 | } 8 | 9 | output "prefix_list_id" { 10 | value = "${module.vpc_endpoint.prefix_list_id}" 11 | } 12 | 13 | output "cidr_blocks" { 14 | value = ["${module.vpc_endpoint.cidr_blocks}"] 15 | } 16 | 17 | output "route_table_ids" { 18 | value = ["${module.vpc_endpoint.route_table_ids}"] 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/dynamodb/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" {} 2 | 3 | variable "route_table_ids" { 4 | type = "list" 5 | } 6 | 7 | variable "policy" { 8 | default = "" 9 | } 10 | 11 | variable "depends_on" { 12 | default = [] 13 | } 14 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_vpc_endpoint_service" "mod" { 2 | service = "${lower(var.service)}" 3 | } 4 | 5 | data "aws_iam_policy_document" "mod" { 6 | count = "${var.policy != "" ? 0 : 1}" 7 | 8 | statement { 9 | principals { 10 | type = "AWS" 11 | identifiers = [ 12 | "*" 13 | ] 14 | } 15 | 16 | actions = [ 17 | "*" 18 | ] 19 | 20 | resources = [ 21 | "*" 22 | ] 23 | } 24 | } 25 | 26 | resource "null_resource" "depends_on" { 27 | triggers { 28 | depends_on = "${join("", var.depends_on)}" 29 | } 30 | } 31 | 32 | resource "aws_vpc_endpoint" "mod" { 33 | vpc_id = "${var.vpc_id}" 34 | service_name = "${data.aws_vpc_endpoint_service.mod.service_name}" 35 | 36 | route_table_ids = ["${var.route_table_ids}"] 37 | 38 | policy = "${coalesce(var.policy, join("", 39 | data.aws_iam_policy_document.mod.*.json))}" 40 | 41 | depends_on = ["null_resource.depends_on"] 42 | } 43 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_vpc_endpoint.mod.id}" 3 | } 4 | 5 | output "vpc_id" { 6 | value = "${aws_vpc_endpoint.mod.vpc_id}" 7 | } 8 | 9 | output "prefix_list_id" { 10 | value = "${aws_vpc_endpoint.mod.prefix_list_id}" 11 | } 12 | 13 | output "cidr_blocks" { 14 | value = ["${aws_vpc_endpoint.mod.cidr_blocks}"] 15 | } 16 | 17 | output "route_table_ids" { 18 | value = ["${aws_vpc_endpoint.mod.route_table_ids}"] 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/s3/main.tf: -------------------------------------------------------------------------------- 1 | module "vpc_endpoint" { 2 | source = "../" 3 | 4 | service = "s3" 5 | 6 | vpc_id = "${var.vpc_id}" 7 | route_table_ids = ["${var.route_table_ids}"] 8 | policy = "${var.policy}" 9 | 10 | depends_on = ["${var.depends_on}"] 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/s3/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${module.vpc_endpoint.id}" 3 | } 4 | 5 | output "vpc_id" { 6 | value = "${module.vpc_endpoint.vpc_id}" 7 | } 8 | 9 | output "prefix_list_id" { 10 | value = "${module.vpc_endpoint.prefix_list_id}" 11 | } 12 | 13 | output "cidr_blocks" { 14 | value = ["${module.vpc_endpoint.cidr_blocks}"] 15 | } 16 | 17 | output "route_table_ids" { 18 | value = ["${module.vpc_endpoint.route_table_ids}"] 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/s3/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" {} 2 | 3 | variable "route_table_ids" { 4 | type = "list" 5 | } 6 | 7 | variable "policy" { 8 | default = "" 9 | } 10 | 11 | variable "depends_on" { 12 | default = [] 13 | } 14 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" {} 2 | 3 | variable "route_table_ids" { 4 | type = "list" 5 | } 6 | 7 | variable "service" { 8 | default = "s3" 9 | } 10 | 11 | variable "policy" { 12 | default = "" 13 | } 14 | 15 | variable "depends_on" { 16 | default = [] 17 | } 18 | -------------------------------------------------------------------------------- /modules/aws/vpc-endpoint/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws/vpc-peering/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "mod" { 2 | count = "${var.peer_owner_id != "" ? 0 : 1}" 3 | } 4 | 5 | resource "null_resource" "depends_on" { 6 | triggers { 7 | depends_on = "${join("", var.depends_on)}" 8 | } 9 | } 10 | 11 | resource "aws_vpc_peering_connection" "mod" { 12 | peer_vpc_id = "${var.peer_vpc_id}" 13 | vpc_id = "${var.vpc_id}" 14 | auto_accept = "${var.auto_accept}" 15 | 16 | peer_owner_id = "${coalesce(var.peer_owner_id, join("", 17 | data.aws_caller_identity.mod.*.account_id))}" 18 | 19 | accepter { 20 | allow_remote_vpc_dns_resolution = true 21 | } 22 | 23 | requester { 24 | allow_remote_vpc_dns_resolution = true 25 | } 26 | 27 | tags = "${merge(map( 28 | "Name", "${format("%s-%s-%s-vpc-peering-connetion", 29 | var.stack_name, var.vpc_id, var.peer_vpc_id)}", 30 | "StackName", "${var.stack_name}", 31 | "Environment", "${var.environment}", 32 | "Version", "${var.version}" 33 | ), var.tags)}" 34 | 35 | depends_on = ["null_resource.depends_on"] 36 | } 37 | -------------------------------------------------------------------------------- /modules/aws/vpc-peering/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_vpc_peering_connection.mod.id}" 3 | } 4 | 5 | output "vpc_id" { 6 | value = "${aws_vpc_peering_connection.mod.vpc_id}" 7 | } 8 | 9 | output "peer_vpc_id" { 10 | value = "${aws_vpc_peering_connection.mod.peer_vpc_id}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/vpc-peering/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "peer_vpc_id" {} 6 | variable "vpc_id" {} 7 | 8 | variable "auto_accept" { 9 | default = true 10 | } 11 | 12 | variable "peer_owner_id" { 13 | default = "" 14 | } 15 | 16 | variable "tags" { 17 | default = {} 18 | } 19 | 20 | variable "depends_on" { 21 | default = [] 22 | } 23 | -------------------------------------------------------------------------------- /modules/aws/vpc/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_vpc" "mod" { 2 | cidr_block = "${var.cidr_block}" 3 | 4 | instance_tenancy = "${var.instance_tenancy}" 5 | 6 | enable_dns_support = "${var.enable_dns_support}" 7 | enable_dns_hostnames = "${var.enable_dns_hostnames}" 8 | enable_classiclink = "${var.enable_classiclink}" 9 | 10 | tags = "${merge(map( 11 | "Name", "${format("%s-vpc", var.stack_name)}", 12 | "StackName", "${var.stack_name}", 13 | "Environment", "${var.environment}", 14 | "Version", "${var.version}" 15 | ), var.tags)}" 16 | } 17 | 18 | resource "aws_route53_zone_association" "mod" { 19 | count = "${var.zone_id == "" ? 0 : 1}" 20 | 21 | zone_id = "${var.zone_id}" 22 | vpc_id = "${aws_vpc.mod.id}" 23 | 24 | depends_on = ["aws_vpc.mod"] 25 | } 26 | -------------------------------------------------------------------------------- /modules/aws/vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${aws_vpc.mod.id}" 3 | } 4 | 5 | output "cidr_block" { 6 | value = "${aws_vpc.mod.cidr_block}" 7 | } 8 | 9 | output "zone_id" { 10 | value = "${aws_route53_zone_association.mod.zone_id}" 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws/vpc/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_name" {} 2 | variable "environment" {} 3 | variable "version" {} 4 | 5 | variable "cidr_block" {} 6 | 7 | variable "zone_id" { 8 | default = "" 9 | } 10 | 11 | variable "instance_tenancy" { 12 | default = "default" 13 | } 14 | 15 | variable "enable_dns_support" { 16 | default = true 17 | } 18 | 19 | variable "enable_dns_hostnames" { 20 | default = true 21 | } 22 | 23 | variable "enable_classiclink" { 24 | default = false 25 | } 26 | 27 | variable "tags" { 28 | default = {} 29 | } 30 | -------------------------------------------------------------------------------- /modules/common/env/interface.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = "string" 3 | } 4 | 5 | variable "allow_empty_value" { 6 | default = false 7 | } 8 | -------------------------------------------------------------------------------- /modules/common/env/main.tf: -------------------------------------------------------------------------------- 1 | data "external" "mod" { 2 | program = [ 3 | "bash", 4 | "${path.module}/scripts/environment.sh", 5 | ] 6 | 7 | query = { 8 | name = "${var.name}" 9 | allow_empty_value = "${var.allow_empty_value}" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /modules/common/env/outputs.tf: -------------------------------------------------------------------------------- 1 | output "value" { 2 | value = "${data.external.mod.result.value}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/common/env/scripts/environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | normalize_boolean() { 8 | local boolean="$1" 9 | shift 10 | 11 | local status='true' 12 | [[ "$boolean" =~ (1|yes|true) ]] || status='false' 13 | 14 | echo "$status" 15 | } 16 | 17 | fetch_value() { 18 | local name="$1" 19 | shift 20 | 21 | local value= 22 | set +e 23 | value="${!name:-}" 24 | set -e 25 | 26 | echo "$value" 27 | } 28 | 29 | export PATH='/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin' 30 | 31 | NAME= 32 | ALLOW_EMPTY_VALUE='false' 33 | 34 | if ! test -t 0; then 35 | eval "$(jq -r '@sh "NAME=\(.name) ALLOW_EMPTY_VALUE=\(.allow_empty_value)"')" 36 | fi 37 | 38 | if [[ -z ${!NAME+x} ]]; then 39 | echo "The environment variable '$NAME' could not be found." >&2 40 | exit 1 41 | fi 42 | 43 | VALUE="$(fetch_value "$NAME")" 44 | 45 | if [[ -z $VALUE ]]; then 46 | if [[ $(normalize_boolean "$ALLOW_EMPTY_VALUE") == 'true' ]]; then 47 | echo '{ "value": "" }' 48 | exit 0 49 | else 50 | echo "The environment variable '$NAME' is empty." >&2 51 | exit 1 52 | fi 53 | fi 54 | 55 | jq -c -n --arg value "$VALUE" '{ "value": $value }' 56 | -------------------------------------------------------------------------------- /modules/common/origin/interface.tf: -------------------------------------------------------------------------------- 1 | variable "add_cidr" { 2 | default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/common/origin/main.tf: -------------------------------------------------------------------------------- 1 | data "external" "mod" { 2 | program = [ 3 | "bash", 4 | "${path.module}/scripts/origin.sh" 5 | ] 6 | 7 | query = { 8 | add_cidr = "${var.add_cidr}" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/common/origin/outputs.tf: -------------------------------------------------------------------------------- 1 | output "origin" { 2 | value = "${data.external.mod.result.origin}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/common/origin/scripts/origin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | normalize_boolean() { 8 | local boolean="$1" 9 | shift 10 | 11 | local status='true' 12 | [[ "$boolean" =~ (1|yes|true) ]] || status='false' 13 | 14 | echo "$status" 15 | } 16 | 17 | fetch_origin() { 18 | # List of popular "what is my IP?" providers. 19 | local hosts=( 20 | 'http://checkip.amazonaws.com/' 21 | 'http://icanhazip.com/' 22 | 'http://ident.me/' 23 | 'http://ifconfig.io/' 24 | 'http://ipecho.net/plain' 25 | 'http://whatismyip.akamai.com/' 26 | ) 27 | 28 | local tries=0 29 | local origin= 30 | local host="${hosts[$(( RANDOM % ${#hosts[@]} ))]}" 31 | 32 | # Try to get an IP address but give up after trying 5 times. 33 | while [[ -z $origin ]] && (( tries < 5 )); do 34 | set +e 35 | if which curl &>/dev/null; then 36 | origin=$(curl --max-time 5 --user-agent 'curl/1.0.0' -L "$host" 2>/dev/null) 37 | else 38 | origin=$(wget --timeout 5 --user-agent 'Wget/1.0.0' -O- "$host" 2>/dev/null) 39 | fi 40 | set -e 41 | 42 | host="${hosts[$(( RANDOM % ${#hosts[@]} ))]}" 43 | tries=$(( tries + 1 )) 44 | done 45 | 46 | echo "$origin" 47 | } 48 | 49 | export PATH='/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin' 50 | 51 | ADD_CIDR=${ADD_CIDR-} 52 | 53 | if ! test -t 0; then 54 | eval "$(jq -r '@sh "ADD_CIDR=\(.add_cidr)"')" 55 | fi 56 | 57 | ORIGIN="$(fetch_origin)" 58 | if [[ $(normalize_boolean "$ADD_CIDR") == 'true' ]]; then 59 | # Add /32 to the IP address. 60 | ORIGIN="${ORIGIN}/32" 61 | fi 62 | 63 | jq -c -n --arg origin "$ORIGIN" '{ "origin": $origin }' 64 | -------------------------------------------------------------------------------- /modules/common/origin/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | -------------------------------------------------------------------------------- /modules/common/ptr-calculator/main.tf: -------------------------------------------------------------------------------- 1 | data "null_data_source" "parser" { 2 | inputs = { 3 | host = "${element(split("/", var.host), 0)}" 4 | size = "${length(split(".", var.host))}" 5 | } 6 | } 7 | 8 | data "null_data_source" "ptr" { 9 | count = "${data.null_data_source.parser.outputs.size}" 10 | 11 | inputs = { 12 | ptr = "${element(split(".", data.null_data_source.parser.outputs.host), 13 | (data.null_data_source.parser.outputs.size - count.index) - 1)}" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /modules/common/ptr-calculator/outputs.tf: -------------------------------------------------------------------------------- 1 | output "host" { 2 | value = "${data.null_data_source.parser.outputs.host}" 3 | } 4 | 5 | output "ptr" { 6 | value = "${format("%s.in-addr.arpa", join(".", 7 | slice(data.null_data_source.ptr.*.outputs.ptr, 8 | lookup(var.shift, var.type), 9 | data.null_data_source.parser.outputs.size)))}" 10 | } 11 | -------------------------------------------------------------------------------- /modules/common/ptr-calculator/variables.tf: -------------------------------------------------------------------------------- 1 | variable "host" {} 2 | 3 | variable "type" { 4 | default = "host" 5 | } 6 | 7 | variable "shift" { 8 | default = { 9 | host = 0 10 | subnet = 1 11 | network = 2 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /modules/common/subnet-calculator/main.tf: -------------------------------------------------------------------------------- 1 | data "null_data_source" "parser" { 2 | inputs = { 3 | to = "${element(split("/", var.to), 1)}" 4 | netmask = "${element(split("/", var.cidr_block), 1)}" 5 | } 6 | } 7 | 8 | data "null_data_source" "integers" { 9 | inputs = { 10 | hosts = "${pow(2, (32 - data.null_data_source.parser.outputs.to)) - 2}" 11 | subnets = "${pow(2, abs(data.null_data_source.parser.outputs.netmask - 12 | data.null_data_source.parser.outputs.to))}" 13 | } 14 | } 15 | 16 | data "null_data_source" "networks" { 17 | count = "${var.count > 0 ? var.count : data.null_data_source.integers.outputs.subnets}" 18 | 19 | inputs = { 20 | value = "${cidrsubnet(var.cidr_block, 21 | abs(data.null_data_source.parser.outputs.netmask - 22 | data.null_data_source.parser.outputs.to), 23 | count.index)}" 24 | } 25 | } 26 | 27 | data "null_data_source" "odd" { 28 | count = "${var.count > 0 ? var.count : data.null_data_source.integers.outputs.subnets}" 29 | 30 | inputs = { 31 | value = "${count.index % 2 != 0 32 | ? element(data.null_data_source.networks.*.outputs.value, count.index) 33 | : ""}" 34 | } 35 | } 36 | 37 | data "null_data_source" "even" { 38 | count = "${var.count > 0 ? var.count : data.null_data_source.integers.outputs.subnets}" 39 | 40 | inputs = { 41 | value = "${count.index % 2 == 0 42 | ? element(data.null_data_source.networks.*.outputs.value, count.index) 43 | : ""}" 44 | } 45 | } 46 | 47 | resource "random_shuffle" "random" { 48 | count = "${var.shuffle ? 1 : 0}" 49 | 50 | input = [ 51 | "${data.null_data_source.networks.*.outputs.value}" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /modules/common/subnet-calculator/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cidr_block" { 2 | value = "${var.cidr_block}" 3 | } 4 | 5 | output "ptr" { 6 | value = "${format("%s.%s.in-addr.arpa", element(split(".", var.cidr_block), 1), 7 | element(split(".", var.cidr_block), 0))}" 8 | } 9 | 10 | output "address" { 11 | value = "${cidrhost(var.cidr_block, 0)}" 12 | } 13 | 14 | output "netmask" { 15 | value = "${cidrnetmask(var.cidr_block)}" 16 | } 17 | 18 | output "hosts" { 19 | value = "${data.null_data_source.integers.outputs.hosts}" 20 | } 21 | 22 | output "subnets" { 23 | value = "${data.null_data_source.integers.outputs.subnets}" 24 | } 25 | 26 | output "all" { 27 | value = ["${data.null_data_source.networks.*.outputs.value}"] 28 | } 29 | 30 | output "random" { 31 | value = ["${random_shuffle.random.*.result}"] 32 | } 33 | 34 | output "odd" { 35 | value = ["${compact(data.null_data_source.odd.*.outputs.value)}"] 36 | } 37 | 38 | output "even" { 39 | value = ["${compact(data.null_data_source.even.*.outputs.value)}"] 40 | } 41 | 42 | output "halve_1" { 43 | value = ["${slice(data.null_data_source.networks.*.outputs.value, 0, 44 | length(data.null_data_source.networks.*.outputs.value) / 2)}"] 45 | } 46 | 47 | output "halve_2" { 48 | value = ["${slice(data.null_data_source.networks.*.outputs.value, 49 | length(data.null_data_source.networks.*.outputs.value) / 2, 50 | length(data.null_data_source.networks.*.outputs.value))}"] 51 | } 52 | -------------------------------------------------------------------------------- /modules/common/subnet-calculator/variables.tf: -------------------------------------------------------------------------------- 1 | variable "cidr_block" {} 2 | variable "to" {} 3 | 4 | variable "count" { 5 | default = 0 6 | } 7 | 8 | variable "shuffle" { 9 | default = false 10 | } 11 | -------------------------------------------------------------------------------- /modules/common/subnet-calculator/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10.7" 3 | } 4 | -------------------------------------------------------------------------------- /modules/do/droplet/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "digitalocean_droplet" "mod" { 8 | count = "${var.count}" 9 | 10 | name = "${var.count > 1 ? format("%s-0%d", var.name, count.index) : var.name}" 11 | image = "${var.image}" 12 | size = "${var.size}" 13 | backups = "${var.backups}" 14 | ipv6 = "${var.ipv6}" 15 | private_networking = "${var.private_networking}" 16 | region = "${var.region}" 17 | ssh_keys = "${var.ssh_keys}" 18 | tags = "${var.tags}" 19 | } 20 | -------------------------------------------------------------------------------- /modules/do/droplet/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = "${digitalocean_droplet.mod.*.id}" 3 | } 4 | 5 | output "name" { 6 | value = "${digitalocean_droplet.mod.*.name}" 7 | } 8 | 9 | output "region" { 10 | value = "${digitalocean_droplet.mod.*.region}" 11 | } 12 | 13 | output "ipv6" { 14 | value = "${digitalocean_droplet.mod.*.ipv6}" 15 | } 16 | 17 | output "ipv6_address" { 18 | value = "${digitalocean_droplet.mod.*.ipv6_address}" 19 | } 20 | 21 | output "ipv6_address_private" { 22 | value = "${digitalocean_droplet.mod.*.ipv6_address_private}" 23 | } 24 | 25 | output "ipv4_address" { 26 | value = "${digitalocean_droplet.mod.*.ipv4_address}" 27 | } 28 | 29 | output "ipv4_address_private" { 30 | value = "${digitalocean_droplet.mod.*.ipv4_address_private}" 31 | } 32 | 33 | output "locked" { 34 | value = "${digitalocean_droplet.mod.*.locked}" 35 | } 36 | 37 | output "status" { 38 | value = "${digitalocean_droplet.mod.*.status}" 39 | } 40 | 41 | output "tags" { 42 | value = "${digitalocean_droplet.mod.*.tags}" 43 | } 44 | 45 | output "volume_ids" { 46 | value = "${digitalocean_droplet.mod.*.volume_ids}" 47 | } 48 | -------------------------------------------------------------------------------- /modules/do/droplet/variables.tf: -------------------------------------------------------------------------------- 1 | variable "depends_on" { 2 | default = [] 3 | } 4 | 5 | variable "name" {} 6 | variable "region" {} 7 | variable "image" {} 8 | variable "ssh_keys" { 9 | type = "list" 10 | } 11 | 12 | variable "count" { 13 | default = 1 14 | } 15 | 16 | variable "size" { 17 | default = "512mb" 18 | } 19 | 20 | variable "backups" { 21 | default = false 22 | } 23 | 24 | variable "ipv6" { 25 | default = false 26 | } 27 | 28 | variable "private_networking" { 29 | default = false 30 | } 31 | 32 | variable "tags" { 33 | default = [] 34 | } 35 | -------------------------------------------------------------------------------- /modules/do/droplet/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | -------------------------------------------------------------------------------- /modules/do/image/main.tf: -------------------------------------------------------------------------------- 1 | data "digitalocean_image" "d" { 2 | name = "${var.name}" 3 | } 4 | -------------------------------------------------------------------------------- /modules/do/image/outputs.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | value = "${data.digitalocean_image.d.name}" 3 | } 4 | 5 | output "image" { 6 | value = "${data.digitalocean_image.d.image}" 7 | } 8 | 9 | output "min_disk_size" { 10 | value = "${data.digitalocean_image.d.min_disk_size}" 11 | } 12 | 13 | output "private" { 14 | value = "${data.digitalocean_image.d.private}" 15 | } 16 | 17 | output "regions" { 18 | value = "${data.digitalocean_image.d.regions}" 19 | } 20 | 21 | output "size_gigabytes" { 22 | value = "${data.digitalocean_image.d.size_gigabytes}" 23 | } 24 | 25 | output "type" { 26 | value = "${data.digitalocean_image.d.type}" 27 | } 28 | -------------------------------------------------------------------------------- /modules/do/image/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" {} 2 | -------------------------------------------------------------------------------- /modules/do/image/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | -------------------------------------------------------------------------------- /modules/do/ssh/main.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "depends_on" { 2 | triggers { 3 | depends_on = "${join("", var.depends_on)}" 4 | } 5 | } 6 | 7 | resource "digitalocean_ssh_key" "mod" { 8 | name = "${var.name}" 9 | count = "${length(var.public_keys)}" 10 | public_key = "${file(element(var.public_keys, count.index))}" 11 | depends_on = ["null_resource.depends_on"] 12 | } 13 | -------------------------------------------------------------------------------- /modules/do/ssh/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ids" { 2 | value = ["${digitalocean_ssh_key.mod.*.id}"] 3 | } 4 | 5 | output "names" { 6 | value = ["${digitalocean_ssh_key.mod.*.name}"] 7 | } 8 | 9 | output "public_keys" { 10 | value = ["${digitalocean_ssh_key.mod.*.public_key}"] 11 | } 12 | 13 | output "fingerprints" { 14 | value = ["${digitalocean_ssh_key.mod.*.fingerprint}"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/do/ssh/variables.tf: -------------------------------------------------------------------------------- 1 | variable "depends_on" { 2 | default = [] 3 | } 4 | 5 | variable "name" {} 6 | variable "public_keys" { 7 | default = [] 8 | } 9 | -------------------------------------------------------------------------------- /modules/do/ssh/version.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.10" 3 | } 4 | --------------------------------------------------------------------------------