keycloak.tf 27.6 KB
Newer Older
1
2
3
4
5
6
terraform {
  backend "pg" {
    schema_name = "terraform_remote_state_stage2"
  }
}

7
data "external" "vault_keycloak" {
8
  program = ["${path.module}/../misc/get_key.py", "${path.module}/../group_vars/all/vault_keycloak.yml",
9
10
11
12
    "vault_keycloak_admin_user",
    "vault_keycloak_admin_password",
    "vault_keycloak_smtp_user",
    "vault_keycloak_smtp_password",
Jelle van der Waa's avatar
Jelle van der Waa committed
13
    "vault_keycloak_gluebuddy_openid_client_secret",
14
  "--format", "json"]
15
16
}

17
data "external" "vault_google" {
18
  program = ["${path.module}/../misc/get_key.py", "${path.module}/../group_vars/all/vault_google.yml",
19
20
    "vault_google_recaptcha_site_key",
    "vault_google_recaptcha_secret_key",
21
  "--format", "json"]
22
23
}

24
data "external" "vault_github" {
25
  program = ["${path.module}/../misc/get_key.py", "${path.module}/../group_vars/all/vault_github.yml",
26
27
    "vault_github_oauth_app_client_id",
    "vault_github_oauth_app_client_secret",
28
  "--format", "json"]
29
30
}

Jelle van der Waa's avatar
Jelle van der Waa committed
31
data "external" "vault_monitoring" {
32
  program = ["${path.module}/../misc/get_key.py", "${path.module}/../group_vars/all/vault_monitoring.yml",
Jelle van der Waa's avatar
Jelle van der Waa committed
33
    "vault_monitoring_grafana_client_secret",
34
  "--format", "json"]
Jelle van der Waa's avatar
Jelle van der Waa committed
35
36
}

37
data "external" "vault_hedgedoc" {
38
  program = ["${path.module}/../misc/get_key.py", "${path.module}/../group_vars/all/vault_hedgedoc.yml",
39
40
41
42
    "vault_hedgedoc_client_secret",
  "--format", "json"]
}

43
data "external" "vault_matrix" {
44
  program = ["${path.module}/../misc/get_key.py", "${path.module}/../group_vars/all/vault_matrix.yml",
45
46
47
48
    "vault_matrix_openid_client_secret",
  "--format", "json"]
}

49
50
provider "keycloak" {
  client_id = "admin-cli"
51
52
53
  username  = data.external.vault_keycloak.result.vault_keycloak_admin_user
  password  = data.external.vault_keycloak.result.vault_keycloak_admin_password
  url       = "https://accounts.archlinux.org"
54
55
56
57
}

variable "gitlab_instance" {
  default = {
58
    root_url          = "https://gitlab.archlinux.org"
59
60
61
62
    saml_redirect_url = "https://gitlab.archlinux.org/users/auth/saml/callback"
  }
}

63
resource "keycloak_realm" "archlinux" {
64
65
66
67
  realm             = "archlinux"
  enabled           = true
  remember_me       = true
  display_name      = "Arch Linux"
68
  display_name_html = "<div class=\"kc-logo-text\"><span>Arch Linux</span></div>"
69

70
  registration_allowed     = true
71
72
  reset_password_allowed   = true
  verify_email             = true
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
73
  login_with_email_allowed = true
74
  password_policy          = "length(8) and notUsername"
75
76
77
78

  web_authn_policy {
    relying_party_entity_name = "Arch Linux SSO"
    relying_party_id          = "accounts.archlinux.org"
79
    signature_algorithms      = ["ES256", "RS256", "ES512", "RS512"]
80
  }
81

82
  login_theme   = "archlinux"
83
  account_theme = "archlinux"
84
  admin_theme   = "archlinux"
85

86
87
  browser_flow           = "Arch Browser"
  registration_flow      = "Arch Registration"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
88
  reset_credentials_flow = "Arch Reset Credentials"
89

90
  smtp_server {
91
92
    host              = "mail.archlinux.org"
    from              = "accounts@archlinux.org"
93
    port              = "465"
94
    from_display_name = "Arch Linux Accounts"
95
96
    ssl               = true
    starttls          = false
97
98

    auth {
99
100
      username = data.external.vault_keycloak.result.vault_keycloak_smtp_user
      password = data.external.vault_keycloak.result.vault_keycloak_smtp_password
101
102
    }
  }
103
104

  security_defenses {
105
106
107
108
109
110
111
112
113
    headers {
      x_frame_options                     = "ALLOW-FROM https://www.google.com"
      content_security_policy             = "frame-src 'self' https://www.google.com; frame-ancestors 'self'; object-src 'none';"
      content_security_policy_report_only = ""
      x_content_type_options              = "nosniff"
      x_robots_tag                        = "none"
      x_xss_protection                    = "1; mode=block"
      strict_transport_security           = "max-age=31536000; includeSubDomains"
    }
114
    brute_force_detection {
115
116
117
118
119
120
121
      permanent_lockout                = false
      max_login_failures               = 30
      wait_increment_seconds           = 60
      quick_login_check_milli_seconds  = 1000
      minimum_quick_login_wait_seconds = 60
      max_failure_wait_seconds         = 900
      failure_reset_time_seconds       = 43200
122
123
    }
  }
124
125
}

