1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# EC2 Nodes ====================================================================
# Key pairs --------------------------------------------------------------------
resource "aws_key_pair" "this" {
for_each = var.key_pairs
key_name = "${var.name_prefix}-${local.region_abbr}-keypair-${each.value.name}"
public_key = each.value.public_key
tags = merge(var.tags, local.module_tags, {
resource-type = "ec2-key-pair"
})
}
# Instances --------------------------------------------------------------------
resource "aws_instance" "this" {
for_each = var.instances
ami = each.value.ami_id
instance_type = each.value.instance_type
subnet_id = each.value.subnet_id
vpc_security_group_ids = each.value.security_group_ids
iam_instance_profile = each.value.iam_instance_profile
key_name = try(aws_key_pair.this[each.value.key_name].key_name, each.value.key_name)
associate_public_ip_address = each.value.associate_public_ip
ebs_optimized = each.value.ebs_optimized
monitoring = each.value.monitoring
user_data = each.value.user_data_base64 == null ? each.value.user_data : null
user_data_base64 = each.value.user_data_base64
placement_group = each.value.placement_group
tenancy = each.value.tenancy
private_ip = each.value.primary_private_ip
secondary_private_ips = each.value.secondary_private_ips
metadata_options {
http_endpoint = "enabled"
http_tokens = each.value.metadata_http_tokens
http_put_response_hop_limit = each.value.metadata_hop_limit
}
root_block_device {
volume_size = each.value.root_volume.size
volume_type = each.value.root_volume.type
encrypted = true
kms_key_id = each.value.root_volume.kms_key_id
delete_on_termination = each.value.root_volume.delete_on_termination
tags = merge(var.tags, each.value.instance_tags, each.value.root_volume.tags, local.module_tags, {
Name = "${local.instance_names[each.key]}-root-vol"
resource-type = "ebs-volume"
})
}
tags = merge(var.tags, each.value.instance_tags, local.module_tags, {
Name = local.instance_names[each.key]
resource-type = "ec2-instance"
})
lifecycle {
ignore_changes = [
user_data,
user_data_base64,
]
postcondition {
condition = self.instance_state == "running"
error_message = "Instance ${self.tags.Name} did not reach running state after apply."
}
postcondition {
condition = self.primary_network_interface_id != null
error_message = "Instance ${self.tags.Name} has no primary network interface — check subnet and security group config."
}
postcondition {
condition = length(each.value.secondary_private_ips) == 0 || alltrue([
for ip in each.value.secondary_private_ips : contains(self.secondary_private_ips, ip)
])
error_message = "Instance ${self.tags.Name} did not receive all requested secondary private IPs."
}
postcondition {
condition = self.metadata_options[0].http_tokens == "required"
error_message = "Instance ${self.tags.Name} is not enforcing IMDSv2. metadata_http_tokens must be 'required'."
}
}
}
# Data volumes -----------------------------------------------------------------
resource "aws_ebs_volume" "data" {
for_each = local.data_volume_map
availability_zone = aws_instance.this[each.value.instance_key].availability_zone
size = each.value.vol.volume_size
type = each.value.vol.volume_type
encrypted = true
kms_key_id = each.value.vol.kms_key_id
iops = each.value.vol.iops
throughput = each.value.vol.throughput
tags = merge(var.tags, each.value.vol.tags, local.module_tags, {
Name = "${local.instance_names[each.value.instance_key]}-data-vol-${format("%02d", each.value.idx + 1)}"
resource-type = "ebs-volume"
})
}
resource "aws_volume_attachment" "data" {
for_each = local.data_volume_map
device_name = each.value.vol.device_name
volume_id = aws_ebs_volume.data[each.key].id
instance_id = aws_instance.this[each.value.instance_key].id
}
|