/terraform-azuredevops-federated-service-principal-connection

A module that uses the Azuredevops, AzureRm and AzureAD provider to create a service principal (spn), scope that spn to a subscription with a role of your choice, it then configures OIDC with Azure DevOps on Entra ID and adds that newly created service principal to a Azure DevOps service connection for use. Use script for Azure DevOps Org id 🚀

Primary LanguagePowerShellMIT LicenseMIT

data "azurerm_client_config" "current" {}

data "azurerm_subscription" "current" {}

data "azuredevops_project" "project_id" {
  name = var.azuredevops_project_name
}

locals {
  default_service_principal_name            = var.service_principal_name != null ? var.service_principal_name : "spn-azdo-${var.azuredevops_project_name}-${var.azuredevops_organization_guid}"
  default_service_principal_description     = var.service_principal_description != null ? var.service_principal_description : "This service principal is for the federated credential of Azure DevOps of the project ${var.azuredevops_project_name}, in the organization ${var.azuredevops_organization_name} with guid ${var.azuredevops_organization_guid}"
  default_federated_credential_display_name = var.federated_credential_display_name != null ? var.federated_credential_display_name : "oidc-wlfid-${local.default_service_principal_name}"
}

resource "azuredevops_serviceendpoint_azurerm" "azure_devops_service_endpoint_azurerm" {
  depends_on                             = [azurerm_role_assignment.assign_spn_to_subscription[0]]
  project_id                             = data.azuredevops_project.project_id.id
  service_endpoint_name                  = var.service_principal_name != null ? var.service_principal_name : local.default_service_principal_name
  description                            = var.service_principal_description
  service_endpoint_authentication_scheme = "WorkloadIdentityFederation"

  credentials {
    serviceprincipalid = module.service_principal.application_id["0"]
  }

  azurerm_spn_tenantid      = data.azurerm_client_config.current.tenant_id
  azurerm_subscription_id   = data.azurerm_subscription.current.subscription_id
  azurerm_subscription_name = data.azurerm_subscription.current.display_name
}

module "service_principal" {
  source = "github.com/libre-devops/terraform-azuread-service-principal"

  spns = [
    {
      spn_name                            = var.service_principal_name != null ? var.service_principal_name : local.default_service_principal_name
      description                         = local.default_service_principal_description
      create_corresponding_enterprise_app = true
      create_federated_credential         = true
      federated_credential_display_name   = local.default_federated_credential_display_name
      federated_credential_description    = var.service_principal_description != null ? var.service_principal_description : local.default_federated_credential_display_name
      federated_credential_audiences      = var.federated_credential_audiences
      federated_credential_issuer         = format("https://vstoken.dev.azure.com/%s", var.azuredevops_organization_guid)
      federated_credential_subject        = format("sc://%s/%s/%s", var.azuredevops_organization_name, var.azuredevops_project_name, var.service_principal_name != null ? var.service_principal_name : "spn-azdo-${var.azuredevops_project_name}-${var.azuredevops_organization_guid}")
    }
  ]
}

resource "azurerm_role_assignment" "assign_spn_to_subscription" {
  count                = var.attempt_assign_role_to_spn == true ? 1 : 0
  principal_id         = module.service_principal.enterprise_app_object_id["0"]
  scope                = data.azurerm_subscription.current.id
  role_definition_name = var.role_definition_name_to_assign
}

Requirements

Name Version
azuredevops ~>0.11.0

Providers

Name Version
azuredevops ~>0.11.0
azurerm n/a

Modules

Name Source Version
service_principal github.com/libre-devops/terraform-azuread-service-principal n/a

Resources

Name Type
azuredevops_serviceendpoint_azurerm.azure_devops_service_endpoint_azurerm resource
azurerm_role_assignment.assign_spn_to_subscription resource
azuredevops_project.project_id data source
azurerm_client_config.current data source
azurerm_subscription.current data source

Inputs

Name Description Type Default Required
attempt_assign_role_to_spn Whether or not to attempt to assign a role to the SPN to the subscription. This is actually needed, so defaults to true bool true no
azuredevops_organization_guid The unique ID of your Azure DevOps organisation string n/a yes
azuredevops_organization_name The name of your Azure DevOps organization string n/a yes
azuredevops_project_name The name of your Azure DevOps project you want to configure the federated cred for string n/a yes
federated_credential_audiences The audience for the credential, set to the default for Azure DevOps list(string)
[
"api://AzureADTokenExchange"
]
no
federated_credential_display_name The display name of your federated credential in AzureAD/Entra for ID string null no
role_definition_name_to_assign The role definition needed to setup SPN, for security reasons, defautls to Reader string "Reader" no
service_principal_description The description of the service principal string null no
service_principal_name The name of the service principal string null no

Outputs

Name Description
service_endpoint_id The id of the service endpoint
service_endpoint_name The project name of the service endpoint is made with
service_endpoint_project_id The project id of the service endpoint is made with
service_endpoint_service_principal_id The service principal id service endpoint is made with
service_principal_outputs The outputs from the service principle
workload_identity_federation_issuer The issuer for the workload issuer
workload_identity_federation_subject The subject for the workload federation