126
127
128
129
130
131
132
133
resource "keycloak_required_action" "custom-terms-and-conditions" {
  realm_id       = "archlinux"
  alias          = "terms_and_conditions"
  default_action = true
  enabled        = true
  name           = "Terms and Conditions"
}

134
resource "keycloak_required_action" "configure_otp" {
135
136
137
138
139
  realm_id = "archlinux"
  alias    = "CONFIGURE_TOTP"
  enabled  = true
  name     = "Configure OTP"
  priority = 0
140
141
142
}

resource "keycloak_required_action" "update_password" {
143
144
145
146
147
  realm_id = "archlinux"
  alias    = "UPDATE_PASSWORD"
  enabled  = true
  name     = "Update Password"
  priority = 20
148
149
150
}

resource "keycloak_required_action" "update_profile" {
151
152
153
154
155
  realm_id = "archlinux"
  alias    = "UPDATE_PROFILE"
  enabled  = true
  name     = "Update Profile"
  priority = 30
156
157
158
}

resource "keycloak_required_action" "verify_email" {
159
160
161
162
163
  realm_id = "archlinux"
  alias    = "VERIFY_EMAIL"
  enabled  = true
  name     = "Verify Email"
  priority = 40
164
165
166
}

resource "keycloak_required_action" "update_user_locale" {
167
168
169
170
171
  realm_id = "archlinux"
  alias    = "update_user_locale"
  enabled  = true
  name     = "Update User Locale"
  priority = 50
172
173
174
}

resource "keycloak_required_action" "webauthn_register" {
175
176
177
178
179
  realm_id = "archlinux"
  alias    = "webauthn-register"
  enabled  = true
  name     = "Webauthn Register"
  priority = 60
180
}
Kristian Klausen's avatar
Kristian Klausen committed
181

182
183
184
resource "keycloak_realm_events" "realm_events" {
  realm_id = "archlinux"

185
186
  events_enabled    = true
  events_expiration = 7889238 # 3 months
187
188
189
190
191
192
193
194
195

  admin_events_enabled         = true
  admin_events_details_enabled = true

  # When omitted or left empty, keycloak will enable all event types
  enabled_event_types = [
  ]

  events_listeners = [
196
    "jboss-logging",    # keycloak enables the 'jboss-logging' event listener by default.
197
    "metrics-listener", # enable the prometheus exporter (keycloak-metrics-spi)
198
199
200
  ]
}

201
resource "keycloak_oidc_identity_provider" "realm_identity_provider" {
202
203
204
205
206
207
208
209
  realm                        = "archlinux"
  alias                        = "github"
  provider_id                  = "github"
  authorization_url            = "https://accounts.archlinux.org/auth/realms/archlinux/broker/github/endpoint"
  client_id                    = data.external.vault_github.result.vault_github_oauth_app_client_id
  client_secret                = data.external.vault_github.result.vault_github_oauth_app_client_secret
  token_url                    = ""
  default_scopes               = ""
210
  post_broker_login_flow_alias = keycloak_authentication_flow.arch_post_ipr_flow.alias
211
  enabled                      = true
212
213
214
  trust_email                  = false
  store_token                  = false
  backchannel_supported        = false
215
216
217
218
219
  extra_config = {
    syncMode = "IMPORT"
  }
}

