deployment/terraform/aws/modules/vault/main.tf (225 lines of code) (raw):
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
module "label" {
source = "cloudposse/label/null"
version = "0.25.0"
environment = var.environment
label_order = ["namespace", "name", "environment"]
name = var.name
namespace = var.namespace
tags = var.tags
}
resource "aws_iam_role" "instance_role" {
name = "${var.namespace}-${var.name}"
description = "Vault role for ${module.label.id}"
assume_role_policy = data.aws_iam_policy_document.instance_role.json
}
data "aws_iam_policy_document" "instance_role" {
statement {
effect = "Allow"
actions = [
"sts:AssumeRole",
]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_instance_profile" "vault" {
name_prefix = "${var.namespace}-${var.name}"
role = aws_iam_role.instance_role.name
tags = module.label.tags
}
resource "aws_iam_role_policy" "auto_join" {
name = "${var.namespace}-${var.name}-auto-join"
policy = data.aws_iam_policy_document.auto_join.json
role = aws_iam_role.instance_role.id
}
data "aws_iam_policy_document" "auto_join" {
statement {
effect = "Allow"
actions = [
"ec2:DescribeInstances",
"ec2:DescribeTags"
]
resources = ["*"]
}
}
resource "aws_iam_role_policy" "auto_unseal" {
name = "${var.namespace}-${var.name}-auto-unseal"
policy = data.aws_iam_policy_document.auto_unseal.json
role = aws_iam_role.instance_role.id
}
resource "aws_kms_key" "vault" {
description = "AWS KMS key used for Vault auto-unseal and encryption"
key_usage = "ENCRYPT_DECRYPT"
deletion_window_in_days = 7
is_enabled = true
tags = merge(
var.tags,
{
"Name" = "${var.namespace}-${var.name}-key"
}
)
}
data "aws_iam_policy_document" "auto_unseal" {
statement {
effect = "Allow"
actions = [
"kms:DescribeKey",
"kms:Encrypt",
"kms:Decrypt",
]
resources = [
aws_kms_key.vault.arn,
]
}
}
resource "aws_iam_role_policy" "secrets_manager" {
name = "${var.namespace}-${var.name}-secrets-manager"
policy = data.aws_iam_policy_document.secrets_manager.json
role = aws_iam_role.instance_role.id
}
data "aws_iam_policy_document" "secrets_manager" {
statement {
effect = "Allow"
actions = [
"secretsmanager:GetSecretValue",
]
resources = [
var.secrets_manager_arn,
]
}
}
module "alb" {
source = "cloudposse/alb/aws"
version = "1.11.1"
alb_access_logs_s3_bucket_force_destroy = var.alb_destroy_log_bucket
attributes = ["alb"]
certificate_arn = var.alb_certificate_arn
deletion_protection_enabled = var.deletion_protection
health_check_interval = 60
health_check_path = var.alb_health_check_path
health_check_timeout = 10
http_ingress_cidr_blocks = var.http_ingress_cidr_blocks
http_redirect = var.http_redirect
https_enabled = true
https_ingress_cidr_blocks = var.https_ingress_cidr_blocks
internal = true
lifecycle_rule_enabled = true
name = module.label.id
subnet_ids = var.private_subnet_ids
tags = module.label.tags
target_group_name = module.label.id
target_group_port = var.container_port
target_group_target_type = "instance"
vpc_id = var.vpc_id
stickiness = var.stickiness
}
resource "aws_security_group" "vault_private" {
name = "${var.namespace}-${var.name}"
description = "Vault Security Group"
vpc_id = var.vpc_id
tags = merge(
var.tags,
{
"Name" = "${var.namespace}-${var.name}-sg"
}
)
}
resource "aws_security_group_rule" "vault_internal_api" {
security_group_id = aws_security_group.vault_private.id
description = "Vault Internal API"
type = "ingress"
from_port = 8200
to_port = 8200
protocol = "tcp"
self = true
}
resource "aws_security_group_rule" "vault_internal_raft" {
security_group_id = aws_security_group.vault_private.id
description = "Vault Raft"
type = "ingress"
from_port = 8201
to_port = 8201
protocol = "tcp"
self = true
}
resource "aws_security_group_rule" "vault_ssh_inbound" {
description = "Allow SSH"
security_group_id = aws_security_group.vault_private.id
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
self = true
}
resource "aws_security_group_rule" "vault_alb_inbound" {
security_group_id = aws_security_group.vault_private.id
description = "Allow AWS ALB to reach Vault nodes"
type = "ingress"
from_port = 8200
to_port = 8200
protocol = "tcp"
source_security_group_id = module.alb.security_group_id
}
resource "aws_security_group_rule" "vault_outbound" {
security_group_id = aws_security_group.vault_private.id
description = "Allow Vault nodes to send outbound traffic"
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
resource "aws_launch_template" "vault" {
name = "${var.namespace}-${var.name}"
image_id = var.ubuntu_ami
instance_type = var.instance_type
key_name = var.ssh_key_name
user_data = base64encode(templatefile("${path.module}/templates/install_vault_script.sh.tpl",
{
region = var.region
name = var.namespace
vault_version = var.vault_version
kms_key_arn = aws_kms_key.vault.arn
secrets_manager_arn = var.secrets_manager_arn
leader_tls_servername = var.leader_tls_servername
}))
vpc_security_group_ids = [
aws_security_group.vault_private.id,
]
block_device_mappings {
device_name = "/dev/sda1"
ebs {
volume_type = "gp3"
volume_size = 100
throughput = 150
iops = 3000
delete_on_termination = true
}
}
iam_instance_profile {
name = aws_iam_instance_profile.vault.name
}
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}
}
resource "aws_autoscaling_group" "vault" {
name = "${var.namespace}-${var.name}-asg"
min_size = var.min_nodes
max_size = var.max_nodes
desired_capacity = var.min_nodes
vpc_zone_identifier = var.private_subnet_ids
target_group_arns = [module.alb.default_target_group_arn]
launch_template {
id = aws_launch_template.vault.id
version = "$Latest"
}
tag {
key = "Name"
value = "${var.namespace}-${var.name}-server"
propagate_at_launch = true
}
}