initial commit

This commit is contained in:
J Cole Morrison 2020-04-09 19:37:14 -07:00
commit ddf83c628c
10 changed files with 424 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.terraform
terraform.tfstate
terraform.tfstate.backup
terraform.tfvars
todos.md
.DS_Store

3
aws-data.tf Normal file
View File

@ -0,0 +1,3 @@
data "aws_availability_zones" "available" {
state = "available"
}

23
dynamodb.tf Normal file
View File

@ -0,0 +1,23 @@
# DynamoDB
resource "aws_dynamodb_table" "vault_storage" {
name = var.dynamodb_table_name
billing_mode = "PAY_PER_REQUEST"
hash_key = "Path"
range_key = "Key"
attribute {
name = "Path"
type = "S"
}
attribute {
name = "Key"
type = "S"
}
tags = {
Name = var.dynamodb_table_name
Project = var.main_project_tag
}
}

77
iam-policies.tf Normal file
View File

@ -0,0 +1,77 @@
# IAM Policies
## KMS Policy
data "aws_iam_policy_document" "kms_vault_policy" {
statement {
sid = "EncryptDecryptAndDescribe"
effect = "Allow"
actions = [
"kms:Decrypt",
"kms:Encrypt",
"kms:DescribeKey"
]
resources = [
aws_kms_key.seal.arn
]
}
}
## DynamoDB Policy
data "aws_iam_policy_document" "dynamodb_vault_policy" {
statement {
sid = "ManageTable"
effect = "Allow"
actions = [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:DescribeTable",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:ListTagsOfResource",
"dynamodb:UpdateItem",
"dynamodb:DescribeTimeToLive"
]
resources = [
aws_dynamodb_table.vault_storage.arn
]
}
statement {
sid = "GetStreamRecords"
effect = "Allow"
actions = [
"dynamodb:GetRecords"
]
resources = [
"${aws_dynamodb_table.vault_storage.arn}/stream/*"
]
}
statement {
sid = "QueryAndScanTable"
effect = "Allow"
actions = [
"dynamodb:Scan",
"dynamodb:Query"
]
resources = [
"${aws_dynamodb_table.vault_storage.arn}/index/*",
aws_dynamodb_table.vault_storage.arn
]
}
}
## AutoScalingGroup Instance Trust Policy
data "aws_iam_policy_document" "asg_trust_policy" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
actions = [
"sts:AssumeRole"
]
}
}

29
iam-roles.tf Normal file
View File

@ -0,0 +1,29 @@
# IAM Roles
## Role for Vault EC2 Instances via AutoScalingGroup
resource "aws_iam_role" "vault_instance" {
name_prefix = "${var.main_project_tag}-instance-role-"
assume_role_policy = data.aws_iam_policy_document.asg_trust_policy.json
}
## Policy Attachments
resource "aws_iam_role_policy" "vault_instance_kms_policy" {
name_prefix = "${var.main_project_tag}-instance-kms-policy-"
role = aws_iam_role.vault_instance.id
policy = data.aws_iam_policy_document.kms_vault_policy.json
}
resource "aws_iam_role_policy" "vault_instance_dynamodb_policy" {
name_prefix = "${var.main_project_tag}-instance-dynamodb-policy-"
role = aws_iam_role.vault_instance.id
policy = data.aws_iam_policy_document.dynamodb_vault_policy.json
}
## Instance Profile
resource "aws_iam_instance_profile" "vault_instance_profile" {
name_prefix = "${var.main_project_tag}-instance-profile-"
role = aws_iam_role.vault_instance.name
}

16
kms.tf Normal file
View File

@ -0,0 +1,16 @@
# AWS KMS Key
resource "aws_kms_key" "seal" {
description = "The KMS key to unseal Vault."
enable_key_rotation = true
tags = merge(
{ "Name" = "${var.main_project_tag}-seal-key" },
{ "Project" = var.main_project_tag },
var.kms_tags
)
}
resource "aws_kms_alias" "seal" {
name = "alias/${var.main_project_tag}-seal-key"
target_key_id = aws_kms_key.seal.key_id
}

0
main.tf Normal file
View File

4
providers.tf Normal file
View File

@ -0,0 +1,4 @@
provider "aws" {
region = var.aws_default_region
profile = var.aws_profile
}

92
variables.tf Normal file
View File