220
resource "keycloak_saml_client" "saml_gitlab" {
221
  realm_id  = "archlinux"
222
223
  client_id = "saml_gitlab"

224
  name    = "Arch Linux Accounts"
225
226
  enabled = true

227
  signature_algorithm = "RSA_SHA256"
228
229
  sign_documents      = true
  sign_assertions     = true
230
231
232
233
234

  valid_redirect_uris = [
    var.gitlab_instance.saml_redirect_url
  ]

235
236
  root_url                   = var.gitlab_instance.root_url
  base_url                   = "/"
237
  master_saml_processing_url = var.gitlab_instance.saml_redirect_url
238
239
240
241
242
  idp_initiated_sso_url_name = "saml_gitlab"

  assertion_consumer_post_url = var.gitlab_instance.saml_redirect_url
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
243
244
245
// This client is only used for the return URL redirect hack!
// See roles/gitlab/tasks/main.yml
resource "keycloak_openid_client" "openid_gitlab" {
246
  realm_id  = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
247
248
  client_id = "openid_gitlab"

249
  name    = "Arch Linux Accounts"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
250
251
  enabled = true

252
  access_type           = "PUBLIC"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
253
  standard_flow_enabled = true
254
  full_scope_allowed    = false
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
255
256
257
258
259
  valid_redirect_uris = [
    "https://gitlab.archlinux.org"
  ]
}

260
resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_email" {
261
  realm_id  = "archlinux"
262
263
  client_id = keycloak_saml_client.saml_gitlab.id

264
265
266
267
  name                       = "email"
  user_property              = "Email"
  friendly_name              = "Email"
  saml_attribute_name        = "email"
268
269
270
271
  saml_attribute_name_format = "Basic"
}

resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_first_name" {
272
  realm_id  = "archlinux"
273
274
  client_id = keycloak_saml_client.saml_gitlab.id

275
276
277
278
  name                       = "first_name"
  user_property              = "FirstName"
  friendly_name              = "First Name"
  saml_attribute_name        = "first_name"
279
280
281
282
  saml_attribute_name_format = "Basic"
}

resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_last_name" {
283
  realm_id  = "archlinux"
284
285
  client_id = keycloak_saml_client.saml_gitlab.id

286
287
288
289
  name                       = "last_name"
  user_property              = "LastName"
  friendly_name              = "Last Name"
  saml_attribute_name        = "last_name"
290
291
292
293
  saml_attribute_name_format = "Basic"
}

resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_username" {
294
  realm_id  = "archlinux"
295
296
  client_id = keycloak_saml_client.saml_gitlab.id

297
298
299
300
  name                       = "username"
  user_property              = "Username"
  friendly_name              = "Username"
  saml_attribute_name        = "username"
301
302
303
  saml_attribute_name_format = "Basic"
}

304
305
306
307
308
309
// This is the super group in which we put the other Arch groups.
// We want to end up with this structure:
// Arch Linux Staff
// |- DevOps
// |- Developers
// |- Trusted Users
Jelle van der Waa's avatar
Jelle van der Waa committed
310
// |- Wiki
311
// |  |- Admins
312
// |  |- Maintainers
Jelle van der Waa's avatar
Jelle van der Waa committed
313
// |- Forum
314
315
// |  |- Admins
// |  |- Mods
Jelle van der Waa's avatar
Jelle van der Waa committed
316
// |- Security Team
317
318
319
320
// |  |- Admins
// |  |- Members
// |- IRC
// |  |- Ops
Jelle van der Waa's avatar
Jelle van der Waa committed
321
// |- Archweb
322
323
// |  |- Mirrorlist Maintainers
// |- Bug Wranglers
324
// External Contributors
325
326
327
328
// |- Security Team
// |  |- Reporters
// |- Archweb
//    |- Testers
329
resource "keycloak_group" "staff" {
330
  realm_id = "archlinux"
331
  name     = "Arch Linux Staff"
332
333
}

334
335
336
resource "keycloak_group" "staff_groups" {
  for_each = toset(["DevOps", "Developers", "Trusted Users", "Wiki", "Forum", "Security Team", "IRC", "Archweb", "Bug Wranglers"])

337
  realm_id  = "archlinux"
338
  parent_id = keycloak_group.staff.id
339
  name      = each.value
340
341
}

342
resource "keycloak_group" "staff_wiki_groups" {
343
  for_each = toset(["Admins", "Maintainers"])
Jelle van der Waa's avatar
Jelle van der Waa committed
344

345
  realm_id  = "archlinux"
346
  parent_id = keycloak_group.staff_groups["Wiki"].id
347
  name      = each.value
Jelle van der Waa's avatar
Jelle van der Waa committed
348
349
}

