├── .gitignore ├── .gitmodules ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── development ├── api.tf ├── kitchen.yml ├── main.tf ├── test │ └── integration │ │ └── default │ │ ├── controls │ │ ├── operating_system_spec.rb │ │ ├── resolv_conf_spec.rb │ │ └── sshd_spec.rb │ │ ├── inspec.lock │ │ ├── inspec.yml │ │ └── libraries │ │ └── resolv_conf.rb ├── variables.tf ├── versions.tf └── web.tf └── production ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf /.gitignore: -------------------------------------------------------------------------------- 1 | .kitchen/ 2 | .terraform/ 3 | terraform.tfvars 4 | terraform.tfstate* 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "modules/remote_state"] 2 | path = modules/remote_state 3 | url = https://github.com/turnbullpress/tf_remote_state 4 | [submodule "modules/vpc"] 5 | path = modules/vpc 6 | url = https://github.com/turnbullpress/tf_vpc 7 | [submodule "modules/consul"] 8 | path = modules/consul 9 | url = https://github.com/turnbullpress/tf_consul 10 | [submodule "modules/web"] 11 | path = modules/web 12 | url = https://github.com/turnbullpress/tf_web 13 | [submodule "modules/api"] 14 | path = modules/api 15 | url = https://github.com/turnbullpress/tf_api 16 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.6.3 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org/' 2 | ruby '2.6.3' 3 | 4 | gem 'test-kitchen' 5 | gem 'kitchen-terraform' 6 | gem 'inspec-bin' 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.6.0) 5 | public_suffix (>= 2.0.2, < 4.0) 6 | aws-eventstream (1.0.3) 7 | aws-partitions (1.180.0) 8 | aws-sdk-autoscaling (1.22.0) 9 | aws-sdk-core (~> 3, >= 3.52.1) 10 | aws-sigv4 (~> 1.1) 11 | aws-sdk-cloudtrail (1.15.0) 12 | aws-sdk-core (~> 3, >= 3.56.0) 13 | aws-sigv4 (~> 1.1) 14 | aws-sdk-cloudwatch (1.24.0) 15 | aws-sdk-core (~> 3, >= 3.56.0) 16 | aws-sigv4 (~> 1.1) 17 | aws-sdk-cloudwatchlogs (1.22.0) 18 | aws-sdk-core (~> 3, >= 3.56.0) 19 | aws-sigv4 (~> 1.1) 20 | aws-sdk-configservice (1.31.0) 21 | aws-sdk-core (~> 3, >= 3.56.0) 22 | aws-sigv4 (~> 1.1) 23 | aws-sdk-core (3.56.0) 24 | aws-eventstream (~> 1.0, >= 1.0.2) 25 | aws-partitions (~> 1.0) 26 | aws-sigv4 (~> 1.1) 27 | jmespath (~> 1.0) 28 | aws-sdk-costandusagereportservice (1.14.0) 29 | aws-sdk-core (~> 3, >= 3.56.0) 30 | aws-sigv4 (~> 1.1) 31 | aws-sdk-dynamodb (1.32.0) 32 | aws-sdk-core (~> 3, >= 3.56.0) 33 | aws-sigv4 (~> 1.1) 34 | aws-sdk-ec2 (1.96.0) 35 | aws-sdk-core (~> 3, >= 3.56.0) 36 | aws-sigv4 (~> 1.1) 37 | aws-sdk-ecr (1.18.0) 38 | aws-sdk-core (~> 3, >= 3.56.0) 39 | aws-sigv4 (~> 1.1) 40 | aws-sdk-ecs (1.42.0) 41 | aws-sdk-core (~> 3, >= 3.56.0) 42 | aws-sigv4 (~> 1.1) 43 | aws-sdk-eks (1.22.0) 44 | aws-sdk-core (~> 3, >= 3.56.0) 45 | aws-sigv4 (~> 1.1) 46 | aws-sdk-elasticloadbalancing (1.16.0) 47 | aws-sdk-core (~> 3, >= 3.56.0) 48 | aws-sigv4 (~> 1.1) 49 | aws-sdk-iam (1.26.0) 50 | aws-sdk-core (~> 3, >= 3.56.0) 51 | aws-sigv4 (~> 1.1) 52 | aws-sdk-kms (1.22.0) 53 | aws-sdk-core (~> 3, >= 3.56.0) 54 | aws-sigv4 (~> 1.1) 55 | aws-sdk-organizations (1.17.0) 56 | aws-sdk-core (~> 3, >= 3.39.0) 57 | aws-sigv4 (~> 1.0) 58 | aws-sdk-rds (1.60.0) 59 | aws-sdk-core (~> 3, >= 3.56.0) 60 | aws-sigv4 (~> 1.1) 61 | aws-sdk-s3 (1.43.0) 62 | aws-sdk-core (~> 3, >= 3.56.0) 63 | aws-sdk-kms (~> 1) 64 | aws-sigv4 (~> 1.1) 65 | aws-sdk-sns (1.17.0) 66 | aws-sdk-core (~> 3, >= 3.56.0) 67 | aws-sigv4 (~> 1.1) 68 | aws-sdk-sqs (1.17.0) 69 | aws-sdk-core (~> 3, >= 3.56.0) 70 | aws-sigv4 (~> 1.1) 71 | aws-sigv4 (1.1.0) 72 | aws-eventstream (~> 1.0, >= 1.0.2) 73 | azure_graph_rbac (0.17.1) 74 | ms_rest_azure (~> 0.11.0) 75 | azure_mgmt_key_vault (0.17.4) 76 | ms_rest_azure (~> 0.11.0) 77 | azure_mgmt_resources (0.17.5) 78 | ms_rest_azure (~> 0.11.1) 79 | bcrypt_pbkdf (1.0.1) 80 | builder (3.2.3) 81 | coderay (1.1.2) 82 | concurrent-ruby (1.1.5) 83 | declarative (0.0.10) 84 | declarative-option (0.1.0) 85 | diff-lcs (1.3) 86 | docker-api (1.34.2) 87 | excon (>= 0.47.0) 88 | multi_json 89 | domain_name (0.5.20180417) 90 | unf (>= 0.0.5, < 1.0.0) 91 | dry-configurable (0.8.3) 92 | concurrent-ruby (~> 1.0) 93 | dry-core (~> 0.4, >= 0.4.7) 94 | dry-container (0.7.1) 95 | concurrent-ruby (~> 1.0) 96 | dry-configurable (~> 0.1, >= 0.1.3) 97 | dry-core (0.4.8) 98 | concurrent-ruby (~> 1.0) 99 | dry-equalizer (0.2.2) 100 | dry-inflector (0.1.2) 101 | dry-logic (0.6.1) 102 | concurrent-ruby (~> 1.0) 103 | dry-core (~> 0.2) 104 | dry-equalizer (~> 0.2) 105 | dry-types (0.14.1) 106 | concurrent-ruby (~> 1.0) 107 | dry-container (~> 0.3) 108 | dry-core (~> 0.4, >= 0.4.4) 109 | dry-equalizer (~> 0.2) 110 | dry-inflector (~> 0.1, >= 0.1.2) 111 | dry-logic (~> 0.5, >= 0.5) 112 | dry-validation (0.13.3) 113 | concurrent-ruby (~> 1.0) 114 | dry-configurable (~> 0.1, >= 0.1.3) 115 | dry-core (~> 0.2, >= 0.2.1) 116 | dry-equalizer (~> 0.2) 117 | dry-logic (~> 0.5, >= 0.5.0) 118 | dry-types (~> 0.14.0) 119 | ed25519 (1.2.4) 120 | equatable (0.5.0) 121 | erubis (2.7.0) 122 | excon (0.71.0) 123 | faraday (0.15.4) 124 | multipart-post (>= 1.2, < 3) 125 | faraday-cookie_jar (0.0.6) 126 | faraday (>= 0.7.4) 127 | http-cookie (~> 1.0.0) 128 | faraday_middleware (0.12.2) 129 | faraday (>= 0.7.4, < 1.0) 130 | ffi (1.11.1) 131 | google-api-client (0.23.9) 132 | addressable (~> 2.5, >= 2.5.1) 133 | googleauth (>= 0.5, < 0.7.0) 134 | httpclient (>= 2.8.1, < 3.0) 135 | mime-types (~> 3.0) 136 | representable (~> 3.0) 137 | retriable (>= 2.0, < 4.0) 138 | signet (~> 0.9) 139 | googleauth (0.6.7) 140 | faraday (~> 0.12) 141 | jwt (>= 1.4, < 3.0) 142 | memoist (~> 0.16) 143 | multi_json (~> 1.11) 144 | os (>= 0.9, < 2.0) 145 | signet (~> 0.7) 146 | gssapi (1.3.0) 147 | ffi (>= 1.0.1) 148 | gyoku (1.3.1) 149 | builder (>= 2.1.2) 150 | hashie (3.6.0) 151 | htmlentities (4.3.4) 152 | http-cookie (1.0.3) 153 | domain_name (~> 0.5) 154 | httpclient (2.8.3) 155 | inifile (3.0.0) 156 | inspec (4.6.4) 157 | addressable (~> 2.4) 158 | faraday (>= 0.9.0) 159 | faraday_middleware (~> 0.12.2) 160 | hashie (~> 3.4) 161 | htmlentities 162 | json-schema (~> 2.8) 163 | license-acceptance (>= 0.2.13, < 2.0) 164 | method_source (~> 0.8) 165 | mixlib-log 166 | multipart-post 167 | parallel (~> 1.9) 168 | parslet (~> 1.5) 169 | pry (~> 0) 170 | rspec (~> 3) 171 | rspec-its (~> 1.2) 172 | rubyzip (~> 1.2, >= 1.2.2) 173 | semverse 174 | sslshake (~> 1.2) 175 | term-ansicolor 176 | thor (~> 0.20) 177 | tomlrb (~> 1.2) 178 | train (~> 2.0) 179 | train-aws (~> 0.1) 180 | train-habitat (~> 0.1) 181 | tty-prompt (~> 0.17) 182 | tty-table (~> 0.10) 183 | jmespath (1.4.0) 184 | json (2.2.0) 185 | json-schema (2.8.1) 186 | addressable (>= 2.4) 187 | jwt (2.2.1) 188 | kitchen-terraform (5.0.0) 189 | dry-validation (~> 0.13) 190 | inspec (~> 4.0) 191 | json (~> 2.2) 192 | mixlib-shellout (~> 2.2) 193 | rbnacl (~> 4.0) 194 | test-kitchen (~> 2.1) 195 | tty-which (~> 0.4.0) 196 | license-acceptance (1.0.13) 197 | pastel (~> 0.7) 198 | tomlrb (~> 1.2) 199 | tty-box (~> 0.3) 200 | tty-prompt (~> 0.18) 201 | little-plugger (1.1.4) 202 | logging (2.2.2) 203 | little-plugger (~> 1.1) 204 | multi_json (~> 1.10) 205 | memoist (0.16.0) 206 | method_source (0.9.2) 207 | mime-types (3.2.2) 208 | mime-types-data (~> 3.2015) 209 | mime-types-data (3.2019.0331) 210 | mixlib-install (3.11.18) 211 | mixlib-shellout 212 | mixlib-versioning 213 | thor 214 | mixlib-log (3.0.1) 215 | mixlib-shellout (2.4.4) 216 | mixlib-versioning (1.2.7) 217 | ms_rest (0.7.4) 218 | concurrent-ruby (~> 1.0) 219 | faraday (~> 0.9) 220 | timeliness (~> 0.3.10) 221 | ms_rest_azure (0.11.1) 222 | concurrent-ruby (~> 1.0) 223 | faraday (~> 0.9) 224 | faraday-cookie_jar (~> 0.0.6) 225 | ms_rest (~> 0.7.4) 226 | unf_ext (= 0.0.7.2) 227 | multi_json (1.13.1) 228 | multipart-post (2.1.1) 229 | necromancer (0.4.0) 230 | net-scp (2.0.0) 231 | net-ssh (>= 2.6.5, < 6.0.0) 232 | net-ssh (5.2.0) 233 | net-ssh-gateway (2.0.0) 234 | net-ssh (>= 4.0.0) 235 | nori (2.6.0) 236 | os (1.0.1) 237 | parallel (1.17.0) 238 | parslet (1.8.2) 239 | pastel (0.7.2) 240 | equatable (~> 0.5.0) 241 | tty-color (~> 0.4.0) 242 | pry (0.12.2) 243 | coderay (~> 1.1.0) 244 | method_source (~> 0.9.0) 245 | public_suffix (3.1.1) 246 | rbnacl (4.0.2) 247 | ffi 248 | representable (3.0.4) 249 | declarative (< 0.1.0) 250 | declarative-option (< 0.2.0) 251 | uber (< 0.2.0) 252 | retriable (3.1.2) 253 | rspec (3.8.0) 254 | rspec-core (~> 3.8.0) 255 | rspec-expectations (~> 3.8.0) 256 | rspec-mocks (~> 3.8.0) 257 | rspec-core (3.8.1) 258 | rspec-support (~> 3.8.0) 259 | rspec-expectations (3.8.4) 260 | diff-lcs (>= 1.2.0, < 2.0) 261 | rspec-support (~> 3.8.0) 262 | rspec-its (1.3.0) 263 | rspec-core (>= 3.0.0) 264 | rspec-expectations (>= 3.0.0) 265 | rspec-mocks (3.8.1) 266 | diff-lcs (>= 1.2.0, < 2.0) 267 | rspec-support (~> 3.8.0) 268 | rspec-support (3.8.2) 269 | rubyntlm (0.6.2) 270 | rubyzip (1.3.0) 271 | semverse (3.0.0) 272 | signet (0.11.0) 273 | addressable (~> 2.3) 274 | faraday (~> 0.9) 275 | jwt (>= 1.5, < 3.0) 276 | multi_json (~> 1.10) 277 | sslshake (1.3.0) 278 | strings (0.1.5) 279 | strings-ansi (~> 0.1) 280 | unicode-display_width (~> 1.5) 281 | unicode_utils (~> 1.4) 282 | strings-ansi (0.1.0) 283 | term-ansicolor (1.7.1) 284 | tins (~> 1.0) 285 | test-kitchen (2.2.5) 286 | bcrypt_pbkdf (~> 1.0) 287 | ed25519 (~> 1.2) 288 | license-acceptance (~> 1.0, >= 1.0.11) 289 | mixlib-install (~> 3.6) 290 | mixlib-shellout (>= 1.2, < 3.0) 291 | net-scp (>= 1.1, < 3.0) 292 | net-ssh (>= 2.9, < 6.0) 293 | net-ssh-gateway (>= 1.2, < 3.0) 294 | thor (~> 0.19) 295 | winrm (~> 2.0) 296 | winrm-elevated (~> 1.0) 297 | winrm-fs (~> 1.1) 298 | thor (0.20.3) 299 | timeliness (0.3.10) 300 | timers (4.3.0) 301 | tins (1.20.3) 302 | tomlrb (1.2.8) 303 | train (2.1.7) 304 | azure_graph_rbac (~> 0.16) 305 | azure_mgmt_key_vault (~> 0.17) 306 | azure_mgmt_resources (~> 0.15) 307 | docker-api (~> 1.26) 308 | google-api-client (~> 0.23.9) 309 | googleauth (~> 0.6.6) 310 | inifile 311 | json (>= 1.8, < 3.0) 312 | mixlib-shellout (>= 2.0, < 4.0) 313 | net-scp (>= 1.2, < 3.0) 314 | net-ssh (>= 2.9, < 6.0) 315 | winrm (~> 2.0) 316 | winrm-fs (~> 1.0) 317 | train-aws (0.1.5) 318 | aws-sdk-autoscaling (~> 1.22.0) 319 | aws-sdk-cloudtrail (~> 1.8) 320 | aws-sdk-cloudwatch (~> 1.13) 321 | aws-sdk-cloudwatchlogs (~> 1.13) 322 | aws-sdk-configservice (~> 1.21) 323 | aws-sdk-core (~> 3.0) 324 | aws-sdk-costandusagereportservice (~> 1.6) 325 | aws-sdk-dynamodb (~> 1.31) 326 | aws-sdk-ec2 (~> 1.70) 327 | aws-sdk-ecr (~> 1.18) 328 | aws-sdk-ecs (~> 1.30) 329 | aws-sdk-eks (~> 1.9) 330 | aws-sdk-elasticloadbalancing (~> 1.8) 331 | aws-sdk-iam (~> 1.13) 332 | aws-sdk-kms (~> 1.13) 333 | aws-sdk-organizations (~> 1.17.0) 334 | aws-sdk-rds (~> 1.43) 335 | aws-sdk-s3 (~> 1.30) 336 | aws-sdk-sns (~> 1.9) 337 | aws-sdk-sqs (~> 1.10) 338 | train (~> 2.0) 339 | train-habitat (0.1.1) 340 | train (>= 1.7.5, < 3.0) 341 | tty-box (0.3.0) 342 | pastel (~> 0.7.2) 343 | strings (~> 0.1.4) 344 | tty-cursor (~> 0.6.0) 345 | tty-color (0.4.3) 346 | tty-cursor (0.6.1) 347 | tty-prompt (0.18.1) 348 | necromancer (~> 0.4.0) 349 | pastel (~> 0.7.0) 350 | timers (~> 4.0) 351 | tty-cursor (~> 0.6.0) 352 | tty-reader (~> 0.5.0) 353 | tty-reader (0.5.0) 354 | tty-cursor (~> 0.6.0) 355 | tty-screen (~> 0.6.4) 356 | wisper (~> 2.0.0) 357 | tty-screen (0.6.5) 358 | tty-table (0.10.0) 359 | equatable (~> 0.5.0) 360 | necromancer (~> 0.4.0) 361 | pastel (~> 0.7.2) 362 | strings (~> 0.1.0) 363 | tty-screen (~> 0.6.4) 364 | tty-which (0.4.1) 365 | uber (0.1.0) 366 | unf (0.1.4) 367 | unf_ext 368 | unf_ext (0.0.7.2) 369 | unicode-display_width (1.6.0) 370 | unicode_utils (1.4.0) 371 | winrm (2.3.2) 372 | builder (>= 2.1.2) 373 | erubis (~> 2.7) 374 | gssapi (~> 1.2) 375 | gyoku (~> 1.0) 376 | httpclient (~> 2.2, >= 2.2.0.2) 377 | logging (>= 1.6.1, < 3.0) 378 | nori (~> 2.0) 379 | rubyntlm (~> 0.6.0, >= 0.6.1) 380 | winrm-elevated (1.1.1) 381 | winrm (~> 2.0) 382 | winrm-fs (~> 1.0) 383 | winrm-fs (1.3.2) 384 | erubis (~> 2.7) 385 | logging (>= 1.6.1, < 3.0) 386 | rubyzip (~> 1.1) 387 | winrm (~> 2.0) 388 | wisper (2.0.0) 389 | 390 | PLATFORMS 391 | ruby 392 | 393 | DEPENDENCIES 394 | kitchen-terraform 395 | test-kitchen 396 | 397 | RUBY VERSION 398 | ruby 2.6.3p62 399 | 400 | BUNDLED WITH 401 | 1.17.2 402 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 James Turnbull 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An example data center architecture with Terraform 2 | 3 | A lightweight data center architecture for The Terraform Book. 4 | 5 | ## Usage 6 | 7 | Checkout the repository and all sub-modules: 8 | 9 | ```bash 10 | git clone --recursive https://github.com/turnbullpublishing/tf_dc.git 11 | ``` 12 | 13 | The rough directory tree should be: 14 | 15 | ``` 16 | . 17 | ├── LICENSE 18 | ├── README.md 19 | ├── development 20 | │   ├── api.tf 21 | │   ├── consul.tf 22 | │   ├── main.tf 23 | │   ├── outputs.tf 24 | │   ├── terraform.tfvars 25 | │   ├── variables.tf 26 | │   └── web.tf 27 | ├── modules 28 | │   ├── api 29 | │   ├── consul 30 | │   ├── vpc 31 | │   └── web 32 | └── production 33 | ``` 34 | 35 | ## License 36 | 37 | MIT 38 | -------------------------------------------------------------------------------- /development/api.tf: -------------------------------------------------------------------------------- 1 | variable "api_instance_count" { 2 | default = 5 3 | description = "The number of API instances to create." 4 | } 5 | 6 | module "api" { 7 | source = "github.com/turnbullpublishing/tf_api" 8 | environment = var.environment 9 | vpc_id = module.vpc.vpc_id 10 | public_subnet_ids = module.vpc.public_subnet_ids 11 | private_subnet_ids = module.vpc.private_subnet_ids 12 | region = var.region 13 | key_name = var.key_name 14 | api_instance_count = var.api_instance_count 15 | } 16 | 17 | output "api_elb_address" { 18 | value = module.api.api_elb_address 19 | } 20 | 21 | output "api_host_addresses" { 22 | value = [module.api.api_host_addresses] 23 | } 24 | 25 | -------------------------------------------------------------------------------- /development/kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: terraform 4 | 5 | provisioner: 6 | name: terraform 7 | variable_files: 8 | - terraform.tfvars 9 | 10 | platforms: 11 | - name: ubuntu 12 | 13 | verifier: 14 | name: terraform 15 | systems: 16 | - name: bastion 17 | backend: ssh 18 | hosts_output: bastion_host_dns 19 | user: ubuntu 20 | key_files: 21 | - ~/.ssh/james_aws 22 | 23 | suites: 24 | - name: default 25 | -------------------------------------------------------------------------------- /development/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | terraform { 6 | backend "s3" { 7 | region = "us-east-1" 8 | bucket = "examplecom-remote-state-development" 9 | key = "terraform.tfstate" 10 | } 11 | } 12 | 13 | module "vpc" { 14 | source = "github.com/turnbullpublishing/tf_vpc.git?ref=v0.0.4" 15 | environment = var.environment 16 | region = var.region 17 | key_name = var.key_name 18 | vpc_cidr = var.vpc_cidr 19 | public_subnets = var.public_subnets 20 | private_subnets = var.private_subnets 21 | } 22 | 23 | output "public_subnet_ids" { 24 | value = [module.vpc.public_subnet_ids] 25 | } 26 | 27 | output "private_subnet_ids" { 28 | value = [module.vpc.private_subnet_ids] 29 | } 30 | 31 | output "bastion_host_dns" { 32 | value = module.vpc.bastion_host_dns 33 | } 34 | 35 | output "bastion_host_ip" { 36 | value = module.vpc.bastion_host_ip 37 | } 38 | 39 | -------------------------------------------------------------------------------- /development/test/integration/default/controls/operating_system_spec.rb: -------------------------------------------------------------------------------- 1 | control 'operating_system' do 2 | title 'Operating system controls' 3 | desc ' 4 | Checks that the host operating system is correctly 5 | configured. 6 | ' 7 | tag 'operating_system', 'ubuntu' 8 | 9 | describe command('lsb_release -a') do 10 | its('stdout') { should match (/Ubuntu 16.04/) } 11 | end 12 | 13 | services = [ 'cron', 'rsyslog' ] 14 | 15 | services.each do |service| 16 | describe service(service) do 17 | it { should be_enabled } 18 | it { should be_running } 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /development/test/integration/default/controls/resolv_conf_spec.rb: -------------------------------------------------------------------------------- 1 | control 'resolv.conf' do 2 | title 'Resolv.conf tests' 3 | desc ' 4 | Tests the contents of the resolv.conf file. 5 | ' 6 | tag 'resolv.conf', 'ubuntu' 7 | 8 | describe resolv_conf do 9 | its('nameserver') { should eq('10.0.0.2') } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /development/test/integration/default/controls/sshd_spec.rb: -------------------------------------------------------------------------------- 1 | control 'sshd' do 2 | title 'SSHd controls' 3 | desc " 4 | Checks that the host's SSH daemon is correctly configured. 5 | " 6 | tag 'sshd', 'ubuntu' 7 | 8 | describe service('sshd') do 9 | it { should be_enabled } 10 | it { should be_running } 11 | end 12 | 13 | describe sshd_config do 14 | its('Protocol') { should eq '2'} 15 | its('Port') { should eq('22') } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /development/test/integration/default/inspec.lock: -------------------------------------------------------------------------------- 1 | --- 2 | lockfile_version: 1 3 | depends: [] 4 | -------------------------------------------------------------------------------- /development/test/integration/default/inspec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: default 3 | title: 'Default suite of tests' 4 | summary: 'A collection of controls to test baseline host configuration' 5 | maintainer: 'James Turnbull' 6 | copyright: 'Turnbull Press' 7 | license: 'MIT' 8 | version: 1.0.0 9 | -------------------------------------------------------------------------------- /development/test/integration/default/libraries/resolv_conf.rb: -------------------------------------------------------------------------------- 1 | class ResolvConf < Inspec.resource(1) 2 | name 'resolv_conf' 3 | 4 | desc ' 5 | Check resolv.conf configuration. 6 | ' 7 | 8 | example " 9 | describe resolv_conf do 10 | its('nameserver') { should eq('10.0.0.2') } 11 | end 12 | " 13 | 14 | def initialize 15 | @path = "/etc/resolv.conf" 16 | @file = inspec.file(@path) 17 | 18 | begin 19 | @params = Hash[*@file.content.split("\n") 20 | .reject{ |l| l =~ /^#/ } 21 | .collect { |v| [ v.chomp.split ] } 22 | .flatten] 23 | rescue StandardError 24 | return skip_resource "#{@file}: #{$!}" 25 | end 26 | end 27 | 28 | def exists? 29 | @file.file? 30 | end 31 | 32 | def method_missing(name) 33 | @params[name.to_s] 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /development/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | type = string 3 | description = "The AWS region." 4 | } 5 | 6 | variable "prefix" { 7 | type = string 8 | description = "The name of our org, i.e. examplecom." 9 | } 10 | 11 | variable "environment" { 12 | type = string 13 | description = "The name of our environment, i.e. development." 14 | default = "development" 15 | } 16 | 17 | variable "key_name" { 18 | type = string 19 | description = "The AWS key pair to use for resources." 20 | } 21 | 22 | variable "vpc_cidr" { 23 | type = string 24 | description = "The CIDR of the VPC." 25 | } 26 | 27 | variable "public_subnets" { 28 | type = list(string) 29 | default = [] 30 | description = "The list of public subnets to populate." 31 | } 32 | 33 | variable "private_subnets" { 34 | type = list(string) 35 | default = [] 36 | description = "The list of private subnets to populate." 37 | } 38 | 39 | -------------------------------------------------------------------------------- /development/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | -------------------------------------------------------------------------------- /development/web.tf: -------------------------------------------------------------------------------- 1 | variable "cloudflare_email" { 2 | type = string 3 | description = "The Cloudflare email of your account" 4 | } 5 | 6 | variable "cloudflare_token" { 7 | type = string 8 | description = "The Cloudflare token" 9 | } 10 | 11 | variable "domain" { 12 | type = string 13 | description = "The domain of our web service." 14 | } 15 | 16 | variable "web_instance_count" { 17 | type = number 18 | default = 2 19 | description = "The number of Web instances" 20 | } 21 | 22 | variable "app_instance_count" { 23 | type = number 24 | default = 2 25 | description = "The number of App instances" 26 | } 27 | 28 | provider "cloudflare" { 29 | email = var.cloudflare_email 30 | token = var.cloudflare_token 31 | } 32 | 33 | module "web" { 34 | source = "github.com/turnbullpublishing/tf_web" 35 | environment = var.environment 36 | vpc_id = module.vpc.vpc_id 37 | public_subnet_ids = module.vpc.public_subnet_ids 38 | private_subnet_ids = module.vpc.private_subnet_ids 39 | web_instance_count = var.web_instance_count 40 | app_instance_count = var.app_instance_count 41 | domain = var.domain 42 | region = var.region 43 | key_name = var.key_name 44 | } 45 | 46 | output "web_elb_address" { 47 | value = module.web.web_elb_address 48 | } 49 | 50 | output "web_host_addresses" { 51 | value = [module.web.web_host_addresses] 52 | } 53 | 54 | output "app_host_addresses" { 55 | value = [module.web.app_host_addresses] 56 | } 57 | 58 | -------------------------------------------------------------------------------- /production/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | terraform { 6 | backend "s3" { 7 | region = "us-east-1" 8 | bucket = "examplecom-remote-state-production" 9 | key = "terraform.tfstate" 10 | } 11 | } 12 | 13 | module "vpc" { 14 | source = "git@github.com:turnbullpublishing/tf_vpc.git?ref=v0.0.4" 15 | environment = var.environment 16 | region = var.region 17 | key_name = var.key_name 18 | vpc_cidr = var.vpc_cidr 19 | public_subnets = [var.public_subnets] 20 | private_subnets = [var.private_subnets] 21 | } 22 | 23 | -------------------------------------------------------------------------------- /production/outputs.tf: -------------------------------------------------------------------------------- 1 | output "public_subnet_ids" { 2 | value = [module.vpc.public_subnet_ids] 3 | } 4 | 5 | output "private_subnet_ids" { 6 | value = [module.vpc.private_subnet_ids] 7 | } 8 | 9 | output "bastion_host_dns" { 10 | value = module.vpc.bastion_host_dns 11 | } 12 | 13 | output "bastion_host_ip" { 14 | value = module.vpc.bastion_host_ip 15 | } 16 | 17 | -------------------------------------------------------------------------------- /production/variables.tf: -------------------------------------------------------------------------------- 1 | variable "access_key" { 2 | type = string 3 | description = "The AWS access key." 4 | } 5 | 6 | variable "secret_key" { 7 | type = string 8 | description = "The AWS secret key." 9 | } 10 | 11 | variable "region" { 12 | type = string 13 | description = "The AWS region." 14 | } 15 | 16 | variable "environment" { 17 | type = string 18 | description = "The name of our environment, i.e. development." 19 | default = "production" 20 | } 21 | 22 | variable "key_name" { 23 | type = string 24 | description = "The AWS key pair to use for resources." 25 | } 26 | 27 | variable "vpc_cidr" { 28 | type = string 29 | description = "The CIDR of the VPC." 30 | } 31 | 32 | variable "public_subnets" { 33 | type = list(string) 34 | default = [] 35 | description = "The list of public subnets to populate." 36 | } 37 | 38 | variable "private_subnets" { 39 | type = list(string) 40 | default = [] 41 | description = "The list of private subnets to populate." 42 | } 43 | 44 | -------------------------------------------------------------------------------- /production/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | --------------------------------------------------------------------------------