diff --git a/DevOpsVPC/infrastructure.conf b/DevOpsVPC/infrastructure.conf index b7db1ee..7014083 100755 --- a/DevOpsVPC/infrastructure.conf +++ b/DevOpsVPC/infrastructure.conf @@ -12,12 +12,16 @@ #-- Version of our infrastructure #-- It has no effect, just to help versioning. -en_infra_aws_version = "1.3.0" +en_infra_aws_version = "1.6.0" #-- AWS region aws_region = "us-east-1" aws_azs = ["us-east-1a", "us-east-1b"] +#-- Store our state file remotely +statefile_bucket = "en-infra-aws-remote-state" +statefile_dynamo = "en-infra-aws-remote-state-lock" + #-- Name vpc_name = "TestTerraformVPC" diff --git a/DevOpsVPC/providers.tf b/DevOpsVPC/providers.tf index ee01bce..bb89e07 100644 --- a/DevOpsVPC/providers.tf +++ b/DevOpsVPC/providers.tf @@ -16,5 +16,5 @@ provider "aws" { region = "${var.aws_region}" #-- must be fullpath, ~ is not evaluated - shared_credentials_file = "/home/vagrant/.aws/credentials" + shared_credentials_file = "${pathexpand("~/.aws/credentials")}" } diff --git a/DevOpsVPC/state.tf b/DevOpsVPC/state.tf new file mode 100644 index 0000000..280bfb6 --- /dev/null +++ b/DevOpsVPC/state.tf @@ -0,0 +1,22 @@ +# +# Project Name:: en_infra_aws +# File:: state.tf +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Configure terraform to store it's state file remote +# + +#-- +terraform { + backend "s3" { + bucket = "en-infra-aws-remote-state" + key = "en_infra_aws/terraform.tfstate" + region = "us-east-1" + lock_table = "en-infra-aws-remote-state-lock" + } +} diff --git a/README.md b/README.md index 452279f..ea0f0f5 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This project uses Terraform to accomplish this goal. - [Supported Cloud Providers by this project](#supported-cloud-providers-by-this-project) - [Dependencies](#dependencies) - [Prerequisites](#prerequisites) + - [Remote state file](#remote-state-file) - [Exposed configuration](#exposed-configuration) - [VPC creation related](#vpc-creation-related) - [Networking related](#networking-related) @@ -24,6 +25,7 @@ This project uses Terraform to accomplish this goal. - [NAT](#nat----modulesnat) - [VPN](#vpn----modulesvpn) - [Usage](#usage) + - [Init Terraform](#terraform-init) - [Inspect the infrastructure](#make-plan) - [Apply changes](#make-apply) - [Destroy managed infrastructure](#make-destroy) @@ -60,7 +62,7 @@ Simple file based configuration gives you a single view of your entire infrastru ## Dependencies |Dependency |Comments | |:---------|:----------| -| `terraform` | This project was developed and tested using `Terraform v0.9.2` | +| `terraform` | This project was developed and tested using `Terraform v0.9.8` | | `make` | `Makefile` helper file was developed and tested using `GNU Make 3.82` | @@ -77,6 +79,12 @@ aws_secret_access_key = someSecretPassKey You need to install terraform by downloading the [appropriate package][4] for your operating system then extract the zip archive.
Terraform runs as a single binary named terraform. +### Remote state file +To prevent stack corruption when terraform is used by multiple teams, remote storate of the state file was implemented. +To provision AWS resource required for remote state storage run `make apply` in `RemoteState` directory. +Name of the created `S3 Bucket` and `DynamoDB table` can be configured from `infrastructure.conf`. +Statefile configuration cannot contain interpolations. If the default values will be changed, the `DevOpsVPC/state.tf` file will also have to be synced manually. + ## Exposed configuration Project's data that can vary from one environment to another was exposed using variables in the `infrastructure.conf` file. This file is automatically loaded when invoking terraform by the `Makefile wrapper`.
@@ -173,6 +181,9 @@ Refer to the `variables.tf` file in the `DevOpsVPC` directory for the default va [//]: # (Identify the commands -- that are meant to be called by a user.) ## Terraform commands are wrapped by the `Makefile` script. +### Terraform init +This will solve module dependencies and configure terraform to use remote state. For provisioning of the resources required for remote state configuration, see [Remote state file][5]. + ### make plan Will read our custom `infrastructure.conf`, process the tf files then compare the local tfstate with the remote state of the infrastructure and will tell you what needs to be done without actually doing it. @@ -202,3 +213,4 @@ License: 'GPL v3'
[2]: https://github.com/hashicorp/hcl "HCL" [3]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html "Make" [4]: https://www.terraform.io/downloads.html "Download Terraform" +[5]: #remote-state-file "Prerequisites - Remote state file" diff --git a/RemoteState/Makefile b/RemoteState/Makefile new file mode 100644 index 0000000..4d5c18b --- /dev/null +++ b/RemoteState/Makefile @@ -0,0 +1,37 @@ +# +# Project Name:: en_infra_aws +# File:: Makefile +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Helper that will help us manage our 'terraform' plans. + +.PHONY: all test get info plan apply destroy + +all: plan apply +test: plan + +get: + terraform get + +info: + for resursa in $$(terraform state list); do \ + echo -e "\n\n========================\n$$resursa\n------------------------"; \ + terraform state show $$resursa; \ + done + +plan: + terraform plan -var-file ../DevOpsVPC/infrastructure.conf + +apply: + terraform apply -var-file ../DevOpsVPC/infrastructure.conf + +destroy: + terraform plan -destroy -var-file ../DevOpsVPC/infrastructure.conf -out=statefiles/destroy.tfplan -state=statefiles/terraform.tfstate + terraform apply statefiles/destroy.tfplan + mv -f statefiles/terraform.tfstate statefiles/terraform.tfstate.old + mv -f terraform.tfstate statefiles/terraform.tfstate diff --git a/RemoteState/README.md b/RemoteState/README.md new file mode 100644 index 0000000..6a89532 --- /dev/null +++ b/RemoteState/README.md @@ -0,0 +1 @@ +Provisioning of the AWS resources required for remote state file storage and locking. diff --git a/RemoteState/dynamodb_table.tf b/RemoteState/dynamodb_table.tf new file mode 100644 index 0000000..27159ab --- /dev/null +++ b/RemoteState/dynamodb_table.tf @@ -0,0 +1,25 @@ +# +# Project Name:: en_infra_aws +# File:: s3_bucket.tf +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Sets up an S3 Bucket for RemoteState Storage +# + +#-- +resource "aws_dynamodb_table" "terraform_state_lock" { + name = "${var.statefile_dynamo}" + read_capacity = 10 + write_capacity = 10 + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } +} diff --git a/RemoteState/providers.tf b/RemoteState/providers.tf new file mode 100644 index 0000000..bb89e07 --- /dev/null +++ b/RemoteState/providers.tf @@ -0,0 +1,20 @@ +# +# Project Name:: en_infra_aws +# File:: providers.tf +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Sets up aws account access credentials +# and regional preference +# + +#-- +provider "aws" { + region = "${var.aws_region}" + #-- must be fullpath, ~ is not evaluated + shared_credentials_file = "${pathexpand("~/.aws/credentials")}" +} diff --git a/RemoteState/s3_bucket.tf b/RemoteState/s3_bucket.tf new file mode 100644 index 0000000..449efbc --- /dev/null +++ b/RemoteState/s3_bucket.tf @@ -0,0 +1,25 @@ +# +# Project Name:: en_infra_aws +# File:: s3_bucket.tf +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Sets up an S3 Bucket for RemoteState Storage +# + +#-- +resource "aws_s3_bucket" "terraform_state" { + bucket = "${var.statefile_bucket}" + + versioning { + enabled = true + } + + lifecycle { + prevent_destroy = true + } +} diff --git a/RemoteState/variables.tf b/RemoteState/variables.tf new file mode 100644 index 0000000..b7d61bf --- /dev/null +++ b/RemoteState/variables.tf @@ -0,0 +1,34 @@ + +# Project Name:: en_infra_aws +# File:: variables.tf +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Variables we're using with their description. +# If a default value is set, the variable is optional. +# Otherwise, the variable is required. + +#-- Naming +variable "aws_region" { + description = "AWS region" + type = "string" + default = "us-east-1" +} + +#-- +variable "statefile_bucket" { + description = "Name of the S3 bucket where we will store our statefile" + type = "string" + default = "en-infra-aws-remote-state" +} + +#-- +variable "statefile_dynamo" { + description = "Name of the DynamoDB table where we will store our locking" + type = "string" + default = "en-infra-aws-remote-state-lock" +}