350
351
resource "keycloak_group" "staff_forum_groups" {
  for_each = toset(["Admins", "Mods"])
Jelle van der Waa's avatar
Jelle van der Waa committed
352

353
  realm_id  = "archlinux"
354
  parent_id = keycloak_group.staff_groups["Forum"].id
355
  name      = each.value
Jelle van der Waa's avatar
Jelle van der Waa committed
356
357
}

358
359
360
resource "keycloak_group" "staff_securityteam_groups" {
  for_each = toset(["Admins", "Members"])

361
  realm_id  = "archlinux"
362
  parent_id = keycloak_group.staff_groups["Security Team"].id
363
  name      = each.value
364
365
}

366
367
resource "keycloak_group" "staff_irc_groups" {
  for_each = toset(["Ops"])
368

369
  realm_id  = "archlinux"
370
  parent_id = keycloak_group.staff_groups["IRC"].id
371
  name      = each.value
372
373
}

374
375
resource "keycloak_group" "staff_archweb_groups" {
  for_each = toset(["Mirrorlist Maintainers"])
Jelle van der Waa's avatar
Jelle van der Waa committed
376

377
  realm_id  = "archlinux"
378
  parent_id = keycloak_group.staff_groups["Archweb"].id
379
  name      = each.value
Jelle van der Waa's avatar
Jelle van der Waa committed
380
381
}

382
383
resource "keycloak_group" "externalcontributors" {
  realm_id = "archlinux"
384
  name     = "External Contributors"
385
386
387
388
}

resource "keycloak_group" "externalcontributors_groups" {
  for_each = toset(["Security Team", "Archweb"])
Jelle van der Waa's avatar
Jelle van der Waa committed
389

390
  realm_id  = "archlinux"
391
  parent_id = keycloak_group.externalcontributors.id
392
  name      = each.value
Jelle van der Waa's avatar
Jelle van der Waa committed
393
394
}

395
396
resource "keycloak_group" "externalcontributors_securityteam_groups" {
  for_each = toset(["Reporters"])
Jelle van der Waa's avatar
Jelle van der Waa committed
397

398
  realm_id  = "archlinux"
399
  parent_id = keycloak_group.externalcontributors_groups["Security Team"].id
400
  name      = each.value
Jelle van der Waa's avatar
Jelle van der Waa committed
401
402
}

403
404
resource "keycloak_group" "externalcontributors_archweb_groups" {
  for_each = toset(["Testers"])
Jelle van der Waa's avatar
Jelle van der Waa committed
405

406
  realm_id  = "archlinux"
407
  parent_id = keycloak_group.externalcontributors_groups["Archweb"].id
408
  name      = each.value
Jelle van der Waa's avatar
Jelle van der Waa committed
409
410
}

411
resource "keycloak_role" "devops" {
412
413
  realm_id    = "archlinux"
  name        = "DevOps"
414
  description = "Role held by members of the DevOps group"
415
416
}

417
resource "keycloak_role" "staff" {
418
419
  realm_id    = "archlinux"
  name        = "Staff"
420
421
422
  description = "Role held by all Arch Linux staff"
}

423
resource "keycloak_role" "externalcontributor" {
424
425
  realm_id    = "archlinux"
  name        = "External Contributor"
426
427
428
  description = "Role held by external contributors working on Arch Linux projects without further access"
}

429
resource "keycloak_group_roles" "devops" {
430
  realm_id = "archlinux"
431
  group_id = keycloak_group.staff_groups["DevOps"].id
432
  role_ids = [
433
    keycloak_role.devops.id
434
435
436
  ]
}

437
438
439
440
resource "keycloak_group_roles" "staff" {
  realm_id = "archlinux"
  group_id = keycloak_group.staff.id
  role_ids = [
441
    keycloak_role.staff.id
442
443
444
  ]
}

445
resource "keycloak_group_roles" "externalcontributor" {
446
  realm_id = "archlinux"
447
  group_id = keycloak_group.externalcontributors.id
448
  role_ids = [
449
    keycloak_role.externalcontributor.id
450
451
452
  ]
}

453
454
// Add new custom registration flow with reCAPTCHA
resource "keycloak_authentication_flow" "arch_registration_flow" {
455
456
  realm_id    = "archlinux"
  alias       = "Arch Registration"
457
458
459
460
  description = "Customized Registration flow that forces enables ReCAPTCHA."
}

