diff --git a/modules/app_registration/app_registration.tf b/modules/app_registration/app_registration.tf new file mode 100644 index 0000000..3e3ea75 --- /dev/null +++ b/modules/app_registration/app_registration.tf @@ -0,0 +1,129 @@ +data "azuread_client_config" "current" { + provider = var.destination == "external" ? azuread.external : azuread.internal +} + +data "azuread_application_published_app_ids" "well_known" { + provider = azuread.entra +} + +resource "random_uuid" "oauth2_permission_scope_uuid" {} + +resource "random_uuid" "read_app_role_uuid" {} + +resource "random_uuid" "write_app_role_uuid" {} + +resource "azuread_application" "app_registration" { + provider = azuread.entra + display_name = module.environment.app_reg_name + owners = [data.azuread_client_config.current.object_id] + sign_in_audience = "AzureADMyOrg" + + api { + requested_access_token_version = 2 + + dynamic "oauth2_permission_scope" { + for_each = var.oauth2_permission_scopes != null ? var.oauth2_permission_scopes : [] + iterator = oauth2_permission_scope + content { + admin_consent_description = oauth2_permission_scope.value.admin_consent_description + admin_consent_display_name = oauth2_permission_scope.value.admin_consent_display_name + enabled = oauth2_permission_scope.value.enabled + id = oauth2_permission_scope.value.id + type = oauth2_permission_scope.value.type + user_consent_description = oauth2_permission_scope.value.user_consent_description + user_consent_display_name = oauth2_perimission_scope.value.user_consent_display_name + value = oauth2_perimission_scope.value.value + } + } + } + + dynamic "app_role" { + for_each = var.app_roles != null ? var.app_roles : [] + iterator = app_role + content { + allowed_member_types = app_role.value.allowed_member_types + description = app_role.value.description + display_name = app_role.value.display_name + enabled = app_role.value.enabled + id = app_role.value.id + value = app_role.value.value + } + } + + required_resource_access { + resource_app_id = data.azuread_application_published_app_ids.well_known.result["MicrosoftGraph"] + + resource_access { + id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # email + type = "Scope" + } + + resource_access { + id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # openid + type = "Scope" + } + + resource_access { + id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # profile + type = "Scope" + } + + resource_access { + id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d" # User.Read + type = "Role" + } + + dynamic "resource_access" { + for_each = var.additional_resource_access != null ? var.additional_resource_access : [] + iterator = resource_access + content { + id = resource_access.value.id + type = resource_access.value.type + } + } + } + + single_page_application { + redirect_uris = var.redirect_uris != null ? var.redirect_uris : [] + } + + web { + implicit_grant { + access_token_issuance_enabled = var.access_token_issuance_enabled != null ? var.access_token_issuance_enabled : false + id_token_issuance_enabled = var.id_token_issuance_enabled != null ? var.id_token_issuance_enabled : false + } + } + + lifecycle { + ignore_changes = [ + identifier_uris, password + ] + } +} + +resource "azuread_application_identifier_uri" "app_registration_identifier_uri" { + count = var.enable_identifier_uri != null ? 1 : 0 + provider = azuread.entra + application_id = azuread_application.app_registration.id + identifier_uri = "api://${azuread_application.app_registration.client_id}" +} + +resource "azuread_application_federated_identity_credential" "github_actions_federated_identity_credential" { + count = var.federated_identity_credential != null ? 1 : 0 + provider = azuread.entra + application_id = azuread_application.app_registration.id + display_name = "github-actions" + description = "Deployments for flying repo" + audiences = ["api://AzureADTokenExchange"] + issuer = "https://token.actions.githubusercontent.com" + subject = module.environment.app_reg_federated_identity_credential_subject +} + +resource "azuread_application_password" "app_registration_secret" { + count = var.secret != null ? 1 : 0 + provider = azuread.entra + application_id = azuread_application.app_registration.id + display_name = var.secret.display_name + end_date = var.secret.end_date != null ? var.secret.end_date : null +} + diff --git a/modules/app_registration/outputs.tf b/modules/app_registration/outputs.tf new file mode 100644 index 0000000..faba468 --- /dev/null +++ b/modules/app_registration/outputs.tf @@ -0,0 +1,3 @@ +output "app_registration_secret" { + value = azuread_application_password.app_registration_secret.value +} \ No newline at end of file diff --git a/modules/app_registration/terraform.tf b/modules/app_registration/terraform.tf new file mode 100644 index 0000000..8d26876 --- /dev/null +++ b/modules/app_registration/terraform.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + azuread = { + source = "hashicorp/azuread" + configuration_aliases = [ entra ] + } + } +} \ No newline at end of file diff --git a/modules/app_registration/variables.tf b/modules/app_registration/variables.tf new file mode 100644 index 0000000..8f3320e --- /dev/null +++ b/modules/app_registration/variables.tf @@ -0,0 +1,88 @@ +variable "access_token_issuance_enabled" { + type = optional(bool) +} + +variable "id_token_issuance_enabled" { + type = optional(bool) +} + +variable "additional_resource_access" { + type = optional(list(object({ + id = string + type = string + }))) +} + +variable "app_roles" { + type = optional(list(object({ + allowed_member_types = list(string) + description = string + display_name = string + enabled = bool + id = string + value = string + }))) +} + +variable "app_reg_name" { + type = string +} + +variable "azuread_provider_alias" { + type = string +} + +variable "client_id" { + type = optional(string) +} + +variable "client_secret" { + sensitive = true + type = opitonal(string) +} + +variable "destination" { + type = string +} + +variable "federated_identity_credential" { + type = optional(object({ + display_name = string + description = string + audiences = list(string) + issuer = string + subject = string + })) +} + +variable "enable_identifier_uri" { + type = bool +} + +variable "oauth2_permission_scopes" { + type = optional(list(object({ + admin_consent_description = string + admin_consent_display_name = string + enabled = bool + id = string + type = string + user_consent_description = string + user_consent_display_name = string + value = string + }))) +} + +variable "secret" { + type = optional(object({ + display_name = string + end_date = optional(string) + })) +} + +variable "redirect_uris" { + type = optional(list(string)) +} + +variable "tenant_id" { + type = string +} \ No newline at end of file