@ -0,0 +1,92 @@
# Organization
variable "main_project_tag" {
description = "Tag that will be attached to all resources."
type = string
default = "vault-deployment"
}
# AWS Provider
variable "aws_profile" {
description = "The AWS Profile to use for this project."
type = string
default = "default"
}
variable "aws_default_region" {
description = "The default region to deploy this."
type = string
default = "us-east-1"
}
# AWS VPC
variable "vpc_cidr" {
description = "Cidr block for the VPC. Using a /16 or /20 Subnet Mask is recommended."
type = string
default = "10.255.0.0/20"
}
variable "vpc_instance_tenancy" {
description = "Tenancy for instances launched into the VPC"
type = string
default = "default"
}
variable "vpc_enable_dns_support" {
description = "Whether the DNS resolution is supported."
type = bool
default = true
}
variable "vpc_enable_dns_hostnames" {
description = "Whether instances with public IP addresses get corresponding public DNS hostnames."
type = bool
default = true
}
variable "vpc_tags" {
description = "Additional tags to add to the VPC and its resources."
type = map(string)
default = {}
}
# VPC Subnets
variable "vpc_public_subnet_count" {
description = "The number of public subnets to create. Cannot exceed the number of AZs in your selected region. 2 is more than enough."
type = number
default = 2
}
variable "vpc_private_subnet_count" {
description = "The number of private subnets to create. Cannot exceed the number of AZs in your selected region."
type = number
default = 2
}
# KMS
variable "kms_tags" {
description = "Tags for the KMS key used to seal and unseal the Vault."
type = map(string)
default = {}
}
# DynamoDB
variable "dynamodb_table_name" {
description = "Name of the DynamoDB Table used for the Vault Storage Backend."
type = string
default = "vault_storage"
}
# Operator Mode
## Turning this on will enable NAT and Bastion to access the Vault Instances
variable "operator_mode" {
description = "Enable a NAT Gateway and Bastion for operator access into the Vault Instances."
type = bool
default = true
}

174
vpc.tf Normal file
View File

@ -0,0 +1,174 @@
# VPC
resource "aws_vpc" "vault" {
cidr_block = var.vpc_cidr
instance_tenancy = var.vpc_instance_tenancy
enable_dns_support = var.vpc_enable_dns_support
enable_dns_hostnames = var.vpc_enable_dns_hostnames
tags = merge(
{ "Name" = "${var.main_project_tag}-vpc" },
{ "Project" = var.main_project_tag },
var.vpc_tags
)
}
# Gateways
## Internet Gateway
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vault.id
tags = merge(
{ "Name" = "${var.main_project_tag}-igw"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
}
## NAT Gateway
#### The NAT Elastic IP
resource "aws_eip" "nat" {
count = var.operator_mode ? 1 : 0
vpc = true
tags = merge(
{ "Name" = "${var.main_project_tag}-nat-eip"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
depends_on = [aws_internet_gateway.igw]
}
#### The NAT Gateway
resource "aws_nat_gateway" "nat" {
count = var.operator_mode ? 1 : 0
allocation_id = aws_eip.nat[0].id
subnet_id = aws_subnet.public.0.id
tags = merge(
{ "Name" = "${var.main_project_tag}-nat"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
depends_on = [
aws_internet_gateway.igw,
aws_eip.nat
]
}
# Route Tables
# NOTE: Routing to the VPC's CIDR is allowed by default, so no route is needed
## Public Route Table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.vault.id
tags = merge(
{ "Name" = "${var.main_project_tag}-public-rtb"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
}
#### Public routes
resource "aws_route" "public_internet_access" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
## Private Route Table
resource "aws_route_table" "private" {
vpc_id = aws_vpc.vault.id
tags = merge(
{ "Name" = "${var.main_project_tag}-private-rtb"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
}
#### Private Routes
resource "aws_route" "private_internet_access" {
count = var.operator_mode ? 1 : 0
route_table_id = aws_route_table.private.id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat[0].id
}
# Subnets
## Public Subnets
resource "aws_subnet" "public" {
count = var.vpc_public_subnet_count
vpc_id = aws_vpc.vault.id
cidr_block = cidrsubnet(aws_vpc.vault.cidr_block, 4, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = merge(
{ "Name" = "${var.main_project_tag}-public-${data.aws_availability_zones.available.names[count.index]}"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
}
## Private Subnets
resource "aws_subnet" "private" {
count = var.vpc_private_subnet_count
vpc_id = aws_vpc.vault.id
# Increment the netnum by the number of public subnets to avoid overlap
cidr_block = cidrsubnet(aws_vpc.vault.cidr_block, 4, count.index + var.vpc_public_subnet_count)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = merge(
{ "Name" = "${var.main_project_tag}-private-${data.aws_availability_zones.available.names[count.index]}"},
{ "Project" = var.main_project_tag },
var.vpc_tags
)
}
# VPC Endpoints
# Make safe calls to KMS and DynamoDB without leaving the VPC.