resource "keycloak_authentication_subflow" "registration_form" {
461
462
  realm_id          = "archlinux"
  alias             = "Registration Form"
463
  parent_flow_alias = keycloak_authentication_flow.arch_registration_flow.alias
464
465
466
  provider_id       = "form-flow"
  authenticator     = "registration-page-form"
  requirement       = "REQUIRED"
467
468
469
}

resource "keycloak_authentication_execution" "registration_user_creation" {
470
  realm_id          = "archlinux"
471
  parent_flow_alias = keycloak_authentication_subflow.registration_form.alias
472
473
  authenticator     = "registration-user-creation"
  requirement       = "REQUIRED"
474
475
476
}

resource "keycloak_authentication_execution" "registration_profile_action" {
477
  realm_id          = "archlinux"
478
  parent_flow_alias = keycloak_authentication_subflow.registration_form.alias
479
480
481
  authenticator     = "registration-profile-action"
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_execution.registration_user_creation]
482
483
484
}

resource "keycloak_authentication_execution" "registration_password_action" {
485
  realm_id          = "archlinux"
486
  parent_flow_alias = keycloak_authentication_subflow.registration_form.alias
487
488
489
  authenticator     = "registration-password-action"
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_execution.registration_profile_action]
490
491
492
}

resource "keycloak_authentication_execution" "registration_recaptcha_action" {
493
  realm_id          = "archlinux"
494
  parent_flow_alias = keycloak_authentication_subflow.registration_form.alias
495
496
497
  authenticator     = "registration-recaptcha-action"
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_execution.registration_password_action]
498
499
500
}

resource "keycloak_authentication_execution_config" "registration_recaptcha_action_config" {
501
502
  realm_id     = "archlinux"
  alias        = "reCAPTCHA config"
503
504
505
  execution_id = keycloak_authentication_execution.registration_recaptcha_action.id
  config = {
    "useRecaptchaNet" = "false",
506
507
    "site.key"        = data.external.vault_google.result.vault_google_recaptcha_site_key
    "secret"          = data.external.vault_google.result.vault_google_recaptcha_secret_key
508
509
510
  }
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
511
// Add new custom browser login flow with WebAuthn support and forced OTP.
512
//
513
514
// Try misc/kcadm_wrapper.sh get authentication/flows/{{ your flow alias}}/executions
// to make this a whole lot easier.
515
516
517
// NOTE: We use the `depends_on` calls to properly order the executions and subflows inside the
// flow. This has to be done until https://github.com/mrparkers/terraform-provider-keycloak/issues/296
// is fixed. :(
518
519
520
521
522
// We want to end up with something like this:
//
// Arch Browser flow
// |- Cookie (A)
// |- Identity Provider Redirector (A)
Kristian Klausen's avatar
Kristian Klausen committed
523
// |- Password and 2FA Subflow (A)
524
//   |- Username Password Form (R)
Kristian Klausen's avatar
Kristian Klausen committed
525
//   |- 2FA Subflow (R)
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
526
527
528
529
//      |- WebAuthn Authenticator (A)
//      |- OTP Form (A)
//      |- OTP Default Subflow (A)
//         |- OTP Form (R)
530
531
532
533
534
//
// IMPORTANT NOTE: Sometimes when changing Authentication Flows via Terraform or UI, flows can become orphaned in which
// case they'll hang around the database doing nothing useful and blocking alias names and causing 409 CONFLICTS. If such
// a thing happens, you'll have to get dirty and and manually clean up the authentication_flows and authentication_executions
// tables on the Keycloak Postgres DB! Quality Red Hat software right there.
535

536
resource "keycloak_authentication_flow" "arch_browser_flow" {
537
538
  realm_id    = "archlinux"
  alias       = "Arch Browser"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
539
  description = "Customized Browser flow that forces 2FA."
540
541
542
}

resource "keycloak_authentication_execution" "cookie" {
543
  realm_id          = "archlinux"
544
  parent_flow_alias = keycloak_authentication_flow.arch_browser_flow.alias
545
546
547
  authenticator     = "auth-cookie"
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_flow.arch_browser_flow]
548
549
550
}

resource "keycloak_authentication_execution" "identity_provider_redirector" {
551
  realm_id          = "archlinux"
552
  parent_flow_alias = keycloak_authentication_flow.arch_browser_flow.alias
553
554
555
  authenticator     = "identity-provider-redirector"
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.cookie]
556
557
}

