](https://asciinema.org/a/omOkMnM3tHr4HN7ycNiaEsuws)
Configuration
Enterprise Account Preparation
- create a new Account under the Billing Account for each tenant
- for continohq, the owner email must be under @contino.io
- for squad0 , the owner email must be @squad0.onmicrosoft.com
Service Principal and Enrolment Role Assignment
- Create Service Principal script
- create service principal
- create app
- retrieve objectId for create applications
- assign SP to the enrolment account
PrimaryProduction & Platform continohq| |
|---|
|
|---|
as continohq global_administrotor using a user account
- create new account with owner email @contino.io
we can now create and associate service principal
- create
ea_continohq_sp.sh
export body=$(cat <<EOF
{
"properties": {
"principalId": "ea1dc3e5-01c6-4c4f-9fae-9ca7fe80dd66",
"principalTenantId": "538cf6fd-f5d4-4451-8e4a-88c34f2f2619",
"roleDefinitionId": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/311200/billingRoleDefinitions/a0bcee42-bf30-4d1b-926a-48d21664ef71"
}
}
EOF)
az ad sp create-for-rbac --name {principalname} --role Owner --scope /
az ad sp credential reset --id 1c3fba73-1ed3-4e86-91f2-a3eff03b148d --query 'password' -o tsv
az rest --method put --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/311200/billingRoleAssignments/9dad08c2-69a3-4d47-85bd-1cdba1408402?api-version=2019-10-01-preview" --body "${body}"
ensure to generate a new valid GUID to replace 9dad08c2-69a3-4d47-85bd-1cdba1408402 zas this is the “name” odf your role assignment
output
{
"id": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340292/billingRoleAssignments/9dfd08c2-69a3-4d47-85bd-1cdba1408402",
"name": "9dfd08c2-69a3-4d47-85bd-1cdba1408402",
"properties": {
"createdByPrincipalId": "93c688a9-1dc1-455e-8659-a87167beee7e",
"createdByPrincipalPuid": "100320029C35282E",
"createdByPrincipalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"createdByUserEmailAddress": "adm-pau.kelleher@squad0.onmicrosoft.com",
"createdOn": "2023-05-05T12:51:43.0011832+00:00",
"modifiedByPrincipalId": "93c688a9-1dc1-455e-8659-a87167beee7e",
"modifiedByPrincipalPuid": "100320029C35282E",
"modifiedByPrincipalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"modifiedByUserEmailAddress": "adm-pau.kelleher@squad0.onmicrosoft.com",
"modifiedOn": "2023-05-05T12:51:43.0011868+00:00",
"principalId": "142a88cc-1cfa-47c7-b8c3-a85f7da33041",
"principalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"roleDefinitionId": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340292/billingRoleDefinitions/a0bcee42-bf30-4d1b-926a-48d21664ef71",
"scope": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340292",
"userAuthenticationType": "Organization"
},
"type": "Microsoft.Billing/billingRoleAssignments"
}
SecondaryInternal Engineering squad0 | |
|---|
|
|---|
as continohq global_administrotor using a user account
- create new account
we can now create and associate service princ
- create
ea_squad0_sp.sh
export body=$(cat <<EOF
{
"properties": {
"principalId": "63a6ec65-074f-47c0-824e-54d178d5e00a",
"principalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"roleDefinitionId": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/311200/billingRoleDefinitions/a0bcee42-bf30-4d1b-926a-48d21664ef71"
}
}
EOF)
az rest --method put --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340492/billingRoleAssignments/9dad08c3-69a3-4d47-85bd-1cdba1408402?api-version=2019-10-01-preview" --body "${body}"
ensure to generate a new valid GUID to replace 9dad08c2-69a3-4d47-85bd-1cdba1408402 zas this is the “name” odf your role assignment
output
{
"id": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340292/billingRoleAssignments/9dfd08c2-69a3-4d47-85bd-1cdba1408402",
"name": "9dfd08c2-69a3-4d47-85bd-1cdba1408402",
"properties": {
"createdByPrincipalId": "93c688a9-1dc1-455e-8659-a87167beee7e",
"createdByPrincipalPuid": "100320029C35282E",
"createdByPrincipalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"createdByUserEmailAddress": "adm-pau.kelleher@squad0.onmicrosoft.com",
"createdOn": "2023-05-05T12:51:43.0011832+00:00",
"modifiedByPrincipalId": "93c688a9-1dc1-455e-8659-a87167beee7e",
"modifiedByPrincipalPuid": "100320029C35282E",
"modifiedByPrincipalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"modifiedByUserEmailAddress": "adm-pau.kelleher@squad0.onmicrosoft.com",
"modifiedOn": "2023-05-05T12:51:43.0011868+00:00",
"principalId": "142a88cc-1cfa-47c7-b8c3-a85f7da33041",
"principalTenantId": "2fc87606-f7b2-4dc1-81a0-71e4dd53584d",
"roleDefinitionId": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340292/billingRoleDefinitions/a0bcee42-bf30-4d1b-926a-48d21664ef71",
"scope": "/providers/Microsoft.Billing/billingAccounts/87561154/enrollmentAccounts/340292",
"userAuthenticationType": "Organization"
},
"type": "Microsoft.Billing/billingRoleAssignments"
}
AAD Configuration
Providers
Once the configuration has been completed, we can create the providers for terraform to start deploying subscriptions
provider "azurerm" {
features {}
skip_provider_registration = false
storage_use_azuread = true
tenant_id = "2fc87606-f7b2-4dc1-81a0-71e4dd53584d"
client_id = "b8878837-d11b-4e42-ab2b-a84f0e838875"
client_secret= ""
subscription_id="8d6ed91d-a8e7-4171-a72b-42fd57075f9c"
alias="contino"
}
provider "azuread" {
tenant_id = "2fc87606-f7b2-4dc1-81a0-71e4dd53584d"
client_id = "b8878837-d11b-4e42-ab2b-a84f0e838875"
client_secret= ""
}
provider "github" {
token = var.org_gh_token
owner = "contino" # workaround due to not having perms to create in contino!
}
provider "azurerm" {
features {}
skip_provider_registration = false
storage_use_azuread = true
#tenant_id = "2fc87606-f7b2-4dc1-81a0-71e4dd53584d"
#client_id = "b8878837-d11b-4e42-ab2b-a84f0e838875"
#client_secret= "hf68Q~2OAq.S1jlOiM~Xn7jjNrfa-4ayccCPXc~S"
#subscription_id="8d6ed91d-a8e7-4171-a72b-42fd57075f9c"
alias="s0"
}
provider "azuread" {
tenant_id = "2fc87606-f7b2-4dc1-81a0-71e4dd53584d"
client_id = "b8878837-d11b-4e42-ab2b-a84f0e838875"
client_secret= ""
}
provider "github" {
token = var.org_gh_token
owner = "contino" # workaround due to not having perms to create in contino!
}
Compile and Process config.json files
locals {
json_files = fileset(path.module, "subscription_configurations/*json")
json_data = [ for f in local.json_files : jsondecode(file("${f}")) ]
user_list = distinct([ for f in local.json_data : f.email ] )
squad0_users = distinct(local.user_list)
}
Computed continohq->squad0 tenant accounts tf module
So that users can access the squad0 resources using their continohq tenant account, a de-deplicated list of valid users is generated from the available configuration files
- If the user already exists, we do not re-add
- if the user no longer has any resources, so drops from the list, the guest account in squad0 is removed
- if the user is new, we automatically invite the user, accept the invite and assign them appropriate roles under the squad0 tenant
module "squad0_users" {
providers = {
azurerm.s0=azurerm.s0
azurerm.contino=azurerm.contino
azuread.s0=azuread.s0
azuread.contino=azuread.contino
}
source = "./modules/aad_create_guest_users"
count = length(local.squad0_users)
user_email = local.squad0_users[count.index]
}
EA Subscription Deployment tf module
Optional Components Install
Azure Subscription Budget true | false
Automatically, we add a budget of 60GBP onto then subscription with pre-configured email alerts to the subscription and practice owner for exceeding.
The budget can be manually changed by users
Subscription Level Automation Service Principal "" | "new" | "existing_sp"
"" - leaving the setting blank is a noop
new - Most users will require a service principal at some point, so we can automatically create a new service principal and assign it the Owner role over the EA Subscription - itr will not be able to register new apps or service principals as it will be assigned only Reader role on AD
"existing - Any role specified that exists will have the details retrieved and used but the subscription owner must also own that service principal
GitHub IaC Repository "" | "new" |"<existing_repo_url>"
"" - leaving the setting blank is a noop
new - we create a new repository under a github org depending on the target tenant
using tenant contino implies that the deployment is considered business applicable and as such uses
GitHub org
continoworkload
production[ms-azr-017p]
using squad0 tenant implies any non-production usage and uses
GitHub org
contino-squad0Workload
Devtest[ms-azr-0148p] [Enterprise DevTest]
"existing" - Any role specified that exists will have the details retrieved and used but the subscription owner must also own that service principal
module "azurerm_ea_subscription" {
source = "./modules/ea_subscription_vending_multitennant"
for_each = { for f in local.json_data : f.subscription_name => f }
providers = {
azurerm.s0=azurerm.s0
azurerm.contino=azurerm.contino
azurerm.continovend=azurerm.continovend
azuread.s0=azuread.s0
azuread.contino=azuread.contino
}
tenant = each.value.tenant
owner = each.value.owner
purpose = each.value.purpose
email = each.value.email
alias = each.value.alias
subscription_name = each.value.subscription_name
workload = each.value.workload
apply_budget = each.value.apply_budget
service_principal_name = each.value.service_principal_name
github_username = each.value.github_username
github_repository = each.value.github_repository
enrollment_account = each.value.enrollment_account
depends_on = [module.squad0_users]
}

