Skip to content

Commit

Permalink
feat(terraform): simplify for single plan and deploy, #22
Browse files Browse the repository at this point in the history
- key-vault: use RBAC authZ, which has since GA'd
- service connections are set directly from terraform
  instead of indirectly via key vault because:
  - terraform released 'sensitive=true' feature for outputs
  - key vault RBAC propagation can take up to 10 minutes,
    which breaks terraform runs
  • Loading branch information
julie-ng committed Jun 11, 2021
1 parent 2a2ab95 commit c2d3d95
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 299 deletions.
45 changes: 38 additions & 7 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@ resource "azuread_group" "groups" {
prevent_duplicate_names = true
}

# ------------------
# Service Principals
# ------------------

# TODO: document use for CI only. Apps should use diff. SP per PILP

module "service_principals" {
for_each = var.environments
source = "./modules/service-principal"
name = "${each.value.team}-${each.value.env}-${local.suffix}-ci-sp"
}

# ------------------------------
# Resource Groups ("Workspaces")
# ------------------------------

module "arm_environments" {
for_each = var.environments
source = "./modules/azure-resources"
name = "${each.value.team}-${each.value.env}-${local.suffix}"
devs_group_id = azuread_group.groups["${each.value.team}_devs"].id
admins_group_id = azuread_group.groups["${each.value.team}_admins"].id
superadmins_group_id = local.superadmins_aad_object_id
service_principal_id = module.service_principals["${each.value.team}_${each.value.env}"].principal_id
}

# Azure DevOps
# ------------
Expand Down Expand Up @@ -133,13 +158,19 @@ module "workspace" {
}


# Service Connections for ADO
# ---------------------------
# Service Connections
# -------------------

module "service_connections" {
for_each = module.workspace
source = "./modules/azure-devops-service-connection"
service_principal_id = each.value.service_principals[0].application_id
key_vault_name = each.value.key_vault
resource_group_name = each.value.resource_group_name
for_each = module.arm_environments
source = "./modules/azure-devops-service-connection"
service_principal_id = module.service_principals[each.key].principal_id
service_principal_secret = module.service_principals[each.key].client_secret
resource_group_name = "${replace(each.key, "_", "-")}-${local.suffix}-rg"

depends_on = [
azuread_group.groups,
module.arm_environments,
module.service_principals
]
}
48 changes: 21 additions & 27 deletions modules/azure-devops-service-connection/main.tf
Original file line number Diff line number Diff line change
@@ -1,39 +1,33 @@
# 1 - get Service Principal secret from Key Vault

data "azurerm_key_vault" "workspace" {
name = var.key_vault_name
resource_group_name = var.resource_group_name
}

data "azurerm_key_vault_secret" "sp_secret" {
name = local.sp_secret_name
key_vault_id = data.azurerm_key_vault.workspace.id
# --------------------
# Azure DevOps Project
# --------------------
# Determine project name based on resource group name:
# - fruits-dev-*-rg => project-fruits
# - veggies-prod-*-rg => project-veggies
# - infra-shared-*-rg => central-it

locals {
project_name = split("-", var.resource_group_name)[0] == "infra" ? "central-it" : "project-${split("-", var.resource_group_name)[0]}"
}

# 2 - get reference to ADO Project

data "azuredevops_project" "team" {
name = local.project_name
}

# 3 -get Subscription Info

data "azurerm_subscription" "current" {
}

data "azurerm_client_config" "current" {
}

# 4 - finally create Service Connection in ADO project
# ------------------
# Service Connection
# ------------------
data "azurerm_subscription" "current" {}
data "azurerm_client_config" "current" {}

resource "azuredevops_serviceendpoint_azurerm" "workspace_endpoint" {
project_id = data.azuredevops_project.team.id
service_endpoint_name = local.connection_name
credentials {
serviceprincipalid = var.service_principal_id
serviceprincipalkey = data.azurerm_key_vault_secret.sp_secret.value
}
service_endpoint_name = "${var.resource_group_name}-connection"
project_id = data.azuredevops_project.team.id
azurerm_spn_tenantid = data.azurerm_client_config.current.tenant_id
azurerm_subscription_id = data.azurerm_client_config.current.subscription_id
azurerm_subscription_name = data.azurerm_subscription.current.display_name
credentials {
serviceprincipalid = var.service_principal_id
serviceprincipalkey = var.service_principal_secret
}
}
10 changes: 7 additions & 3 deletions modules/azure-devops-service-connection/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
output "service_connection" {
value = azuredevops_serviceendpoint_azurerm.workspace_endpoint
}
output "connection_name" {
value = azuredevops_serviceendpoint_azurerm.workspace_endpoint.service_endpoint_name
}

output "scope" {
value = azuredevops_serviceendpoint_azurerm.workspace_endpoint.resource_group
}
25 changes: 7 additions & 18 deletions modules/azure-devops-service-connection/variables.tf
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
variable "service_principal_id" {
variable "resource_group_name" {
type = string
description = "ID of Service Principal scoped to workspace/environment. The display name of this service principal uses `fruits-dev-XXXX-rg-sp` format, where `X` is a random character."
description = "Name of resource group of this workspace the service principal is scoped to."
}

variable "key_vault_name" {
variable "service_principal_id" {
type = string
description = "Name of Key Vault of this workspace, e.g. `fruits-dev-XXXX-kv`, where `X` is a random character."
description = "Client ID for Service Principal"
}

variable "resource_group_name" {
variable "service_principal_secret" {
type = string
description = "Name of resource group of this workspace, e.g. `fruits-dev-XXXX-rg`, where `X` is a random character."
description = "Client Secret for Service Principal"
sensitive = true
}

locals {
sp_secret_name = "workspace-sp-secret"
connection_name = "${var.resource_group_name}-connection"
project_name = split("-", var.resource_group_name)[0] == "infra" ? "central-it" : "project-${split("-", var.resource_group_name)[0]}"
}

# Note: ADO project names are determined based on Resource Group name patterns:
#
# - fruits-dev-u6t7-rg
# - veggies-prod-u6t7-rg
# - infra-shared-u6t7-rg (breaks convetion)
55 changes: 0 additions & 55 deletions modules/azure-resources/_rbac-key-vault.tf

This file was deleted.

27 changes: 0 additions & 27 deletions modules/azure-resources/_rbac.tf

This file was deleted.

56 changes: 0 additions & 56 deletions modules/azure-resources/_service-principals.tf

This file was deleted.

0 comments on commit c2d3d95

Please sign in to comment.