Kristian Klausen's avatar
Kristian Klausen committed
558
resource "keycloak_authentication_subflow" "password_and_2fa" {
559
560
  realm_id          = "archlinux"
  alias             = "Password and 2FA subflow"
561
  parent_flow_alias = keycloak_authentication_flow.arch_browser_flow.alias
562
563
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.identity_provider_redirector]
564
565
566
}

resource "keycloak_authentication_execution" "username_password_form" {
567
  realm_id          = "archlinux"
Kristian Klausen's avatar
Kristian Klausen committed
568
  parent_flow_alias = keycloak_authentication_subflow.password_and_2fa.alias
569
570
  authenticator     = "auth-username-password-form"
  requirement       = "REQUIRED"
571
572
}

Kristian Klausen's avatar
Kristian Klausen committed
573
resource "keycloak_authentication_subflow" "_2fa" {
574
575
  realm_id          = "archlinux"
  alias             = "2FA subflow"
Kristian Klausen's avatar
Kristian Klausen committed
576
  parent_flow_alias = keycloak_authentication_subflow.password_and_2fa.alias
577
578
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_execution.username_password_form]
579
580
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
581
resource "keycloak_authentication_execution" "webauthn_form" {
582
  realm_id          = "archlinux"
Kristian Klausen's avatar
Kristian Klausen committed
583
  parent_flow_alias = keycloak_authentication_subflow._2fa.alias
584
585
  authenticator     = "webauthn-authenticator"
  requirement       = "ALTERNATIVE"
586
587
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
588
resource "keycloak_authentication_execution" "otp_form" {
589
  realm_id          = "archlinux"
Kristian Klausen's avatar
Kristian Klausen committed
590
  parent_flow_alias = keycloak_authentication_subflow._2fa.alias
591
592
593
  authenticator     = "auth-otp-form"
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.webauthn_form]
Kristian Klausen's avatar
Kristian Klausen committed
594
595
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
596
resource "keycloak_authentication_subflow" "otp_default" {
597
598
  realm_id          = "archlinux"
  alias             = "OTP Default Subflow"
Kristian Klausen's avatar
Kristian Klausen committed
599
  parent_flow_alias = keycloak_authentication_subflow._2fa.alias
600
601
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.otp_form]
602
603
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
604
resource "keycloak_authentication_execution" "otp_default_form" {
605
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
606
  parent_flow_alias = keycloak_authentication_subflow.otp_default.alias
607
608
  authenticator     = "auth-otp-form"
  requirement       = "REQUIRED"
609
610
}

611
612
613
// Add new custom post-Identity Provider login flow with forced OTP for some user roles
//
// Arch Post IPR Flow
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
614
615
616
617
// |- WebAuthn Form (A)
// |- OTP Form (A)
// |- IPR OTP Default Subflow (A)
//    |- OTP Form (R)
618
619

resource "keycloak_authentication_flow" "arch_post_ipr_flow" {
620
621
  realm_id    = "archlinux"
  alias       = "Arch Post IPR Flow"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
622
  description = "Post IPR login flow that forces 2FA."
623
624
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
625
resource "keycloak_authentication_execution" "ipr_webauthn_form" {
626
  realm_id          = "archlinux"
627
  parent_flow_alias = keycloak_authentication_flow.arch_post_ipr_flow.alias
628
629
  authenticator     = "webauthn-authenticator"
  requirement       = "ALTERNATIVE"
630
631
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
632
resource "keycloak_authentication_execution" "ipr_otp_form" {
633
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
634
  parent_flow_alias = keycloak_authentication_flow.arch_post_ipr_flow.alias
635
636
637
  authenticator     = "auth-otp-form"
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.ipr_webauthn_form]
638
639
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
640
resource "keycloak_authentication_subflow" "ipr_otp_default" {
641
642
  realm_id          = "archlinux"
  alias             = "IPR OTP Default Subflow"
643
  parent_flow_alias = keycloak_authentication_flow.arch_post_ipr_flow.alias
644
645
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.ipr_otp_form]
646
647
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
648
resource "keycloak_authentication_execution" "ipr_otp_default_form" {
649
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
650
  parent_flow_alias = keycloak_authentication_subflow.ipr_otp_default.alias
651
652
  authenticator     = "auth-otp-form"
  requirement       = "REQUIRED"
653
654
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
655
656
657
658
659
660
661
662
663
664
665
666
667
// Add new custom Reset Credentials flow that asks users to verify 2FA before resetting their password
//
// Arch Reset Credentials
// |- Choose User (R)
// |- Send Reset Email (R)
// |- Conditional Reset Credentials 2FA Subflow (C)
//    |- Condition - User Configured (R)
//    |- Reset Credentials 2FA Subflow (R)
//       |- WebAuthn Form (A)
//       |- OTP Form (A)
//       |- Reset Credentials OTP Default Subflow (A)
//          |- OTP Form (R)
// |- Reset Password (R)
668

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
669
resource "keycloak_authentication_flow" "arch_reset_credentials_flow" {
670
671
  realm_id    = "archlinux"
  alias       = "Arch Reset Credentials"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
672
  description = "Reset credentials flow that forces 2FA verification before password reset."
Kristian Klausen's avatar
Kristian Klausen committed
673
674
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
675
resource "keycloak_authentication_execution" "rc_choose_user" {
676
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
677
  parent_flow_alias = keycloak_authentication_flow.arch_reset_credentials_flow.alias
678
679
  authenticator     = "reset-credentials-choose-user"
  requirement       = "REQUIRED"
680
681
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
682
resource "keycloak_authentication_execution" "rc_reset_email" {
683
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
684
  parent_flow_alias = keycloak_authentication_flow.arch_reset_credentials_flow.alias
685
686
687
  authenticator     = "reset-credential-email"
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_execution.rc_choose_user]
688
689
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
690
resource "keycloak_authentication_subflow" "rc_conditional_2fa" {
691
692
  realm_id          = "archlinux"
  alias             = "Conditional Reset Credentials 2FA Subflow"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
693
  parent_flow_alias = keycloak_authentication_flow.arch_reset_credentials_flow.alias
694
695
  requirement       = "CONDITIONAL"
  depends_on        = [keycloak_authentication_execution.rc_choose_user]
696
697
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
698
resource "keycloak_authentication_execution" "rc_2fa_condition" {
699
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
700
  parent_flow_alias = keycloak_authentication_subflow.rc_conditional_2fa.alias
701
702
  authenticator     = "conditional-user-configured"
  requirement       = "REQUIRED"
703
704
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
705
resource "keycloak_authentication_subflow" "rc_2fa" {
706
707
  realm_id          = "archlinux"
  alias             = "Reset Credentials 2FA Subflow"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
708
  parent_flow_alias = keycloak_authentication_subflow.rc_conditional_2fa.alias
709
710
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_execution.rc_2fa_condition]
711
712
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
713
resource "keycloak_authentication_execution" "rc_webauthn_form" {
714
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
715
  parent_flow_alias = keycloak_authentication_subflow.rc_2fa.alias
716
717
  authenticator     = "webauthn-authenticator"
  requirement       = "ALTERNATIVE"
718
719
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
720
resource "keycloak_authentication_execution" "rc_otp_form" {
721
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
722
  parent_flow_alias = keycloak_authentication_subflow.rc_2fa.alias
723
724
725
  authenticator     = "auth-otp-form"
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.rc_webauthn_form]
Kristian Klausen's avatar
Kristian Klausen committed
726
727
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
728
resource "keycloak_authentication_subflow" "rc_otp_default" {
729
730
  realm_id          = "archlinux"
  alias             = "Reset Credentials OTP Default Subflow"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
731
  parent_flow_alias = keycloak_authentication_subflow.rc_2fa.alias
732
733
  requirement       = "ALTERNATIVE"
  depends_on        = [keycloak_authentication_execution.rc_otp_form]
734
735
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
736
resource "keycloak_authentication_execution" "rc_otp_default_form" {
737
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
738
  parent_flow_alias = keycloak_authentication_subflow.rc_otp_default.alias
739
740
  authenticator     = "auth-otp-form"
  requirement       = "REQUIRED"
741
742
}

Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
743
resource "keycloak_authentication_execution" "rc_reset_password" {
744
  realm_id          = "archlinux"
Sven-Hendrik Haase's avatar
Sven-Hendrik Haase committed
745
  parent_flow_alias = keycloak_authentication_flow.arch_reset_credentials_flow.alias
746
747
748
  authenticator     = "reset-password"
  requirement       = "REQUIRED"
  depends_on        = [keycloak_authentication_subflow.rc_conditional_2fa]
749
750
}

751
752
output "gitlab_saml_configuration" {
  value = {
753
754
755
756
    issuer                          = keycloak_saml_client.saml_gitlab.client_id
    assertion_consumer_service_url  = var.gitlab_instance.saml_redirect_url
    admin_groups                    = [keycloak_role.devops.name]
    idp_sso_target_url              = "https://accounts.archlinux.org/auth/realms/archlinux/protocol/saml/clients/${keycloak_saml_client.saml_gitlab.client_id}"
757
758
759
    signing_certificate_fingerprint = keycloak_saml_client.saml_gitlab.signing_certificate
  }
}
Jelle van der Waa's avatar
Jelle van der Waa committed
760
761

resource "keycloak_openid_client" "grafana_openid_client" {
762
763
764
  realm_id      = "archlinux"
  client_id     = "openid_grafana"
  client_secret = data.external.vault_monitoring.result.vault_monitoring_grafana_client_secret
Jelle van der Waa's avatar
Jelle van der Waa committed
765

766
  name    = "Grafana"
Jelle van der Waa's avatar
Jelle van der Waa committed
767
768
  enabled = true

769
  access_type           = "CONFIDENTIAL"
Jelle van der Waa's avatar
Jelle van der Waa committed
770
771
772
773
774
775
776
777
  standard_flow_enabled = true
  valid_redirect_uris = [
    "https://monitoring.archlinux.org",
    "https://monitoring.archlinux.org/login/generic_oauth"
  ]
}

resource "keycloak_openid_user_realm_role_protocol_mapper" "user_realm_role_mapper" {
778
779
780
  realm_id  = "archlinux"
  client_id = keycloak_openid_client.grafana_openid_client.id
  name      = "user realms"
Jelle van der Waa's avatar
Jelle van der Waa committed
781

782
783
784
  claim_name          = "roles"
  multivalued         = true
  add_to_id_token     = false
Jelle van der Waa's avatar
Jelle van der Waa committed
785
786
  add_to_access_token = false
}
787

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
resource "keycloak_openid_client" "hedgedoc_openid_client" {
  realm_id      = "archlinux"
  client_id     = "openid_hedgedoc"
  client_secret = data.external.vault_hedgedoc.result.vault_hedgedoc_client_secret

  name    = "Hedgedoc"
  enabled = true

  access_type           = "CONFIDENTIAL"
  standard_flow_enabled = true
  valid_redirect_uris = [
    "https://md.archlinux.org/*",
  ]
}

resource "keycloak_openid_user_realm_role_protocol_mapper" "hedgedoc_user_realm_role_mapper" {
  realm_id  = "archlinux"
  client_id = keycloak_openid_client.hedgedoc_openid_client.id
  name      = "user realms"

  claim_name          = "roles"
  multivalued         = true
  add_to_id_token     = false
  add_to_access_token = false
}
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835

resource "keycloak_openid_client" "matrix_openid_client" {
  realm_id      = "archlinux"
  client_id     = "openid_matrix"
  client_secret = data.external.vault_matrix.result.vault_matrix_openid_client_secret

  name    = "Matrix"
  enabled = true

  access_type           = "CONFIDENTIAL"
  standard_flow_enabled = true
  valid_redirect_uris = [
    "https://matrix.archlinux.org/_synapse/client/oidc/callback"
  ]
}

resource "keycloak_openid_user_realm_role_protocol_mapper" "matrix_user_realm_role_mapper" {
  realm_id  = "archlinux"
  client_id = keycloak_openid_client.matrix_openid_client.id
  name      = "user realms"

  claim_name          = "roles"
  multivalued         = true
836
  add_to_id_token     = true
837
838
  add_to_access_token = false
}
Jelle van der Waa's avatar
Jelle van der Waa committed
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856

resource "keycloak_openid_client" "gluebuddy_openid_client" {
  realm_id      = "archlinux"
  client_id     = "gluebuddy"
  client_secret = data.external.vault_keycloak.result.vault_keycloak_gluebuddy_openid_client_secret
  web_origins   = []

  name    = "Gluebuddy"
  enabled = true

  service_accounts_enabled = true

  access_type           = "CONFIDENTIAL"
  standard_flow_enabled = true
  valid_redirect_uris = [
    "https://gitlab.archlinux.org/"
  ]
}