diff --git a/caf_solution/add-ons/azure_devops_v1/azdo_pipelines.tf b/caf_solution/add-ons/azure_devops_v1/azdo_pipelines.tf index 0af255f4f..e8645c875 100644 --- a/caf_solution/add-ons/azure_devops_v1/azdo_pipelines.tf +++ b/caf_solution/add-ons/azure_devops_v1/azdo_pipelines.tf @@ -16,6 +16,7 @@ resource "azuredevops_build_definition" "build_definition" { azuredevops_variable_group.variable_group[key].id ] + # This block handles repos that are hosted in AZDO dynamic "repository" { for_each = { for key, value in try(data.azuredevops_git_repositories.repos[try(each.value.repo_project_key, each.value.project_key)].repositories, {}) : key => value @@ -27,7 +28,20 @@ resource "azuredevops_build_definition" "build_definition" { repo_type = each.value.repo_type yml_path = each.value.yaml branch_name = lookup(each.value, "branch_name", null) - # service_connection_id = lookup(each.value, "repo_type", null) == "github" ? null : azuredevops_serviceendpoint_azurerm.github[each.value.service_connection_key].id + } + } + + # This block handles repos that are hosted in GitHub and require a service connection + dynamic "repository" { + for_each = each.value.repo_type == "GitHub" ? [1] : [] + + content { + repo_id = each.value.git_repo_name + repo_type = each.value.repo_type + yml_path = each.value.yaml + branch_name = lookup(each.value, "branch_name", null) + service_connection_id = azuredevops_serviceendpoint_github.serviceendpoint_github[ + each.value.service_connection_key].id } } diff --git a/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.github.tf b/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.github.tf new file mode 100644 index 000000000..bfb14dad4 --- /dev/null +++ b/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.github.tf @@ -0,0 +1,31 @@ + +# To support cross subscription +data "external" "github_pat" { + for_each = { + for key, value in var.service_endpoints : key => value + if try(value.type, null) == "Github" + } + + program = [ + "bash", "-c", + format( + "az keyvault secret show --id '%s'secrets/'%s' --query '{value: value}' -o json", + local.remote.keyvaults[each.value.keyvault.lz_key][each.value.keyvault.key].vault_uri, + each.value.keyvault.secret_name + ) + ] +} + +resource "azuredevops_serviceendpoint_github" "serviceendpoint_github" { + for_each = { + for key, value in var.service_endpoints : key => value + if try(value.type, null) == "Github" + } + + project_id = data.azuredevops_project.project[each.value.project_key].id + service_endpoint_name = each.value.endpoint_name + + auth_personal { + personal_access_token = data.external.github_pat[each.key].result.value + } +} diff --git a/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.tf b/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.tf index cf02cac3e..aa5d620aa 100644 --- a/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.tf +++ b/caf_solution/add-ons/azure_devops_v1/azdo_service_endpoint.tf @@ -1,7 +1,11 @@ # To support cross subscription data "external" "client_secret" { - for_each = var.service_endpoints + for_each = { + for key, value in var.service_endpoints : key => value + if try(value.type, "TfsGit") == "TfsGit" + } + program = [ "bash", "-c", format( @@ -13,7 +17,10 @@ data "external" "client_secret" { } resource "azuredevops_serviceendpoint_azurerm" "azure" { - for_each = var.service_endpoints + for_each = { + for key, value in var.service_endpoints : key => value + if try(value.type, "TfsGit") == "TfsGit" + } project_id = data.azuredevops_project.project[each.value.project_key].id service_endpoint_name = each.value.endpoint_name @@ -31,10 +38,13 @@ resource "azuredevops_serviceendpoint_azurerm" "azure" { # resource "azuredevops_resource_authorization" "endpoint" { - for_each = var.service_endpoints + for_each = { + for key, value in var.service_endpoints : key => value + if try(value.type, "TfsGit") == "TfsGit" + } project_id = data.azuredevops_project.project[each.value.project_key].id resource_id = azuredevops_serviceendpoint_azurerm.azure[each.key].id type = "endpoint" authorized = true -} \ No newline at end of file +} diff --git a/caf_solution/add-ons/azure_devops_v1/readme.md b/caf_solution/add-ons/azure_devops_v1/readme.md index 058bb07a6..bfb21d01f 100644 --- a/caf_solution/add-ons/azure_devops_v1/readme.md +++ b/caf_solution/add-ons/azure_devops_v1/readme.md @@ -26,7 +26,55 @@ Azure Devops (example): - sample yaml attached [here](./scenario/200-contoso_demo/pipeline/rover.yaml). Azure: -* PAT Token : PAT Token should be updated in keyvault secret that deployed by launchpad LZ as below +* AZDO PAT Token : PAT Token should be updated in keyvault secret that deployed by launchpad LZ as below +* Github PAT Token : If building from repos hosted in Github, a Github PAT Token should be added to a keyvault secret. + + +## Pipelines +AZDO supports creating pipelines from a number of sources, such as AZDO itself, Github, Bitbucket, +etc. For repos hosted in Github, you must configure a [service connection][https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints]. + +To do this, create a Github PAT token (repo read access is sufficient), and add it to a KeyVault (we +recommend the 'secrets' KeyVault typically provisioned in level0). Then provide the following config +directive to configure the connection: + +``` +service_endpoints = { + github_endpoint = { + endpoint_name = "github_endpoint" + type = "Github" + project_key = "my_project"" + keyvault = { + lz_key = "launchpad" + key = "secrets" + secret_name = "github-pat" + } + } +} +``` + +When configuring pipelines via the pipelines{} config directive, you can then set the following +parameters: + +``` +pipelines = { + launchpad = { + project_key = "my_project" + repo_project_key = "my_project_repo" + name = "launchpad" + folder = "\\configuration\\level0" + yaml = "configuration/dev/pipelines/test.yml" + repo_type = "GitHub" + git_repo_name = "github_org/repo_name" + branch_name = "main" + service_connection_key = "github_endpoint" + variables = { + ... + } + } +} +``` + ![](./documentation/images/pat_token.png)