-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathmain.tf
357 lines (301 loc) · 15.6 KB
/
main.tf
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
##############################################################################
# terraform-ibm-landing-zone-vpc
##############################################################################
locals {
# input variable validation
# tflint-ignore: terraform_unused_declarations
validate_default_secgroup_rules = var.clean_default_sg_acl && (var.security_group_rules != null && length(var.security_group_rules) > 0) ? tobool("var.clean_default_sg_acl is true and var.security_group_rules are not empty, which are in direct conflict of each other. If you would like the default VPC Security Group to be empty, you must remove default rules from var.security_group_rules.") : true
# tflint-ignore: terraform_unused_declarations
validate_existing_vpc_id = !var.create_vpc && var.existing_vpc_id == null ? tobool("If var.create_vpc is false, then provide a value for var.existing_vpc_id to create vpc.") : true
# tflint-ignore: terraform_unused_declarations
validate_existing_subnet_id = !var.create_subnets && length(var.existing_subnets) == 0 ? tobool("If var.create_subnet is false, then provide a value for var.existing_subnets to create subnets.") : true
# tflint-ignore: terraform_unused_declarations
validate_existing_vpc_and_subnet = var.create_vpc == true && var.create_subnets == false ? tobool("If user is not providing a vpc then they should also not be providing a subnet") : true
# tflint-ignore: terraform_unused_declarations
validate_hub_vpc_input = (var.hub_vpc_id != null && var.hub_vpc_crn != null) ? tobool("var.hub_vpc_id and var.hub_vpc_crn are mutually exclusive. Hence cannot have values at the same time.") : true
# tflint-ignore: terraform_unused_declarations
validate_hub_vpc_id_input = (var.enable_hub_vpc_id && var.hub_vpc_id == null) ? tobool("var.hub_vpc_id must be passed when var.enable_hub_vpc_id is True.") : true
# tflint-ignore: terraform_unused_declarations
validate_enable_hub_vpc_id_input = (!var.enable_hub_vpc_id && var.hub_vpc_id != null) ? tobool("var.enable_hub_vpc_id must be true when var.hub_vpc_id is not null.") : true
# tflint-ignore: terraform_unused_declarations
validate_hub_vpc_crn_input = (var.enable_hub_vpc_crn && var.hub_vpc_crn == null) ? tobool("var.hub_vpc_crn must be passed when var.enable_hub_vpc_crn is True.") : true
# tflint-ignore: terraform_unused_declarations
validate_enable_hub_vpc_crn_input = (!var.enable_hub_vpc_crn && var.hub_vpc_crn != null) ? tobool("var.enable_hub_vpc_crn must be true when var.hub_vpc_crn is not null.") : true
# tflint-ignore: terraform_unused_declarations
validate_manual_servers_input = (var.resolver_type == "manual" && length(var.manual_servers) == 0) ? tobool("var.manual_servers must be set when var.resolver_type is manual") : true
# tflint-ignore: terraform_unused_declarations
validate_resolver_type_input = (var.resolver_type != null && var.update_delegated_resolver == true) ? tobool("var.resolver_type cannot be set if var.update_delegated_resolver is set to true. Only one type of resolver can be created by VPC.") : true
# tflint-ignore: terraform_unused_declarations
validate_vpc_flow_logs_inputs = (var.enable_vpc_flow_logs) ? ((var.create_authorization_policy_vpc_to_cos) ? ((var.existing_cos_instance_guid != null && var.existing_storage_bucket_name != null) ? true : tobool("Please provide COS instance & bucket name to create flow logs collector.")) : ((var.existing_storage_bucket_name != null) ? true : tobool("Please provide COS bucket name to create flow logs collector"))) : false
# tflint-ignore: terraform_unused_declarations
validate_skip_spoke_auth_policy_input = (var.hub_account_id == null && !var.skip_spoke_auth_policy && !var.enable_hub && (var.enable_hub_vpc_id || var.enable_hub_vpc_crn)) ? tobool("var.hub_account_id must be set when var.skip_spoke_auth_policy is False and either var.enable_hub_vpc_id or var.enable_hub_vpc_crn is true.") : true
}
##############################################################################
# Check if existing vpc id is passed
##############################################################################
data "ibm_is_vpc" "vpc" {
depends_on = [time_sleep.wait_for_vpc_creation_data]
identifier = local.vpc_id
}
locals {
vpc_id = var.create_vpc ? resource.ibm_is_vpc.vpc[0].id : var.existing_vpc_id
vpc_name = var.create_vpc ? resource.ibm_is_vpc.vpc[0].name : data.ibm_is_vpc.vpc.name
vpc_crn = var.create_vpc ? resource.ibm_is_vpc.vpc[0].crn : data.ibm_is_vpc.vpc.crn
}
##############################################################################
# Create new VPC
##############################################################################
resource "time_sleep" "wait_for_vpc_creation_data" {
depends_on = [resource.ibm_is_vpc.vpc, resource.ibm_is_subnet.subnet]
count = var.create_vpc == true || var.create_subnets ? 1 : 0
create_duration = "30s"
}
resource "ibm_is_vpc" "vpc" {
count = var.create_vpc == true ? 1 : 0
name = var.prefix != null ? "${var.prefix}-${var.name}-vpc" : var.name
resource_group = var.resource_group_id
# address prefix is set to auto only if no address prefixes NOR any subnet is passed as input
address_prefix_management = (length([for prefix in values(coalesce(var.address_prefixes, {})) : prefix if prefix != null]) != 0) || (length([for subnet in values(coalesce(var.subnets, {})) : subnet if subnet != null]) != 0) ? "manual" : null
default_network_acl_name = var.default_network_acl_name
default_security_group_name = var.default_security_group_name
default_routing_table_name = var.default_routing_table_name
tags = var.tags
access_tags = var.access_tags
no_sg_acl_rules = var.clean_default_sg_acl
dns {
enable_hub = var.enable_hub
# Delegated resolver
dynamic "resolver" {
for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver ? [1] : []
content {
type = "delegated"
vpc_id = var.hub_vpc_id != null ? var.hub_vpc_id : null
vpc_crn = var.hub_vpc_crn != null ? var.hub_vpc_crn : null
}
}
# Manual resolver
dynamic "resolver" {
for_each = var.resolver_type == "manual" && !var.update_delegated_resolver ? [1] : []
content {
type = var.resolver_type
dynamic "manual_servers" {
for_each = length(var.manual_servers) > 0 ? var.manual_servers : []
content {
address = manual_servers.value.address
zone_affinity = manual_servers.value.zone_affinity
}
}
}
}
# System resolver
dynamic "resolver" {
for_each = var.resolver_type == "system" && !var.update_delegated_resolver ? [1] : []
content {
type = var.resolver_type
}
}
}
}
###############################################################################
##############################################################################
# Hub and Spoke specific configuration
# See https://cloud.ibm.com/docs/vpc?topic=vpc-hub-spoke-model for context
##############################################################################
# fetch this account ID
data "ibm_iam_account_settings" "iam_account_settings" {}
# spoke -> hub auth policy based on https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-dns-sharing-s2s-auth&interface=terraform
resource "ibm_iam_authorization_policy" "vpc_dns_resolution_auth_policy" {
count = (var.enable_hub == false && var.skip_spoke_auth_policy == false && (var.enable_hub_vpc_id || var.enable_hub_vpc_crn)) ? 1 : 0
roles = ["DNS Binding Connector"]
# subject is the spoke
subject_attributes {
name = "accountId"
value = data.ibm_iam_account_settings.iam_account_settings.account_id
}
subject_attributes {
name = "serviceName"
value = "is"
}
subject_attributes {
name = "resourceType"
value = "vpc"
}
subject_attributes {
name = "resource"
value = local.vpc_id
}
# resource is the hub
resource_attributes {
name = "accountId"
value = var.hub_account_id
}
resource_attributes {
name = "serviceName"
value = "is"
}
resource_attributes {
name = "vpcId"
value = var.enable_hub_vpc_id ? var.hub_vpc_id : split(":", var.hub_vpc_crn)[9]
}
}
# Enable Hub to dns resolve in spoke VPC
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
count = (var.enable_hub == false && var.enable_hub_vpc_id) ? 1 : 0
# Depends on required as the authorization policy cannot be directly referenced
depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy]
# Use var.dns_binding_name if not null, otherwise, use var.prefix and var.name combination.
name = coalesce(
var.dns_binding_name,
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-dns-binding"
)
vpc_id = local.vpc_id # Source VPC
vpc {
id = var.hub_vpc_id # Target VPC ID
}
}
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_crn" {
count = (var.enable_hub == false && var.enable_hub_vpc_crn) ? 1 : 0
# Depends on required as the authorization policy cannot be directly referenced
depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy]
# Use var.dns_binding_name if not null, otherwise, use var.prefix and var.name combination.
name = coalesce(
var.dns_binding_name,
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-dns-binding"
)
vpc_id = local.vpc_id # Source VPC
vpc {
crn = var.hub_vpc_crn # Target VPC CRN
}
}
# Configure custom resolver on the hub vpc
resource "ibm_resource_instance" "dns_instance_hub" {
count = var.enable_hub && !var.skip_custom_resolver_hub_creation && !var.use_existing_dns_instance ? 1 : 0
# Use var.dns_instance_name if not null, otherwise, use var.prefix and var.name combination.
name = coalesce(
var.dns_instance_name,
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-dns-instance"
)
resource_group_id = var.resource_group_id
location = var.dns_location
service = "dns-svcs"
plan = var.dns_plan
}
resource "ibm_dns_custom_resolver" "custom_resolver_hub" {
count = var.enable_hub && !var.skip_custom_resolver_hub_creation ? 1 : 0
# Use var.dns_custom_resolver_name if not null, otherwise, use var.prefix and var.name combination.
name = coalesce(
var.dns_custom_resolver_name,
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-custom-resolver"
)
instance_id = var.use_existing_dns_instance ? var.existing_dns_instance_id : ibm_resource_instance.dns_instance_hub[0].guid
high_availability = true
enabled = true
dynamic "locations" {
for_each = local.subnets
content {
subnet_crn = locations.value.crn
enabled = true
}
}
}
##############################################################################
##############################################################################
# Address Prefixes
##############################################################################
locals {
# For each address prefix
address_prefixes = {
for prefix in module.dynamic_values.address_prefixes :
(prefix.name) => prefix
}
}
resource "ibm_is_vpc_address_prefix" "address_prefixes" {
for_each = local.address_prefixes
name = each.value.name
vpc = local.vpc_id
zone = each.value.zone
cidr = each.value.cidr
}
data "ibm_is_vpc_address_prefixes" "get_address_prefixes" {
depends_on = [ibm_is_vpc_address_prefix.address_prefixes, ibm_is_vpc_address_prefix.subnet_prefix]
vpc = local.vpc_id
}
##############################################################################
# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
resource "time_sleep" "wait_for_authorization_policy" {
depends_on = [ibm_iam_authorization_policy.policy]
count = (var.enable_vpc_flow_logs) ? ((var.create_authorization_policy_vpc_to_cos) ? 1 : 0) : 0
create_duration = "30s"
}
##############################################################################
# Create vpc route resource
##############################################################################
resource "ibm_is_vpc_routing_table" "route_table" {
for_each = module.dynamic_values.routing_table_map
# Use var.routing_table_name if not null, otherwise, use var.prefix and var.name combination.
name = var.routing_table_name != null ? "${var.routing_table_name}-${each.value.name}" : var.prefix != null ? "${var.prefix}-${var.name}-route-${each.value.name}" : "${var.name}-route-${each.value.name}"
vpc = local.vpc_id
route_direct_link_ingress = each.value.route_direct_link_ingress
route_transit_gateway_ingress = each.value.route_transit_gateway_ingress
route_vpc_zone_ingress = each.value.route_vpc_zone_ingress
}
resource "ibm_is_vpc_routing_table_route" "routing_table_routes" {
for_each = module.dynamic_values.routing_table_route_map
vpc = local.vpc_id
routing_table = ibm_is_vpc_routing_table.route_table[each.value.route_table].routing_table
zone = "${var.region}-${each.value.zone}"
name = each.key
destination = each.value.destination
action = each.value.action
next_hop = each.value.next_hop
}
##############################################################################
##############################################################################
# Public Gateways (Optional)
##############################################################################
locals {
# create object that only contains gateways that will be created
gateway_object = {
for zone in keys(var.use_public_gateways) :
zone => "${var.region}-${index(keys(var.use_public_gateways), zone) + 1}" if var.use_public_gateways[zone]
}
}
resource "ibm_is_public_gateway" "gateway" {
for_each = local.gateway_object
# Use var.public_gateway_name if not null, otherwise, use var.prefix and var.name combination.
name = var.public_gateway_name != null ? "${var.public_gateway_name}-${each.key}" : var.prefix != null ? "${var.prefix}-${var.name}-public-gateway-${each.key}" : "${var.name}-public-gateway-${each.key}"
vpc = local.vpc_id
resource_group = var.resource_group_id
zone = each.value
tags = var.tags
access_tags = var.access_tags
}
##############################################################################
##############################################################################
# Add VPC to Flow Logs
##############################################################################
# Create authorization policy to allow VPC to access COS instance
resource "ibm_iam_authorization_policy" "policy" {
count = (var.enable_vpc_flow_logs) ? ((var.create_authorization_policy_vpc_to_cos) ? 1 : 0) : 0
source_service_name = "is"
source_resource_type = "flow-log-collector"
target_service_name = "cloud-object-storage"
target_resource_instance_id = var.existing_cos_instance_guid
roles = ["Writer"]
}
# Create VPC flow logs collector
resource "ibm_is_flow_log" "flow_logs" {
count = (var.enable_vpc_flow_logs) ? 1 : 0
# Use var.vpc_flow_logs_name if not null, otherwise, use var.prefix and var.name combination.
name = coalesce(
var.vpc_flow_logs_name,
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-logs"
)
target = local.vpc_id
active = var.is_flow_log_collector_active
storage_bucket = var.existing_storage_bucket_name
resource_group = var.resource_group_id
tags = var.tags
access_tags = var.access_tags
}
##############################################################################