-
Notifications
You must be signed in to change notification settings - Fork 28
/
infra.ci.jenkins.io.tf
414 lines (385 loc) · 20.9 KB
/
infra.ci.jenkins.io.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
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
/** One resource group for the agents **/
resource "azurerm_resource_group" "infra_ci_jenkins_io_agents" {
name = "infra-agents"
location = var.location
}
/** Agent Resources **/
resource "azurerm_storage_account" "infra_ci_jenkins_io_agents" {
name = "infraciagents"
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_agents.name
location = azurerm_resource_group.infra_ci_jenkins_io_agents.location
account_tier = "Standard"
account_replication_type = "LRS"
min_tls_version = "TLS1_2" # default value, needed for tfsec
tags = local.default_tags
}
# Azure AD resources to allow controller to spawn agents in Azure
resource "azuread_application" "infra_ci_jenkins_io" {
display_name = "infra.ci.jenkins.io"
owners = [
data.azuread_service_principal.terraform_production.object_id,
]
tags = [for key, value in local.default_tags : "${key}:${value}"]
required_resource_access {
resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
resource_access {
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # User.Read
type = "Scope"
}
}
web {
homepage_url = "https://github.com/jenkins-infra/azure"
}
}
resource "azuread_service_principal" "infra_ci_jenkins_io" {
client_id = azuread_application.infra_ci_jenkins_io.client_id
app_role_assignment_required = false
owners = [
data.azuread_service_principal.terraform_production.object_id,
]
}
resource "azuread_application_password" "infra_ci_jenkins_io" {
application_id = azuread_application.infra_ci_jenkins_io.id
display_name = "infra.ci.jenkins.io-tf-managed"
end_date = "2024-12-18T00:00:00Z"
}
# Allow Service Principal to manage AzureRM resources inside the agents resource groups
resource "azurerm_role_assignment" "infra_ci_jenkins_io_allow_azurerm" {
scope = azurerm_resource_group.infra_ci_jenkins_io_agents.id
role_definition_name = "Contributor"
principal_id = azuread_service_principal.infra_ci_jenkins_io.object_id
}
resource "azurerm_role_assignment" "infra_ci_jenkins_io_allow_packer" {
scope = azurerm_resource_group.packer_images["prod"].id
role_definition_name = "Reader"
principal_id = azuread_service_principal.infra_ci_jenkins_io.object_id
}
resource "azurerm_role_assignment" "infra_ci_jenkins_io_privatek8s_subnet_role" {
scope = data.azurerm_subnet.privatek8s_tier.id
role_definition_name = "Virtual Machine Contributor"
principal_id = azuread_service_principal.infra_ci_jenkins_io.object_id
}
resource "azurerm_role_assignment" "infra_ci_jenkins_io_privatek8s_subnet_private_vnet_reader" {
scope = data.azurerm_virtual_network.private.id
role_definition_id = azurerm_role_definition.private_vnet_reader.role_definition_resource_id
principal_id = azuread_service_principal.infra_ci_jenkins_io.object_id
}
# Required to allow azcopy sync of contributors.jenkins.io File Share
module "infraci_contributorsjenkinsio_fileshare_serviceprincipal_writer" {
source = "./.shared-tools/terraform/modules/azure-jenkinsinfra-fileshare-serviceprincipal-writer"
service_fqdn = "infra-ci-jenkins-io-fileshare_serviceprincipal_writer"
active_directory_owners = [data.azuread_service_principal.terraform_production.object_id]
active_directory_url = "https://github.com/jenkins-infra/azure"
service_principal_end_date = local.end_dates.infra_ci_jenkins_io.infraci_contributorsjenkinsio_fileshare_serviceprincipal_writer.end_date
file_share_resource_manager_id = azurerm_storage_share.contributors_jenkins_io.resource_manager_id
storage_account_id = azurerm_storage_account.contributors_jenkins_io.id
default_tags = local.default_tags
}
output "infraci_contributorsjenkinsio_fileshare_serviceprincipal_writer_application_client_id" {
value = module.infraci_contributorsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_id
}
output "infraci_contributorsjenkinsio_fileshare_serviceprincipal_writer_application_client_password" {
sensitive = true
value = module.infraci_contributorsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_password
}
# Required to allow azcopy sync of docs.jenkins.io File Share
module "infraci_docsjenkinsio_fileshare_serviceprincipal_writer" {
source = "./.shared-tools/terraform/modules/azure-jenkinsinfra-fileshare-serviceprincipal-writer"
service_fqdn = "infra-ci-jenkins-io-fileshare_serviceprincipal_writer"
active_directory_owners = [data.azuread_service_principal.terraform_production.object_id]
active_directory_url = "https://github.com/jenkins-infra/azure"
service_principal_end_date = local.end_dates.infra_ci_jenkins_io.infraci_docsjenkinsio_fileshare_serviceprincipal_writer.end_date
file_share_resource_manager_id = azurerm_storage_share.docs_jenkins_io.resource_manager_id
storage_account_id = azurerm_storage_account.docs_jenkins_io.id
default_tags = local.default_tags
}
output "infraci_docsjenkinsio_fileshare_serviceprincipal_writer_application_client_id" {
value = module.infraci_docsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_id
}
output "infraci_docsjenkinsio_fileshare_serviceprincipal_writer_application_client_password" {
sensitive = true
value = module.infraci_docsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_password
}
# Required to allow azcopy sync of stats.jenkins.io File Share
module "infraci_statsjenkinsio_fileshare_serviceprincipal_writer" {
source = "./.shared-tools/terraform/modules/azure-jenkinsinfra-fileshare-serviceprincipal-writer"
service_fqdn = "infra-ci-jenkins-io-fileshare_serviceprincipal_writer"
active_directory_owners = [data.azuread_service_principal.terraform_production.object_id]
active_directory_url = "https://github.com/jenkins-infra/azure"
service_principal_end_date = local.end_dates.infra_ci_jenkins_io.infraci_statsjenkinsio_fileshare_serviceprincipal_writer.end_date
file_share_resource_manager_id = azurerm_storage_share.stats_jenkins_io.resource_manager_id
storage_account_id = azurerm_storage_account.stats_jenkins_io.id
default_tags = local.default_tags
}
output "infraci_statsjenkinsio_fileshare_serviceprincipal_writer_application_client_id" {
value = module.infraci_statsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_id
}
output "infraci_statsjenkinsio_fileshare_serviceprincipal_writer_application_client_password" {
sensitive = true
value = module.infraci_statsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_password
}
locals {
infra_ci_jenkins_io_fqdn = "infra.ci.jenkins.io"
infra_ci_jenkins_io_service_short_name = trimprefix(trimprefix(local.infra_ci_jenkins_io_fqdn, "jenkins.io"), ".")
infra_ci_jenkins_io_service_short_stripped_name = replace(local.infra_ci_jenkins_io_service_short_name, ".", "-")
}
####################################################################################
## Sponsorship subscription specific resources for controller
####################################################################################
# This resource group hosts resources used for agents only managed by terraform or administrators
# such as NSG for agents subnet (we don't want azure-vm-agents jenkins plugin to access this RG)
resource "azurerm_resource_group" "infra_ci_jenkins_io_controller_jenkins_sponsorship" {
provider = azurerm.jenkins-sponsorship
name = "infra-ci-jenkins-io-controller"
location = var.location
tags = local.default_tags
}
# Required to allow controller to check for subnets inside the sponsorship network
resource "azurerm_role_definition" "infra_ci_jenkins_io_controller_vnet_sponsorship_reader" {
provider = azurerm.jenkins-sponsorship
name = "Read-infra-ci-jenkins-io-sponsorship-VNET"
scope = data.azurerm_virtual_network.infra_ci_jenkins_io_sponsorship.id
permissions {
actions = ["Microsoft.Network/virtualNetworks/read"]
}
}
resource "azurerm_role_assignment" "infra_controller_vnet_reader" {
provider = azurerm.jenkins-sponsorship
scope = data.azurerm_virtual_network.infra_ci_jenkins_io_sponsorship.id
role_definition_id = azurerm_role_definition.infra_ci_jenkins_io_controller_vnet_sponsorship_reader.role_definition_resource_id
principal_id = azuread_service_principal.infra_ci_jenkins_io.object_id
}
module "infra_ci_jenkins_io_azurevm_agents_jenkins_sponsorship" {
providers = {
azurerm = azurerm.jenkins-sponsorship
}
source = "./.shared-tools/terraform/modules/azure-jenkinsinfra-azurevm-agents"
service_fqdn = local.infra_ci_jenkins_io_fqdn
service_short_stripped_name = local.infra_ci_jenkins_io_service_short_stripped_name
ephemeral_agents_network_rg_name = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.resource_group_name
ephemeral_agents_network_name = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.virtual_network_name
ephemeral_agents_subnet_name = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.name
controller_rg_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins_sponsorship.name
controller_ips = data.azurerm_subnet.privatek8s_infra_ci_controller_tier.address_prefixes # Pod IPs: controller IP may change in the pods IP subnet
controller_service_principal_id = azuread_service_principal.infra_ci_jenkins_io.object_id
default_tags = local.default_tags
storage_account_name = "infraciagentssub" # Max 24 chars
jenkins_infra_ips = {
privatevpn_subnet = data.azurerm_subnet.private_vnet_data_tier.address_prefixes
}
}
# Allow infra.ci VM agents to reach packer VMs with SSH
resource "azurerm_network_security_rule" "allow_outbound_ssh_from_infraci_agents_to_packer_vms" {
provider = azurerm.jenkins-sponsorship
name = "allow-outbound-ssh-from-infraci-agents-to-packer-vms"
priority = 4080
direction = "Outbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.address_prefix
destination_address_prefix = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_packer_builds.address_prefix
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins_sponsorship.name
network_security_group_name = module.infra_ci_jenkins_io_azurevm_agents_jenkins_sponsorship.ephemeral_agents_nsg_name
}
# Allow infra.ci VM agents to reach packer VMs with WinRM (HTTP without TLS)
resource "azurerm_network_security_rule" "allow_outbound_winrm_http_from_infraci_agents_to_packer_vms" {
provider = azurerm.jenkins-sponsorship
name = "allow-outbound-winrm-http-from-infraci-agents-to-packer-vms"
priority = 4081
direction = "Outbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5985"
source_address_prefix = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.address_prefix
destination_address_prefix = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_packer_builds.address_prefix
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins_sponsorship.name
network_security_group_name = module.infra_ci_jenkins_io_azurevm_agents_jenkins_sponsorship.ephemeral_agents_nsg_name
}
# Allow infra.ci VM agents to reach packer VMs with WinRM (HTTPS)
resource "azurerm_network_security_rule" "allow_outbound_winrm_https_from_infraci_agents_to_packer_vms" {
provider = azurerm.jenkins-sponsorship
name = "allow-outbound-winrm-https-from-infraci-agents-to-packer-vms"
priority = 4082
direction = "Outbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5986"
source_address_prefix = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.address_prefix
destination_address_prefix = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_packer_builds.address_prefix
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins_sponsorship.name
network_security_group_name = module.infra_ci_jenkins_io_azurevm_agents_jenkins_sponsorship.ephemeral_agents_nsg_name
}
# Required to allow azcopy sync of plugins.jenkins.io File Share
module "infraci_pluginsjenkinsio_fileshare_serviceprincipal_writer" {
source = "./.shared-tools/terraform/modules/azure-jenkinsinfra-fileshare-serviceprincipal-writer"
service_fqdn = "infraci-pluginsjenkinsio-fileshare_serviceprincipal_writer"
active_directory_owners = [data.azuread_service_principal.terraform_production.object_id]
active_directory_url = "https://github.com/jenkins-infra/azure"
service_principal_end_date = local.end_dates.infra_ci_jenkins_io.infraci_pluginsjenkinsio_fileshare_serviceprincipal_writer.end_date
file_share_resource_manager_id = azurerm_storage_share.plugins_jenkins_io.resource_manager_id
storage_account_id = azurerm_storage_account.plugins_jenkins_io.id
default_tags = local.default_tags
}
output "infraci_pluginsjenkinsio_fileshare_serviceprincipal_writer_application_client_id" {
value = module.infraci_pluginsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_id
}
output "infraci_pluginsjenkinsio_fileshare_serviceprincipal_writer_application_client_password" {
sensitive = true
value = module.infraci_pluginsjenkinsio_fileshare_serviceprincipal_writer.fileshare_serviceprincipal_writer_application_client_password
}
# This resource group hosts resources used by the controller on the main subscription
resource "azurerm_resource_group" "infra_ci_jenkins_io_controller_jenkins" {
name = "infra-ci-jenkins-io-controller"
location = var.location
tags = local.default_tags
}
resource "azurerm_managed_disk" "jenkins_infra_data" {
name = "jenkins-infra-data"
location = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins.location
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins.name
storage_account_type = "StandardSSD_ZRS"
create_option = "Empty"
disk_size_gb = 64
tags = local.default_tags
}
resource "kubernetes_persistent_volume" "jenkins_infra_data" {
provider = kubernetes.privatek8s
metadata {
name = "jenkins-infra-pv"
}
spec {
capacity = {
storage = "${azurerm_managed_disk.jenkins_infra_data.disk_size_gb}Gi"
}
access_modes = ["ReadWriteOnce"]
persistent_volume_reclaim_policy = "Retain"
storage_class_name = kubernetes_storage_class.statically_provisionned_privatek8s.id
persistent_volume_source {
csi {
driver = "disk.csi.azure.com"
volume_handle = azurerm_managed_disk.jenkins_infra_data.id
}
}
}
}
resource "kubernetes_persistent_volume_claim" "jenkins_infra_data" {
provider = kubernetes.privatek8s
metadata {
name = "jenkins-infra-data"
namespace = "jenkins-infra"
}
spec {
access_modes = kubernetes_persistent_volume.jenkins_infra_data.spec[0].access_modes
volume_name = kubernetes_persistent_volume.jenkins_infra_data.metadata.0.name
storage_class_name = kubernetes_storage_class.statically_provisionned_privatek8s.id
resources {
requests = {
storage = "${azurerm_managed_disk.jenkins_infra_data.disk_size_gb}Gi"
}
}
}
}
# Required to allow AKS CSI driver to access the Azure disk
resource "azurerm_role_definition" "infra_ci_jenkins_io_controller_disk_reader" {
name = "ReadinfraCIDisk"
scope = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins.id
permissions {
actions = ["Microsoft.Compute/disks/read"]
}
}
resource "azurerm_role_assignment" "infra_ci_jenkins_io_allow_azurerm_privatek8s" {
scope = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins.id
role_definition_id = azurerm_role_definition.infra_ci_jenkins_io_controller_disk_reader.role_definition_resource_id
principal_id = azurerm_kubernetes_cluster.privatek8s.identity[0].principal_id
}
## Allow access to/from ACR endpoint
resource "azurerm_network_security_rule" "allow_out_https_from_infra_ephemeral_agents_to_acr" {
provider = azurerm.jenkins-sponsorship
name = "allow-out-https-from-ephemeral-agents-to-acr"
priority = 4050
direction = "Outbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefixes = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.address_prefixes
destination_address_prefixes = distinct(
flatten(
[for rs in azurerm_private_endpoint.dockerhub_mirror["infracijenkinsio"].private_dns_zone_configs.*.record_sets : rs.*.ip_addresses]
)
)
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins_sponsorship.name
network_security_group_name = module.infra_ci_jenkins_io_azurevm_agents_jenkins_sponsorship.ephemeral_agents_nsg_name
}
resource "azurerm_network_security_rule" "allow_in_https_from_infra_ephemeral_agents_to_acr" {
provider = azurerm.jenkins-sponsorship
name = "allow-in-https-from-ephemeral-agents-to-acr"
priority = 4050
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefixes = data.azurerm_subnet.infra_ci_jenkins_io_sponsorship_ephemeral_agents.address_prefixes
destination_address_prefixes = distinct(
flatten(
[for rs in azurerm_private_endpoint.dockerhub_mirror["infracijenkinsio"].private_dns_zone_configs.*.record_sets : rs.*.ip_addresses]
)
)
resource_group_name = azurerm_resource_group.infra_ci_jenkins_io_controller_jenkins_sponsorship.name
network_security_group_name = module.infra_ci_jenkins_io_azurevm_agents_jenkins_sponsorship.ephemeral_agents_nsg_name
}
# Azure SP for updatecli with minimum rights
resource "azurerm_resource_group" "updatecli_infra_ci_jenkins_io" {
name = "updatecli-infra-ci-jenkins-io"
location = var.location
}
resource "azuread_application" "updatecli_infra_ci_jenkins_io" {
display_name = "updatecli_infra.ci.jenkins.io"
owners = [
# Commenting out to migrate to new AzureAD provider
# data.azuread_service_principal.terraform_production.id,
"b847a030-25e1-4791-ad04-9e8484d87bce",
]
tags = [for key, value in local.default_tags : "${key}:${value}"]
required_resource_access {
resource_app_id = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
resource_access {
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # User.Read
type = "Scope"
}
}
web {
homepage_url = "https://infra.ci.jenkins.io/job/updatecli/"
}
}
resource "azuread_service_principal" "updatecli_infra_ci_jenkins_io" {
client_id = azuread_application.updatecli_infra_ci_jenkins_io.client_id
app_role_assignment_required = false
owners = [
# Commenting out to migrate to new AzureAD provider
# data.azuread_service_principal.terraform_production.id,
"b847a030-25e1-4791-ad04-9e8484d87bce",
]
}
resource "azuread_application_password" "updatecli_infra_ci_jenkins_io" {
application_id = azuread_application.updatecli_infra_ci_jenkins_io.id
display_name = "updatecli_infra.ci.jenkins.io-tf-managed"
end_date = "2025-01-18T00:00:00Z"
}
resource "azurerm_role_definition" "vm_images_reader" {
name = "ReadVMImages"
scope = azurerm_resource_group.updatecli_infra_ci_jenkins_io.id
permissions {
actions = ["Microsoft.Compute/images/read"]
}
}
resource "azurerm_role_assignment" "updatecli_infra_ci_jenkins_io_allow_images_list" {
scope = azurerm_resource_group.updatecli_infra_ci_jenkins_io.id
role_definition_id = azurerm_role_definition.vm_images_reader.role_definition_resource_id
principal_id = azuread_service_principal.updatecli_infra_ci_jenkins_io.object_id
}