You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/enos/modules/aws_vault/vault-instances.tf

362 lines
12 KiB

# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
resource "aws_instance" "vault_instance" {
for_each = local.vault_instances
ami = var.ami_id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.enos_vault_sg[0].id]
subnet_id = tolist(data.aws_subnets.infra.ids)[each.key % length(data.aws_subnets.infra.ids)]
key_name = var.ssh_aws_keypair
iam_instance_profile = aws_iam_instance_profile.vault_profile[0].name
ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count
tags = merge(
var.common_tags,
{
Name = "${local.name_suffix}-vault-${var.vault_node_prefix}-${each.key}-${split(":", data.aws_caller_identity.current.user_id)[1]}"
Type = local.vault_cluster_tag
},
)
}
resource "enos_remote_exec" "install_dependencies" {
depends_on = [aws_instance.vault_instance]
for_each = toset([
for idx in local.vault_instances : idx
if length(var.dependencies_to_install) > 0
])
content = templatefile("${path.module}/templates/install-dependencies.sh", {
dependencies = join(" ", var.dependencies_to_install)
})
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.value].ipv6_addresses[0] : aws_instance.vault_instance[each.value].public_ip
}
}
}
resource "enos_bundle_install" "consul" {
for_each = {
for idx, instance in aws_instance.vault_instance : idx => instance
if var.storage_backend == "consul"
}
destination = var.consul_install_dir
release = merge(var.consul_release, { product = "consul" })
transport = {
ssh = {
host = var.ip_version == "6" ? each.value.ipv6_addresses[0] : each.value.public_ip
}
}
}
resource "enos_bundle_install" "vault" {
for_each = aws_instance.vault_instance
destination = var.vault_install_dir
release = var.vault_release == null ? var.vault_release : merge({ product = "vault" }, var.vault_release)
artifactory = var.vault_artifactory_release
path = var.vault_local_artifact_path
transport = {
ssh = {
host = var.ip_version == "6" ? each.value.ipv6_addresses[0] : each.value.public_ip
}
}
}
resource "enos_consul_start" "consul" {
for_each = enos_bundle_install.consul
bin_path = local.consul_bin_path
data_dir = var.consul_data_dir
config = {
data_dir = var.consul_data_dir
datacenter = "dc1"
retry_join = ["provider=aws tag_key=Type tag_value=${var.consul_cluster_tag}"]
server = false
bootstrap_expect = 0
license = var.consul_license
log_level = var.consul_log_level
log_file = var.consul_log_dir
}
license = var.consul_license
unit_name = "consul"
username = "consul"
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
}
}
}
resource "enos_vault_start" "leader" {
depends_on = [
enos_consul_start.consul,
enos_bundle_install.vault,
]
for_each = local.leader
bin_path = local.vault_bin_path
config_dir = var.vault_config_dir
manage_service = var.manage_service
config = {
api_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8200" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8200"
cluster_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8201" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8201"
cluster_name = local.vault_cluster_tag
listener = {
type = "tcp"
attributes = {
address = var.ip_version == "4" ? "0.0.0.0:8200" : "[::]:8200"
tls_disable = "true"
}
}
log_level = var.vault_log_level
storage = {
type = var.storage_backend
attributes = ({ for key, value in local.storage_config[each.key] : key => value })
}
seal = local.seal[var.unseal_method]
ui = true
}
license = var.vault_license
unit_name = "vault"
username = local.vault_service_user
environment = var.vault_environment
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
}
}
}
resource "enos_vault_start" "followers" {
depends_on = [
enos_vault_start.leader,
]
for_each = local.followers
bin_path = local.vault_bin_path
config_dir = var.vault_config_dir
manage_service = var.manage_service
config = {
api_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8200" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8200"
cluster_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8201" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8201"
cluster_name = local.vault_cluster_tag
log_level = var.vault_log_level
listener = {
type = "tcp"
attributes = {
address = var.ip_version == "4" ? "0.0.0.0:8200" : "[::]:8200"
tls_disable = "true"
}
}
storage = {
type = var.storage_backend
attributes = { for key, value in local.storage_config[each.key] : key => value }
}
seal = local.seal[var.unseal_method]
ui = true
}
license = var.vault_license
unit_name = "vault"
username = local.vault_service_user
environment = var.vault_environment
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
}
}
}
resource "enos_vault_init" "leader" {
depends_on = [enos_vault_start.followers]
for_each = toset([
for idx in local.leader : idx
if var.vault_init
])
bin_path = local.vault_bin_path
vault_addr = enos_vault_start.leader[0].config.api_addr
key_shares = local.key_shares[var.unseal_method]
key_threshold = local.key_threshold[var.unseal_method]
recovery_shares = local.recovery_shares[var.unseal_method]
recovery_threshold = local.recovery_threshold[var.unseal_method]
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
}
}
}
resource "enos_vault_unseal" "leader" {
depends_on = [
enos_vault_start.followers,
enos_vault_init.leader,
]
for_each = enos_vault_init.leader // only unseal the leader if we initialized it
bin_path = local.vault_bin_path
vault_addr = enos_vault_start.leader[each.key].config.api_addr
seal_type = var.unseal_method
unseal_keys = var.unseal_method != "shamir" ? null : coalesce(var.vault_unseal_keys, enos_vault_init.leader[0].unseal_keys_hex)
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
}
}
}
# We need to ensure that the directory used for audit logs is present and accessible to the vault
# user on all nodes, since logging will only happen on the leader.
resource "enos_remote_exec" "create_audit_log_dir" {
depends_on = [
enos_vault_unseal.leader,
]
for_each = toset([
for idx in local.vault_instances : idx
if var.enable_file_audit_device
])
environment = {
LOG_FILE_PATH = local.audit_device_file_path
SERVICE_USER = local.vault_service_user
}
scripts = [abspath("${path.module}/scripts/create_audit_log_dir.sh")]
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.value].ipv6_addresses[0] : aws_instance.vault_instance[each.value].public_ip
}
}
}
resource "enos_remote_exec" "init_audit_device" {
depends_on = [
enos_remote_exec.create_audit_log_dir,
enos_vault_unseal.leader,
]
for_each = toset([
for idx in local.leader : idx
if local.enable_audit_device
])
environment = {
VAULT_TOKEN = enos_vault_init.leader[each.key].root_token
VAULT_ADDR = var.ip_version == "4" ? "http://127.0.0.1:8200" : "http://[::1]:8200"
VAULT_BIN_PATH = local.vault_bin_path
LOG_FILE_PATH = local.audit_device_file_path
SERVICE_USER = local.vault_service_user
}
scripts = [
abspath("${path.module}/scripts/enable_audit_logging.sh"),
]
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
}
}
}
resource "enos_vault_unseal" "followers" {
depends_on = [
enos_vault_init.leader,
enos_vault_unseal.leader,
]
// Only unseal followers if we're not using an auto-unseal method and we've
// initialized the cluster
for_each = {
for idx, follower in local.followers : idx => follower
if var.unseal_method == "shamir" && var.vault_init
}
bin_path = local.vault_bin_path
vault_addr = enos_vault_start.followers[each.key].config.api_addr
seal_type = var.unseal_method
unseal_keys = var.unseal_method != "shamir" ? null : coalesce(var.vault_unseal_keys, enos_vault_init.leader[0].unseal_keys_hex)
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
}
}
}
// Unseal everything when we're not initializing and unseal when not init is set.
// This flag is intended to handle cases when you're adding additional nodes to
// an existing cluster to use auto-pilot to upgrade them and they're not using
// an auto-unseal method.
resource "enos_vault_unseal" "when_vault_unseal_when_no_init_is_set" {
depends_on = [enos_vault_start.followers]
for_each = toset([
for idx in local.instances : idx
if var.vault_unseal_when_no_init && !var.vault_init
])
bin_path = local.vault_bin_path
vault_addr = "http://localhost:8200"
seal_type = var.unseal_method
unseal_keys = coalesce(
var.vault_unseal_keys,
try(enos_vault_init.leader[0].unseal_keys_hex, null),
)
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
}
}
}
resource "enos_remote_exec" "vault_write_license" {
count = var.deploy && var.vault_init ? 1 : 0
depends_on = [
enos_vault_unseal.leader,
enos_vault_unseal.when_vault_unseal_when_no_init_is_set,
]
content = templatefile("${path.module}/templates/vault-write-license.sh", {
vault_bin_path = local.vault_bin_path,
vault_root_token = coalesce(var.vault_root_token, try(enos_vault_init.leader[0].root_token, null), "none")
vault_license = coalesce(var.vault_license, "none")
})
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
}
}
}
resource "enos_remote_exec" "vault_kms_policy" {
count = var.deploy && var.vault_init ? 1 : 0
depends_on = [
enos_remote_exec.vault_write_license,
]
content = templatefile("${path.module}/templates/create-kms-policy.sh", {
vault_bin_path = local.vault_bin_path,
vault_root_token = coalesce(var.vault_root_token, try(enos_vault_init.leader[0].root_token, null), "none")
policy_path = "${path.module}/policies/kms-transit.hcl"
})
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
}
}
}