locals { use_strategy = var.use_strategy cloudinit_ignore = var.cloudinit_ignore server = var.server image = var.image image_workfolder = (local.image.workfolder == "~" ? "/home/${local.image.user}" : local.image.workfolder) access_addresses = var.access_addresses ssh = var.ssh add_domain = var.add_domain domain = var.domain add_eip = var.add_eip domain_ips = flatten(local.domain.ips) # tflint-ignore: terraform_unused_declarations fail_domain_ips = ((local.add_domain && length(local.domain_ips) == 0) ? one([local.domain_ips, "missing_domain_ips"]) : false) all_ips = compact(concat(local.domain_ips, [(local.add_eip ? aws_eip.created[0].public_ip : "")])) server_security_group_name = var.server_security_group_name access_address_cidrs_length = [ for i in range(length(local.access_addresses)) : length(local.access_addresses[keys(local.access_addresses)[i]].cidrs) ] # [1,1,2,2,1] access_address_cidrs_matrix = merge([ for ia in range(length(local.access_addresses)) : { for ib in range(local.access_address_cidrs_length[ia]) : "${keys(local.access_addresses)[ia]}-${ib}" => { port = local.access_addresses[keys(local.access_addresses)[ia]].port cidr = local.access_addresses[keys(local.access_addresses)[ia]].cidrs[ib] ip_family = local.access_addresses[keys(local.access_addresses)[ia]].ip_family protocol = local.access_addresses[keys(local.access_addresses)[ia]].protocol } } ]...) } data "aws_security_group" "server_security_group" { filter { name = "tag:Name" values = [local.server_security_group_name] } } resource "aws_security_group" "direct_access" { name = "${local.server.name}-direct" description = "Security group for server ${local.server.name}" vpc_id = local.server.vpc_id tags = { Name = "${local.server.name}-direct" } } resource "aws_vpc_security_group_ingress_rule" "server_ingress" { depends_on = [ aws_security_group.direct_access, ] for_each = local.access_address_cidrs_matrix security_group_id = aws_security_group.direct_access.id from_port = each.value.port to_port = each.value.port ip_protocol = each.value.protocol cidr_ipv4 = (each.value.ip_family != "ipv6" ? each.value.cidr : null) cidr_ipv6 = (each.value.ip_family == "ipv6" ? each.value.cidr : null) } # allow the server's security group direct access to the server resource "aws_vpc_security_group_ingress_rule" "server_direct_link" { depends_on = [ aws_security_group.direct_access, data.aws_security_group.server_security_group, ] security_group_id = aws_security_group.direct_access.id referenced_security_group_id = data.aws_security_group.server_security_group.id ip_protocol = -1 } resource "aws_network_interface_sg_attachment" "server_security_group_attachment" { depends_on = [ aws_security_group.direct_access, ] security_group_id = aws_security_group.direct_access.id network_interface_id = local.server.network_interface_id } resource "aws_eip" "created" { count = local.add_eip ? 1 : 0 domain = "vpc" } resource "aws_eip_association" "created" { depends_on = [ aws_eip.created, ] count = local.add_eip ? 1 : 0 allocation_id = aws_eip.created[0].id network_interface_id = local.server.network_interface_id allow_reassociation = true # this should allow the server to be destroyed without the ip changing } data "aws_route53_zone" "general_info" { count = (local.add_domain ? 1 : 0) name = local.domain.zone } resource "aws_route53_record" "created" { depends_on = [ aws_eip.created, aws_eip_association.created, data.aws_route53_zone.general_info, ] count = (local.add_domain ? 1 : 0) zone_id = data.aws_route53_zone.general_info[0].zone_id name = local.domain.name type = local.domain.type ttl = 300 records = local.all_ips allow_overwrite = true } resource "terraform_data" "setup" { depends_on = [ aws_eip.created, aws_eip_association.created, aws_network_interface_sg_attachment.server_security_group_attachment, aws_vpc_security_group_ingress_rule.server_ingress, aws_vpc_security_group_ingress_rule.server_direct_link, aws_security_group.direct_access, ] count = (local.use_strategy == "ssh" ? 1 : 0) triggers_replace = [ local.server.id ] connection { type = "ssh" user = local.image.user script_path = "${local.image_workfolder}/setup" agent = true host = (local.add_eip ? aws_eip.created[0].public_ip : local.server.public_ip) } provisioner "remote-exec" { inline = ["echo 'connection successful'"] } provisioner "file" { source = "${path.module}/initial.sh" destination = "${local.image_workfolder}/initial.sh" } provisioner "remote-exec" { inline = [<<-EOT set -x set -e sudo chmod +x ${local.image_workfolder}/initial.sh sudo ${local.image_workfolder}/initial.sh ${local.image.user} ${local.ssh.user} ${local.server.name} ${local.image.admin_group} ${local.ssh.timeout} ${local.cloudinit_ignore} EOT ] } } resource "terraform_data" "remove_initial_user" { depends_on = [ aws_eip.created, terraform_data.setup, aws_eip_association.created, aws_network_interface_sg_attachment.server_security_group_attachment, aws_vpc_security_group_ingress_rule.server_ingress, aws_vpc_security_group_ingress_rule.server_direct_link, aws_security_group.direct_access, ] count = (local.use_strategy == "ssh" ? 1 : 0) triggers_replace = [ local.server.id, ] connection { type = "ssh" user = local.ssh.user script_path = "${local.ssh.user_workfolder}/remove_initial_user_script" agent = true host = (local.add_eip ? aws_eip.created[0].public_ip : local.server.public_ip) } provisioner "remote-exec" { inline = ["echo 'connection successful'"] } provisioner "file" { source = "${path.module}/remove_initial_user.sh" destination = "${local.ssh.user_workfolder}/remove_initial_user.sh" } provisioner "remote-exec" { inline = [<<-EOT set -x set -e sudo chmod +x ${local.ssh.user_workfolder}/remove_initial_user.sh sudo ${local.ssh.user_workfolder}/remove_initial_user.sh ${local.image.user} EOT ] } }