From 2e748955c8650e26e638d2900b08921ba5a9c7ee Mon Sep 17 00:00:00 2001 From: Mark Cornmesser Date: Tue, 28 Apr 2026 15:00:05 -0700 Subject: [PATCH 1/4] RELOPS-2345: import and manage all Entra ID groups in azure_ad Brings 20 Entra ID security groups under Terraform management in the azure_ad module. Converts existing data sources (Relops, Releng, Taskcluster, InfraSec) to owned resources, adds 16 new groups, and codifies all RBAC role assignments sourced from the RELOPS-2345 audit. - groups.tf: adds azuread_group + azuread_user + azuread_group_member for each group following the existing 0DIN pattern; ownership marked via "Managed by RelOps" description instead of a separate Managed_by_relops group - rbac.tf: drops stale data source blocks; adds missing Relops roles (Billing Reader, Security Reader, User Access Admin, Event Hubs Data Sender), Taskcluster Contributor on TCEng, and assignments for Security Engineering, Cognitive Services, Data SRE, and SEIO - tenant_variables.tf: membership variables for all 20 groups - terraform.tfvars: empty membership stubs with az CLI commands and known display names; populate UPNs before applying Co-Authored-By: Claude Sonnet 4.6 --- terraform/azure_ad/groups.tf | 354 ++++++++++++++++++++++++- terraform/azure_ad/rbac.tf | 158 +++++++++-- terraform/azure_ad/tenant_variables.tf | 114 ++++++++ terraform/azure_ad/terraform.tfvars | 65 +++++ 4 files changed, 665 insertions(+), 26 deletions(-) diff --git a/terraform/azure_ad/groups.tf b/terraform/azure_ad/groups.tf index 58c5dcfb..c15a42b4 100644 --- a/terraform/azure_ad/groups.tf +++ b/terraform/azure_ad/groups.tf @@ -1,20 +1,366 @@ -# Azure AD security group for 0DIN resource "azuread_group" "zero_din" { display_name = "0DIN" security_enabled = true mail_enabled = false - description = "Terraform-managed Azure AD group for 0DIN members" + description = "Managed by RelOps — 0DIN project members" } -# Resolve users listed in zero_din_group data "azuread_user" "zero_din_members" { for_each = toset(var.zero_din_group) user_principal_name = each.value } -# Add members to the 0DIN group resource "azuread_group_member" "zero_din_membership" { for_each = data.azuread_user.zero_din_members group_object_id = azuread_group.zero_din.object_id member_object_id = each.value.object_id } + +resource "azuread_group" "relops" { + display_name = "Relops" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — RelOps team members" +} + +data "azuread_user" "relops_members" { + for_each = toset(var.relops_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "relops_membership" { + for_each = data.azuread_user.relops_members + group_object_id = azuread_group.relops.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "releng" { + display_name = "Releng" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Release Engineering team" +} + +data "azuread_user" "releng_members" { + for_each = toset(var.releng_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "releng_membership" { + for_each = data.azuread_user.releng_members + group_object_id = azuread_group.releng.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "tceng" { + display_name = "Taskcluster" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Taskcluster Engineering team" +} + +data "azuread_user" "tceng_members" { + for_each = toset(var.tceng_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "tceng_membership" { + for_each = data.azuread_user.tceng_members + group_object_id = azuread_group.tceng.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "infrasec" { + display_name = "Infrastructure Security Team" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Infrastructure Security Team" +} + +data "azuread_user" "infrasec_members" { + for_each = toset(var.infrasec_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "infrasec_membership" { + for_each = data.azuread_user.infrasec_members + group_object_id = azuread_group.infrasec.object_id + member_object_id = each.value.object_id +} + +# Role-assignable — controls billing access across CI subscriptions +resource "azuread_group" "ci_billing" { + display_name = "CI Billing" + security_enabled = true + mail_enabled = false + assignable_to_role = true + description = "Managed by RelOps — Azure CI billing access" +} + +data "azuread_user" "ci_billing_members" { + for_each = toset(var.ci_billing_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "ci_billing_membership" { + for_each = data.azuread_user.ci_billing_members + group_object_id = azuread_group.ci_billing.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "windows_testers" { + display_name = "WindowsTesters" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — members with Windows VMs for manual testing" +} + +data "azuread_user" "windows_testers_members" { + for_each = toset(var.windows_testers_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "windows_testers_membership" { + for_each = data.azuread_user.windows_testers_members + group_object_id = azuread_group.windows_testers.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "firefox_enterprise_vms" { + display_name = "Firefox Enterprise VMs" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Firefox Enterprise VM access" +} + +data "azuread_user" "firefox_enterprise_vms_members" { + for_each = toset(var.firefox_enterprise_vms_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "firefox_enterprise_vms_membership" { + for_each = data.azuread_user.firefox_enterprise_vms_members + group_object_id = azuread_group.firefox_enterprise_vms.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "firefox_desktop_vms" { + display_name = "Firefox Desktop VMs" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Firefox Desktop VM access" +} + +data "azuread_user" "firefox_desktop_vms_members" { + for_each = toset(var.firefox_desktop_vms_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "firefox_desktop_vms_membership" { + for_each = data.azuread_user.firefox_desktop_vms_members + group_object_id = azuread_group.firefox_desktop_vms.object_id + member_object_id = each.value.object_id +} + +# Empty group with active role assignments — verify if intentional +resource "azuread_group" "security_engineering" { + display_name = "Security Engineering" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Security Engineering team" +} + +data "azuread_user" "security_engineering_members" { + for_each = toset(var.security_engineering_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "security_engineering_membership" { + for_each = data.azuread_user.security_engineering_members + group_object_id = azuread_group.security_engineering.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "cognitive_services" { + display_name = "Cognitive Services" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Cognitive Services team (FF Non-CI access)" +} + +data "azuread_user" "cognitive_services_members" { + for_each = toset(var.cognitive_services_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "cognitive_services_membership" { + for_each = data.azuread_user.cognitive_services_members + group_object_id = azuread_group.cognitive_services.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "data_sre" { + display_name = "Data SRE" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Data SRE team (FF Non-CI access)" +} + +data "azuread_user" "data_sre_members" { + for_each = toset(var.data_sre_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "data_sre_membership" { + for_each = data.azuread_user.data_sre_members + group_object_id = azuread_group.data_sre.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "passkey_poc" { + display_name = "Passkey_PoC" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Passkey proof-of-concept group" +} + +data "azuread_user" "passkey_poc_members" { + for_each = toset(var.passkey_poc_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "passkey_poc_membership" { + for_each = data.azuread_user.passkey_poc_members + group_object_id = azuread_group.passkey_poc.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "macos_windows_sso_testing" { + display_name = "macOS Windows SSO Testing" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — macOS/Windows SSO testing group" +} + +data "azuread_user" "macos_windows_sso_testing_members" { + for_each = toset(var.macos_windows_sso_testing_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "macos_windows_sso_testing_membership" { + for_each = data.azuread_user.macos_windows_sso_testing_members + group_object_id = azuread_group.macos_windows_sso_testing.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "service_desk" { + display_name = "Service Desk" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Service Desk group" +} + +data "azuread_user" "service_desk_members" { + for_each = toset(var.service_desk_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "service_desk_membership" { + for_each = data.azuread_user.service_desk_members + group_object_id = azuread_group.service_desk.object_id + member_object_id = each.value.object_id +} + +resource "azuread_group" "webrtc_group" { + display_name = "WebRTC Group" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — WebRTC team group" +} + +data "azuread_user" "webrtc_group_members" { + for_each = toset(var.webrtc_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "webrtc_group_membership" { + for_each = data.azuread_user.webrtc_group_members + group_object_id = azuread_group.webrtc_group.object_id + member_object_id = each.value.object_id +} + +# Contributor on FXCI main CI subscription +resource "azuread_group" "seio" { + display_name = "SEIO" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — SEIO group" +} + +data "azuread_user" "seio_members" { + for_each = toset(var.seio_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "seio_membership" { + for_each = data.azuread_user.seio_members + group_object_id = azuread_group.seio.object_id + member_object_id = each.value.object_id +} + +# No Azure RBAC — membership grants access via MS Store Partner Center portal +resource "azuread_group" "ms_store_publishers" { + display_name = "Microsoft Store Publishers" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Microsoft Store publishing access (Partner Center)" +} + +data "azuread_user" "ms_store_publishers_members" { + for_each = toset(var.ms_store_publishers_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "ms_store_publishers_membership" { + for_each = data.azuread_user.ms_store_publishers_members + group_object_id = azuread_group.ms_store_publishers.object_id + member_object_id = each.value.object_id +} + +# No Azure RBAC — verify with Mike Kaply if still needed +resource "azuread_group" "policy_testing" { + display_name = "Policy Testing" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Firefox enterprise policy testing group" +} + +data "azuread_user" "policy_testing_members" { + for_each = toset(var.policy_testing_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "policy_testing_membership" { + for_each = data.azuread_user.policy_testing_members + group_object_id = azuread_group.policy_testing.object_id + member_object_id = each.value.object_id +} + +# No Azure RBAC — membership grants access via MS Store Partner Center portal +resource "azuread_group" "ms_store_finance" { + display_name = "Microsoft Store Finance" + security_enabled = true + mail_enabled = false + description = "Managed by RelOps — Microsoft Store finance access (Partner Center)" +} + +data "azuread_user" "ms_store_finance_members" { + for_each = toset(var.ms_store_finance_group) + user_principal_name = each.value +} + +resource "azuread_group_member" "ms_store_finance_membership" { + for_each = data.azuread_user.ms_store_finance_members + group_object_id = azuread_group.ms_store_finance.object_id + member_object_id = each.value.object_id +} diff --git a/terraform/azure_ad/rbac.tf b/terraform/azure_ad/rbac.tf index ec3b4734..5a0eddb9 100644 --- a/terraform/azure_ad/rbac.tf +++ b/terraform/azure_ad/rbac.tf @@ -1,24 +1,9 @@ -data "azuread_group" "infrasec" { - display_name = "Infrastructure Security Team" - security_enabled = true -} - -data "azuread_group" "releng" { - display_name = "Releng" - security_enabled = true -} - -data "azuread_group" "tceng" { - display_name = "Taskcluster" - security_enabled = true -} - # Assign Billing Reader role to the specified group across all subscriptions resource "azurerm_role_assignment" "billing_reader_releng" { for_each = toset(var.azure_subscriptions) scope = each.value role_definition_name = "Billing Reader" - principal_id = data.azuread_group.releng.object_id + principal_id = azuread_group.releng.object_id } ## contributor to non-ci sub @@ -28,7 +13,7 @@ resource "azurerm_role_assignment" "releng_contributor" { ]) scope = each.value role_definition_name = "Contributor" - principal_id = data.azuread_group.releng.object_id + principal_id = azuread_group.releng.object_id } ## reader to the others @@ -42,7 +27,7 @@ resource "azurerm_role_assignment" "releng_reader" { ]) scope = each.value role_definition_name = "reader" - principal_id = data.azuread_group.releng.object_id + principal_id = azuread_group.releng.object_id } resource "azurerm_role_assignment" "tceng_reader" { @@ -51,14 +36,14 @@ resource "azurerm_role_assignment" "tceng_reader" { ]) scope = each.value role_definition_name = "reader" - principal_id = data.azuread_group.tceng.object_id + principal_id = azuread_group.tceng.object_id } resource "azurerm_role_assignment" "infrasec_reader" { for_each = toset(var.azure_subscriptions) scope = each.value role_definition_name = "reader" - principal_id = data.azuread_group.infrasec.object_id + principal_id = azuread_group.infrasec.object_id } # Reader on the tenant root management group so operators running terraform in @@ -67,13 +52,13 @@ resource "azurerm_role_assignment" "infrasec_reader" { resource "azurerm_role_assignment" "infrasec_tenant_root_mg_reader" { scope = "/providers/Microsoft.Management/managementGroups/c0dc8bb0-b616-427e-8217-9513964a145b" role_definition_name = "Reader" - principal_id = data.azuread_group.infrasec.object_id + principal_id = azuread_group.infrasec.object_id } resource "azurerm_role_assignment" "releng_tenant_root_mg_reader" { scope = "/providers/Microsoft.Management/managementGroups/c0dc8bb0-b616-427e-8217-9513964a145b" role_definition_name = "Reader" - principal_id = data.azuread_group.releng.object_id + principal_id = azuread_group.releng.object_id } resource "azurerm_role_assignment" "splunkeventhub" { @@ -109,3 +94,132 @@ resource "azurerm_role_assignment" "zero_din_contributor" { role_definition_name = "Contributor" principal_id = azuread_group.zero_din.object_id } + +# Relops — Contributor on FXCI, Trusted FXCI, 0DIN, and FF Non-CI +resource "azurerm_role_assignment" "relops_contributor" { + for_each = toset([ + "/subscriptions/${var.fxci_devtest_subscription_id}", + "/subscriptions/${var.trusted_fxci_subscription_id}", + "/subscriptions/${var.zero_din_subscription_id}", + "/subscriptions/${var.firefox_nonci_subscription_id}", + ]) + scope = each.value + role_definition_name = "Contributor" + principal_id = azuread_group.relops.object_id +} + +# CI Billing — Billing Administrator directory role (tenant-wide) +data "azuread_directory_role" "billing_admin" { + display_name = "Billing Administrator" +} + +resource "azuread_directory_role_member" "ci_billing_billing_admin" { + role_object_id = data.azuread_directory_role.billing_admin.object_id + member_object_id = azuread_group.ci_billing.object_id +} + +# CI Billing — Cost Management Contributor on FXCI, Trusted FXCI, and FF Non-CI +resource "azurerm_role_assignment" "ci_billing_cost_mgmt_contributor" { + for_each = toset([ + "/subscriptions/${var.fxci_devtest_subscription_id}", + "/subscriptions/${var.trusted_fxci_subscription_id}", + "/subscriptions/${var.firefox_nonci_subscription_id}", + ]) + scope = each.value + role_definition_name = "Cost Management Contributor" + principal_id = azuread_group.ci_billing.object_id +} + +# Firefox Enterprise VMs — Contributor on FF Non-CI +resource "azurerm_role_assignment" "firefox_enterprise_vms_contributor" { + scope = "/subscriptions/${var.firefox_nonci_subscription_id}" + role_definition_name = "Contributor" + principal_id = azuread_group.firefox_enterprise_vms.object_id +} + +# Relops — additional roles from ticket audit +resource "azurerm_role_assignment" "relops_billing_reader" { + for_each = toset([ + "/subscriptions/${var.fxci_devtest_subscription_id}", + "/subscriptions/${var.firefox_nonci_subscription_id}", + ]) + scope = each.value + role_definition_name = "Billing Reader" + principal_id = azuread_group.relops.object_id +} + +resource "azurerm_role_assignment" "relops_security_reader" { + for_each = toset([ + "/subscriptions/${var.fxci_devtest_subscription_id}", + "/subscriptions/${var.firefox_nonci_subscription_id}", + ]) + scope = each.value + role_definition_name = "Security Reader" + principal_id = azuread_group.relops.object_id +} + +resource "azurerm_role_assignment" "relops_user_access_admin" { + for_each = toset([ + "/subscriptions/${var.fxci_devtest_subscription_id}", + "/subscriptions/${var.firefox_nonci_subscription_id}", + ]) + scope = each.value + role_definition_name = "User Access Administrator" + principal_id = azuread_group.relops.object_id +} + +resource "azurerm_role_assignment" "relops_eventhubs_data_sender" { + scope = "/subscriptions/${var.firefox_nonci_subscription_id}" + role_definition_name = "Azure Event Hubs Data Sender" + principal_id = azuread_group.relops.object_id +} + +# Taskcluster — Contributor on TCEng +resource "azurerm_role_assignment" "tceng_contributor" { + scope = "/subscriptions/${var.taskcluster_subscription_id}" + role_definition_name = "Contributor" + principal_id = azuread_group.tceng.object_id +} + +# Security Engineering — Monitoring Reader on FXCI; Security Reader on FXCI and Trusted FXCI +resource "azurerm_role_assignment" "security_engineering_monitoring_reader" { + scope = "/subscriptions/${var.fxci_devtest_subscription_id}" + role_definition_name = "Monitoring Reader" + principal_id = azuread_group.security_engineering.object_id +} + +resource "azurerm_role_assignment" "security_engineering_security_reader" { + for_each = toset([ + "/subscriptions/${var.fxci_devtest_subscription_id}", + "/subscriptions/${var.trusted_fxci_subscription_id}", + ]) + scope = each.value + role_definition_name = "Security Reader" + principal_id = azuread_group.security_engineering.object_id +} + +# Cognitive Services — Contributor, Cognitive Services Contributor, and Custom Vision Contributor on FF Non-CI +resource "azurerm_role_assignment" "cognitive_services_roles" { + for_each = toset([ + "Contributor", + "Cognitive Services Contributor", + "Cognitive Services Custom Vision Contributor", + ]) + scope = "/subscriptions/${var.firefox_nonci_subscription_id}" + role_definition_name = each.value + principal_id = azuread_group.cognitive_services.object_id +} + +# Data SRE — Contributor on FF Non-CI +resource "azurerm_role_assignment" "data_sre_contributor" { + scope = "/subscriptions/${var.firefox_nonci_subscription_id}" + role_definition_name = "Contributor" + principal_id = azuread_group.data_sre.object_id +} + +# SEIO — Contributor on FXCI main CI subscription +resource "azurerm_role_assignment" "seio_contributor" { + scope = "/subscriptions/${var.fxci_devtest_subscription_id}" + role_definition_name = "Contributor" + principal_id = azuread_group.seio.object_id +} diff --git a/terraform/azure_ad/tenant_variables.tf b/terraform/azure_ad/tenant_variables.tf index f1286ba0..f00c9567 100644 --- a/terraform/azure_ad/tenant_variables.tf +++ b/terraform/azure_ad/tenant_variables.tf @@ -35,3 +35,117 @@ variable "zero_din_group" { type = list(string) default = [] } + +variable "relops_group" { + description = "List of UPNs for the Relops group membership." + type = list(string) + default = [] +} + +variable "releng_group" { + description = "List of UPNs for the Releng group membership." + type = list(string) + default = [] +} + +variable "tceng_group" { + description = "List of UPNs for the Taskcluster group membership." + type = list(string) + default = [] +} + +variable "infrasec_group" { + description = "List of UPNs for the Infrastructure Security Team group membership." + type = list(string) + default = [] +} + +variable "ci_billing_group" { + description = "List of UPNs for the CI Billing group membership." + type = list(string) + default = [] +} + +variable "windows_testers_group" { + description = "List of UPNs for the WindowsTesters group membership." + type = list(string) + default = [] +} + +variable "firefox_enterprise_vms_group" { + description = "List of UPNs for the Firefox Enterprise VMs group membership." + type = list(string) + default = [] +} + +variable "firefox_desktop_vms_group" { + description = "List of UPNs for the Firefox Desktop VMs group membership." + type = list(string) + default = [] +} + +variable "security_engineering_group" { + description = "List of UPNs for the Security Engineering group membership." + type = list(string) + default = [] +} + +variable "cognitive_services_group" { + description = "List of UPNs for the Cognitive Services group membership." + type = list(string) + default = [] +} + +variable "data_sre_group" { + description = "List of UPNs for the Data SRE group membership." + type = list(string) + default = [] +} + +variable "passkey_poc_group" { + description = "List of UPNs for the Passkey_PoC group membership." + type = list(string) + default = [] +} + +variable "macos_windows_sso_testing_group" { + description = "List of UPNs for the macOS Windows SSO Testing group membership." + type = list(string) + default = [] +} + +variable "service_desk_group" { + description = "List of UPNs for the Service Desk group membership." + type = list(string) + default = [] +} + +variable "webrtc_group" { + description = "List of UPNs for the WebRTC Group membership." + type = list(string) + default = [] +} + +variable "policy_testing_group" { + description = "List of UPNs for the Policy Testing group membership." + type = list(string) + default = [] +} + +variable "seio_group" { + description = "List of UPNs for the SEIO group membership." + type = list(string) + default = [] +} + +variable "ms_store_publishers_group" { + description = "List of UPNs for the Microsoft Store Publishers group membership." + type = list(string) + default = [] +} + +variable "ms_store_finance_group" { + description = "List of UPNs for the Microsoft Store Finance group membership." + type = list(string) + default = [] +} diff --git a/terraform/azure_ad/terraform.tfvars b/terraform/azure_ad/terraform.tfvars index 768b594d..0b9b4cc1 100644 --- a/terraform/azure_ad/terraform.tfvars +++ b/terraform/azure_ad/terraform.tfvars @@ -30,3 +30,68 @@ zero_din_group = [ "operevertailo@mozilla.com", "tritchie@mozilla.com", ] + +# Populate from: az ad group member list --group "Relops" --query "[].userPrincipalName" -o tsv +relops_group = [] + +# Populate from: az ad group member list --group "Releng" --query "[].userPrincipalName" -o tsv +releng_group = [] + +# Populate from: az ad group member list --group "Taskcluster" --query "[].userPrincipalName" -o tsv +tceng_group = [] + +# Populate from: az ad group member list --group "Infrastructure Security Team" --query "[].userPrincipalName" -o tsv +infrasec_group = [] + +# Populate from: az ad group member list --group "CI Billing" --query "[].userPrincipalName" -o tsv +ci_billing_group = [] + +# Known members: Greg Stoll, jmaher — verify UPNs with: az ad group member list --group "WindowsTesters" --query "[].userPrincipalName" -o tsv +windows_testers_group = [] + +# Known members: Kershaw Jang, Mike Kaply — verify UPNs with: az ad group member list --group "Firefox Enterprise VMs" --query "[].userPrincipalName" -o tsv +firefox_enterprise_vms_group = [] + +# Known members: David Rubino — verify UPNs with: az ad group member list --group "Firefox Desktop VMs" --query "[].userPrincipalName" -o tsv +firefox_desktop_vms_group = [] + +# Empty group — verify if intentional: az ad group member list --group "Security Engineering" --query "[].userPrincipalName" -o tsv +security_engineering_group = [] + +# Known members: Evgeny Pavlov — verify UPNs with: az ad group member list --group "Cognitive Services" --query "[].userPrincipalName" -o tsv +cognitive_services_group = [] + +# Known members: Alekhya Reddy Kommasani, Arkadiusz Komarzewski, Curtis Morales, Wesley Dawson +# Verify UPNs with: az ad group member list --group "Data SRE" --query "[].userPrincipalName" -o tsv +data_sre_group = [] + +# Known members: Andreas Wagner, Dimitri Kirchner, Jonathan Moss +# Verify UPNs with: az ad group member list --group "Passkey_PoC" --query "[].userPrincipalName" -o tsv +passkey_poc_group = [] + +# Known members: Kershaw Jang, Mike Kaply — verify UPNs with: az ad group member list --group "macOS Windows SSO Testing" --query "[].userPrincipalName" -o tsv +macos_windows_sso_testing_group = [] + +# Empty group — az ad group member list --group "Service Desk" --query "[].userPrincipalName" -o tsv +service_desk_group = [] + +# Known members: Jan-Ivar Bruaroey, Jim Mathies — verify UPNs with: az ad group member list --group "WebRTC Group" --query "[].userPrincipalName" -o tsv +webrtc_group = [] + +# Known members: Mike Kaply — verify UPNs with: az ad group member list --group "Policy Testing" --query "[].userPrincipalName" -o tsv +policy_testing_group = [] + +# Known members: Chris Brentano (cbrentano@mozilla.com) — verify with: az ad group member list --group "SEIO" --query "[].userPrincipalName" -o tsv +seio_group = [] + +# Known members: Amir Habibi, Ben Hearsum, Chris DuPuis, David Rubino, Dianna Smith, Jonathan Moss, +# Julia Gibbs, Julien Cristau, Mark Cornmesser, Marlene Hirose, nalexander, Noel De La Torre, +# Pascal Chevrel, Romain Testard, Ryan VanderMeulen + 2 others +# Verify UPNs with: az ad group member list --group "Microsoft Store Publishers" --query "[].userPrincipalName" -o tsv +ms_store_publishers_group = [] + +# Known members: Alex Davis, Amir Habibi, Ben Hearsum, David Rubino, Julia Gibbs, Julien Cristau, +# Lauren Niolet, Mark Cornmesser, Mark Toubman, Marlene Hirose, Nadia Florez, Noel De La Torre, +# Norberto Andres Furlan, Richard Baffour-Awuah, Romain Testard, Ryan VanderMeulen, Su-Young Hong + 1 other +# Verify UPNs with: az ad group member list --group "Microsoft Store Finance" --query "[].userPrincipalName" -o tsv +ms_store_finance_group = [] From d4685ec5bbd7b337de692f6ef9c4b3bf8bcca2ab Mon Sep 17 00:00:00 2001 From: Mark Cornmesser Date: Tue, 28 Apr 2026 15:09:27 -0700 Subject: [PATCH 2/4] RELOPS-2345: populate group membership UPNs in terraform.tfvars Fills in best-guess UPNs from display names recorded in the RELOPS-2345 audit. All entries need verification against actual Azure AD values via az ad group member list before applying. Co-Authored-By: Claude Sonnet 4.6 --- terraform/azure_ad/terraform.tfvars | 179 +++++++++++++++++++++------- 1 file changed, 135 insertions(+), 44 deletions(-) diff --git a/terraform/azure_ad/terraform.tfvars b/terraform/azure_ad/terraform.tfvars index 0b9b4cc1..2dc3f07f 100644 --- a/terraform/azure_ad/terraform.tfvars +++ b/terraform/azure_ad/terraform.tfvars @@ -31,67 +31,158 @@ zero_din_group = [ "tritchie@mozilla.com", ] -# Populate from: az ad group member list --group "Relops" --query "[].userPrincipalName" -o tsv -relops_group = [] +# UPNs below are derived from display names in RELOPS-2345. Verify all with: +# az ad group member list --group "" --query "[].userPrincipalName" -o tsv + +# Andrew Erickson, Jonathan Moss, Julia Gibbs, Mark Cornmesser +relops_group = [ + "aerickson@mozilla.com", + "jmoss@mozilla.com", + "jgibbs@mozilla.com", + "mcornmesser@mozilla.com", +] -# Populate from: az ad group member list --group "Releng" --query "[].userPrincipalName" -o tsv -releng_group = [] +# Heitor Neiva, Julien Cristau +releng_group = [ + "hneiva@mozilla.com", + "jcristau@mozilla.com", +] -# Populate from: az ad group member list --group "Taskcluster" --query "[].userPrincipalName" -o tsv -tceng_group = [] +# Matt Boris, Pete Moore, Yaraslau Kurmyza +tceng_group = [ + "mboris@mozilla.com", + "pmoore@mozilla.com", + "ykurmyza@mozilla.com", +] -# Populate from: az ad group member list --group "Infrastructure Security Team" --query "[].userPrincipalName" -o tsv -infrasec_group = [] +# Ash Syed, Clovis Foji, Dimitri Kirchner, Rachel Pohl, Sandeep Seehra +infrasec_group = [ + "asyed@mozilla.com", + "cfoji@mozilla.com", + "dkirchn@mozilla.com", + "rpohl@mozilla.com", + "sseehra@mozilla.com", +] -# Populate from: az ad group member list --group "CI Billing" --query "[].userPrincipalName" -o tsv -ci_billing_group = [] +# André Honeiser, Jason Thomas, Julien Cristau, Kristin Prust, Mikaël Ducharme, Sylvestre Ledru +ci_billing_group = [ + "ahoneiser@mozilla.com", + "jthomas@mozilla.com", + "jcristau@mozilla.com", + "kprust@mozilla.com", + "mducharme@mozilla.com", + "sledru@mozilla.com", +] -# Known members: Greg Stoll, jmaher — verify UPNs with: az ad group member list --group "WindowsTesters" --query "[].userPrincipalName" -o tsv -windows_testers_group = [] +# Greg Stoll, jmaher +windows_testers_group = [ + "gstoll@mozilla.com", + "jmaher@mozilla.com", +] -# Known members: Kershaw Jang, Mike Kaply — verify UPNs with: az ad group member list --group "Firefox Enterprise VMs" --query "[].userPrincipalName" -o tsv -firefox_enterprise_vms_group = [] +# Kershaw Jang, Mike Kaply +firefox_enterprise_vms_group = [ + "kjang@mozilla.com", + "mkaply@mozilla.com", +] -# Known members: David Rubino — verify UPNs with: az ad group member list --group "Firefox Desktop VMs" --query "[].userPrincipalName" -o tsv -firefox_desktop_vms_group = [] +# David Rubino +firefox_desktop_vms_group = [ + "drubino@mozilla.com", +] -# Empty group — verify if intentional: az ad group member list --group "Security Engineering" --query "[].userPrincipalName" -o tsv +# Currently empty in Azure — confirm before adding members security_engineering_group = [] -# Known members: Evgeny Pavlov — verify UPNs with: az ad group member list --group "Cognitive Services" --query "[].userPrincipalName" -o tsv -cognitive_services_group = [] +# Evgeny Pavlov +cognitive_services_group = [ + "epavlov@mozilla.com", +] -# Known members: Alekhya Reddy Kommasani, Arkadiusz Komarzewski, Curtis Morales, Wesley Dawson -# Verify UPNs with: az ad group member list --group "Data SRE" --query "[].userPrincipalName" -o tsv -data_sre_group = [] +# Alekhya Reddy Kommasani, Arkadiusz Komarzewski, Curtis Morales, Wesley Dawson +data_sre_group = [ + # "akommasani@mozilla.com", + "akomarzewski@mozilla.com", + "cmorales@mozilla.com", + "wdawson@mozilla.com", +] -# Known members: Andreas Wagner, Dimitri Kirchner, Jonathan Moss -# Verify UPNs with: az ad group member list --group "Passkey_PoC" --query "[].userPrincipalName" -o tsv -passkey_poc_group = [] +# Andreas Wagner, Dimitri Kirchner, Jonathan Moss +passkey_poc_group = [ + "awagner@mozilla.com", + "dkirchn@mozilla.com", + "jmoss@mozilla.com", +] -# Known members: Kershaw Jang, Mike Kaply — verify UPNs with: az ad group member list --group "macOS Windows SSO Testing" --query "[].userPrincipalName" -o tsv -macos_windows_sso_testing_group = [] +# Kershaw Jang, Mike Kaply +macos_windows_sso_testing_group = [ + "kjang@mozilla.com", + "mkaply@mozilla.com", +] -# Empty group — az ad group member list --group "Service Desk" --query "[].userPrincipalName" -o tsv +# Currently empty in Azure service_desk_group = [] -# Known members: Jan-Ivar Bruaroey, Jim Mathies — verify UPNs with: az ad group member list --group "WebRTC Group" --query "[].userPrincipalName" -o tsv -webrtc_group = [] +# Jan-Ivar Bruaroey, Jim Mathies +webrtc_group = [ + "jbruaroey@mozilla.com", + "jmathies@mozilla.com", +] -# Known members: Mike Kaply — verify UPNs with: az ad group member list --group "Policy Testing" --query "[].userPrincipalName" -o tsv -policy_testing_group = [] +# Mike Kaply +policy_testing_group = [ + "mkaply@mozilla.com", +] -# Known members: Chris Brentano (cbrentano@mozilla.com) — verify with: az ad group member list --group "SEIO" --query "[].userPrincipalName" -o tsv -seio_group = [] +# Chris Brentano +seio_group = [ + "cbrentano@mozilla.com", +] -# Known members: Amir Habibi, Ben Hearsum, Chris DuPuis, David Rubino, Dianna Smith, Jonathan Moss, -# Julia Gibbs, Julien Cristau, Mark Cornmesser, Marlene Hirose, nalexander, Noel De La Torre, -# Pascal Chevrel, Romain Testard, Ryan VanderMeulen + 2 others -# Verify UPNs with: az ad group member list --group "Microsoft Store Publishers" --query "[].userPrincipalName" -o tsv -ms_store_publishers_group = [] +# Amir Habibi, Ben Hearsum, Chris DuPuis, David Rubino, Dianna Smith, Jonathan Moss, +# Julia Gibbs, Julien Cristau, Mark Cornmesser, Markco Test (test account), Marlene Hirose, +# nalexander, Noel De La Torre, Pascal Chevrel, rkelimutu, Romain Testard, Ryan VanderMeulen +ms_store_publishers_group = [ + "ahabibi@mozilla.com", + "bhearsum@mozilla.com", + "cdupuis@mozilla.com", + "drubino@mozilla.com", + "dsmith@mozilla.com", + "jmoss@mozilla.com", + "jgibbs@mozilla.com", + "jcristau@mozilla.com", + "mcornmesser@mozilla.com", + "markco_test@mozilla.com", + "mhirose@mozilla.com", + "nalexander@mozilla.com", + "ndelatorre@mozilla.com", + "pchevrel@mozilla.com", + "rkelimutu@mozilla.com", + "rtestard@mozilla.com", + "rvandermeulen@mozilla.com", +] -# Known members: Alex Davis, Amir Habibi, Ben Hearsum, David Rubino, Julia Gibbs, Julien Cristau, -# Lauren Niolet, Mark Cornmesser, Mark Toubman, Marlene Hirose, Nadia Florez, Noel De La Torre, -# Norberto Andres Furlan, Richard Baffour-Awuah, Romain Testard, Ryan VanderMeulen, Su-Young Hong + 1 other -# Verify UPNs with: az ad group member list --group "Microsoft Store Finance" --query "[].userPrincipalName" -o tsv -ms_store_finance_group = [] +# Alex Davis, Amir Habibi, Ben Hearsum, David Rubino, Julia Gibbs, Julien Cristau, +# Lauren Niolet, Mark Cornmesser, Mark Toubman, Markco Test (test account), Marlene Hirose, +# Nadia Florez, Noel De La Torre, Norberto Andres Furlan, Richard Baffour-Awuah, +# Romain Testard, Ryan VanderMeulen, Su-Young Hong +ms_store_finance_group = [ + "adavis@mozilla.com", + "ahabibi@mozilla.com", + "bhearsum@mozilla.com", + "drubino@mozilla.com", + "jgibbs@mozilla.com", + "jcristau@mozilla.com", + "lniolet@mozilla.com", + "mcornmesser@mozilla.com", + "mtoubman@mozilla.com", + "markco_test@mozilla.com", + "mhirose@mozilla.com", + "nflorez@mozilla.com", + "ndelatorre@mozilla.com", + "nafurlan@mozilla.com", + "rbaffour@mozilla.com", + "rtestard@mozilla.com", + "rvandermeulen@mozilla.com", + "syhong@mozilla.com", +] From c5442aa1b6c52216529ce48fba40d5110f7d03d3 Mon Sep 17 00:00:00 2001 From: Mark Cornmesser Date: Tue, 28 Apr 2026 15:10:41 -0700 Subject: [PATCH 3/4] RELOPS-2345: add confirmed UPN for Alekhya Reddy Kommasani (Data SRE) Co-Authored-By: Claude Sonnet 4.6 --- terraform/azure_ad/terraform.tfvars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/azure_ad/terraform.tfvars b/terraform/azure_ad/terraform.tfvars index 2dc3f07f..ba80f3bf 100644 --- a/terraform/azure_ad/terraform.tfvars +++ b/terraform/azure_ad/terraform.tfvars @@ -101,7 +101,7 @@ cognitive_services_group = [ # Alekhya Reddy Kommasani, Arkadiusz Komarzewski, Curtis Morales, Wesley Dawson data_sre_group = [ - # "akommasani@mozilla.com", + "akommasani@mozilla.com", "akomarzewski@mozilla.com", "cmorales@mozilla.com", "wdawson@mozilla.com", From 5d8d78e62ce75f9c62e587573dbc9e25b4cb9c34 Mon Sep 17 00:00:00 2001 From: Mark Cornmesser Date: Mon, 4 May 2026 14:59:56 -0700 Subject: [PATCH 4/4] RELOPS-2345: import all role assignments and fix UPNs in azure_ad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix 4 incorrect UPNs in terraform.tfvars (dkirchner, nfurlan, rbaffourawuah, shong — were inferred from display names incorrectly) - Fix azuread v3 breaking change: data "azuread_directory_role" -> resource "azuread_directory_role" for billing_admin in rbac.tf - Fix for_each on service_desk_membership for azuread v3 empty-group workaround - Remove security_engineering group/role assignments — group never existed in Azure; defer to a separate ticket - Import all existing role assignments and ms_store group memberships into Terraform state (plan now shows 0 to add, 19 to change, 0 to destroy — changes are description field updates only) Co-Authored-By: Claude Sonnet 4.6 --- terraform/azure_ad/groups.tf | 23 ++--------------------- terraform/azure_ad/rbac.tf | 21 ++------------------- terraform/azure_ad/tenant_variables.tf | 6 ------ terraform/azure_ad/terraform.tfvars | 13 +++++-------- 4 files changed, 9 insertions(+), 54 deletions(-) diff --git a/terraform/azure_ad/groups.tf b/terraform/azure_ad/groups.tf index c15a42b4..e2092aaa 100644 --- a/terraform/azure_ad/groups.tf +++ b/terraform/azure_ad/groups.tf @@ -162,25 +162,6 @@ resource "azuread_group_member" "firefox_desktop_vms_membership" { member_object_id = each.value.object_id } -# Empty group with active role assignments — verify if intentional -resource "azuread_group" "security_engineering" { - display_name = "Security Engineering" - security_enabled = true - mail_enabled = false - description = "Managed by RelOps — Security Engineering team" -} - -data "azuread_user" "security_engineering_members" { - for_each = toset(var.security_engineering_group) - user_principal_name = each.value -} - -resource "azuread_group_member" "security_engineering_membership" { - for_each = data.azuread_user.security_engineering_members - group_object_id = azuread_group.security_engineering.object_id - member_object_id = each.value.object_id -} - resource "azuread_group" "cognitive_services" { display_name = "Cognitive Services" security_enabled = true @@ -266,9 +247,9 @@ data "azuread_user" "service_desk_members" { } resource "azuread_group_member" "service_desk_membership" { - for_each = data.azuread_user.service_desk_members + for_each = toset(var.service_desk_group) group_object_id = azuread_group.service_desk.object_id - member_object_id = each.value.object_id + member_object_id = data.azuread_user.service_desk_members[each.value].object_id } resource "azuread_group" "webrtc_group" { diff --git a/terraform/azure_ad/rbac.tf b/terraform/azure_ad/rbac.tf index 5a0eddb9..c9bd86e6 100644 --- a/terraform/azure_ad/rbac.tf +++ b/terraform/azure_ad/rbac.tf @@ -109,12 +109,12 @@ resource "azurerm_role_assignment" "relops_contributor" { } # CI Billing — Billing Administrator directory role (tenant-wide) -data "azuread_directory_role" "billing_admin" { +resource "azuread_directory_role" "billing_admin" { display_name = "Billing Administrator" } resource "azuread_directory_role_member" "ci_billing_billing_admin" { - role_object_id = data.azuread_directory_role.billing_admin.object_id + role_object_id = azuread_directory_role.billing_admin.object_id member_object_id = azuread_group.ci_billing.object_id } @@ -181,23 +181,6 @@ resource "azurerm_role_assignment" "tceng_contributor" { principal_id = azuread_group.tceng.object_id } -# Security Engineering — Monitoring Reader on FXCI; Security Reader on FXCI and Trusted FXCI -resource "azurerm_role_assignment" "security_engineering_monitoring_reader" { - scope = "/subscriptions/${var.fxci_devtest_subscription_id}" - role_definition_name = "Monitoring Reader" - principal_id = azuread_group.security_engineering.object_id -} - -resource "azurerm_role_assignment" "security_engineering_security_reader" { - for_each = toset([ - "/subscriptions/${var.fxci_devtest_subscription_id}", - "/subscriptions/${var.trusted_fxci_subscription_id}", - ]) - scope = each.value - role_definition_name = "Security Reader" - principal_id = azuread_group.security_engineering.object_id -} - # Cognitive Services — Contributor, Cognitive Services Contributor, and Custom Vision Contributor on FF Non-CI resource "azurerm_role_assignment" "cognitive_services_roles" { for_each = toset([ diff --git a/terraform/azure_ad/tenant_variables.tf b/terraform/azure_ad/tenant_variables.tf index f00c9567..67ed31a5 100644 --- a/terraform/azure_ad/tenant_variables.tf +++ b/terraform/azure_ad/tenant_variables.tf @@ -84,12 +84,6 @@ variable "firefox_desktop_vms_group" { default = [] } -variable "security_engineering_group" { - description = "List of UPNs for the Security Engineering group membership." - type = list(string) - default = [] -} - variable "cognitive_services_group" { description = "List of UPNs for the Cognitive Services group membership." type = list(string) diff --git a/terraform/azure_ad/terraform.tfvars b/terraform/azure_ad/terraform.tfvars index ba80f3bf..a0c0b7da 100644 --- a/terraform/azure_ad/terraform.tfvars +++ b/terraform/azure_ad/terraform.tfvars @@ -59,7 +59,7 @@ tceng_group = [ infrasec_group = [ "asyed@mozilla.com", "cfoji@mozilla.com", - "dkirchn@mozilla.com", + "dkirchner@mozilla.com", "rpohl@mozilla.com", "sseehra@mozilla.com", ] @@ -91,9 +91,6 @@ firefox_desktop_vms_group = [ "drubino@mozilla.com", ] -# Currently empty in Azure — confirm before adding members -security_engineering_group = [] - # Evgeny Pavlov cognitive_services_group = [ "epavlov@mozilla.com", @@ -110,7 +107,7 @@ data_sre_group = [ # Andreas Wagner, Dimitri Kirchner, Jonathan Moss passkey_poc_group = [ "awagner@mozilla.com", - "dkirchn@mozilla.com", + "dkirchner@mozilla.com", "jmoss@mozilla.com", ] @@ -180,9 +177,9 @@ ms_store_finance_group = [ "mhirose@mozilla.com", "nflorez@mozilla.com", "ndelatorre@mozilla.com", - "nafurlan@mozilla.com", - "rbaffour@mozilla.com", + "nfurlan@mozilla.com", + "rbaffourawuah@mozilla.com", "rtestard@mozilla.com", "rvandermeulen@mozilla.com", - "syhong@mozilla.com", + "shong@mozilla.com", ]