Skip to content

Commit 2540658

Browse files
committed
feat: multiple mca service principals
1 parent 743d44f commit 2540658

File tree

7 files changed

+40
-48
lines changed

7 files changed

+40
-48
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [v0.8.0]
11+
12+
### Changed
13+
14+
- Multiple MCA service principals support
15+
1016
## [v0.7.0]
1117

1218
### Added

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ To run this module, you need the following:
8585

8686
- Ensure you have permissions in the source AAD Tenant for granting access to the billing account used for subscription creation using the `Account Administrator` role
8787

88-
**Create an MCA service principal**:
88+
**Create MCA service principals**:
89+
90+
> With this module, you can create multiple MCA service principals by passing a list of `mca.service_principal_names`. This is useful for environments with restricted acceses to the AAD tenant holding the MCA license.
8991
9092
Add an `mca` block when calling this module.
9193

@@ -97,17 +99,14 @@ module "meshplatform" {
9799
# required inputs
98100
99101
mca = {
100-
source_tenant = "<aad-tenant-id>"
101-
service_principal_name = "your-mca-sp-name"
102-
billing_account_name = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_xxxx-xx-xx"
103-
billing_profile_name = "xxxx-xxxx-xxx-xxx"
104-
invoice_section_name = "xxxx-xxxx-xxx-xxx"
102+
service_principal_names = ["your-mca-sp-name-1", "your-mca-sp-name-2", "..."]
103+
billing_account_name = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_xxxx-xx-xx"
104+
billing_profile_name = "xxxx-xxxx-xxx-xxx"
105+
invoice_section_name = "xxxx-xxxx-xxx-xxx"
105106
}
106107
}
107108
```
108109

109-
> note that the source_tenant is the tenant ID of the AAD with the billing account in which you can create subscriptions. This module supports creating MCA and Replicator service principals in different AAD tenants.
110-
111110
### Using Pre-provisioned Subscriptions
112111

113112
meshStack will need to be able to read subscriptions at the source location
@@ -197,7 +196,7 @@ Before opening a Pull Request, please do the following:
197196
| <a name="input_can_cancel_subscriptions_in_scopes"></a> [can\_cancel\_subscriptions\_in\_scopes](#input\_can\_cancel\_subscriptions\_in\_scopes) | The scopes to which Service Principal cancel subscription permission is assigned to. List of management group id of form `/providers/Microsoft.Management/managementGroups/<mgmtGroupId>/`. | `list(string)` | `[]` | no |
198197
| <a name="input_can_delete_rgs_in_scopes"></a> [can\_delete\_rgs\_in\_scopes](#input\_can\_delete\_rgs\_in\_scopes) | The scopes to which Service Principal delete resource group permission is assigned to. Only relevant when `replicator_rg_enabled`. List of subscription scopes of form `/subscriptions/<subscriptionId>`. | `list(string)` | `[]` | no |
199198
| <a name="input_create_passwords"></a> [create\_passwords](#input\_create\_passwords) | Create passwords for service principals. | `bool` | `true` | no |
200-
| <a name="input_mca"></a> [mca](#input\_mca) | n/a | <pre>object({<br> source_tenant = string<br> service_principal_name = string<br> billing_account_name = string<br> billing_profile_name = string<br> invoice_section_name = string<br> })</pre> | `null` | no |
199+
| <a name="input_mca"></a> [mca](#input\_mca) | n/a | <pre>object({<br> service_principal_names = list(string)<br> billing_account_name = string<br> billing_profile_name = string<br> invoice_section_name = string<br> })</pre> | `null` | no |
201200
| <a name="input_metering_assignment_scopes"></a> [metering\_assignment\_scopes](#input\_metering\_assignment\_scopes) | Names or UUIDs of the Management Groups that kraken should collect costs for. | `list(string)` | n/a | yes |
202201
| <a name="input_metering_enabled"></a> [metering\_enabled](#input\_metering\_enabled) | Whether to create Metering Service Principal or not. | `bool` | `true` | no |
203202
| <a name="input_metering_service_principal_name"></a> [metering\_service\_principal\_name](#input\_metering\_service\_principal\_name) | Service principal for collecting cost data. Kraken ist the name of the meshStack component. Name must be unique per Entra ID. | `string` | `"kraken"` | no |

main.tf

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,6 @@ terraform {
1616
}
1717
}
1818

19-
provider "azapi" {
20-
alias = "azapi_mca_source"
21-
tenant_id = var.mca.source_tenant
22-
skip_provider_registration = true
23-
}
24-
provider "azuread" {
25-
alias = "azuread_mca_source"
26-
tenant_id = var.mca.source_tenant
27-
}
28-
provider "azurerm" {
29-
features {}
30-
alias = "azurerm_mca_source"
31-
tenant_id = var.mca.source_tenant
32-
skip_provider_registration = true
33-
}
34-
3519
data "azurerm_management_group" "replicator_custom_role_scope" {
3620
name = var.replicator_custom_role_scope
3721
}
@@ -88,16 +72,10 @@ module "replicator_service_principal" {
8872
}
8973

9074
module "mca_service_principal" {
91-
providers = {
92-
azapi = azapi.azapi_mca_source
93-
azurerm = azurerm.azurerm_mca_source
94-
azuread = azuread.azuread_mca_source
95-
}
96-
9775
count = var.mca != null ? 1 : 0
9876
source = "./modules/meshcloud-mca-service-principal"
9977

100-
service_principal_name = var.mca.service_principal_name
78+
service_principal_names = var.mca.service_principal_names
10179

10280
billing_account_name = var.mca.billing_account_name
10381
billing_profile_name = var.mca.billing_profile_name

modules/meshcloud-mca-service-principal/module.tf

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ data "azurerm_billing_mca_account_scope" "mca" {
2828
}
2929

3030
resource "azuread_application" "mca" {
31-
display_name = var.service_principal_name
31+
for_each = toset(var.service_principal_names)
32+
display_name = each.key
3233
}
3334

3435
resource "azuread_service_principal" "mca" {
35-
client_id = azuread_application.mca.client_id
36+
for_each = toset(var.service_principal_names)
37+
client_id = azuread_application.mca[each.key].client_id
3638
}
3739

3840
data "azapi_resource_list" "billing_role_definitions" {
@@ -49,6 +51,8 @@ locals {
4951
}
5052

5153
resource "azapi_resource_action" "add_role_assignment_subscription_creator" {
54+
for_each = toset(var.service_principal_names)
55+
5256
type = "Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections@2019-10-01-preview"
5357
resource_id = data.azurerm_billing_mca_account_scope.mca.id
5458
action = "createBillingRoleAssignment"
@@ -57,15 +61,17 @@ resource "azapi_resource_action" "add_role_assignment_subscription_creator" {
5761
response_export_values = ["*"]
5862
body = jsonencode({
5963
properties = {
60-
principalId = azuread_service_principal.mca.object_id
64+
principalId = azuread_service_principal.mca[each.key].object_id
6165
roleDefinitionId = local.azure_subscription_creator_role_id
6266
}
6367
})
6468
}
6569

6670
resource "azapi_resource_action" "remove_role_assignment_subscription_creator" {
71+
for_each = toset(var.service_principal_names)
72+
6773
type = "Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/billingRoleAssignments@2019-10-01-preview"
68-
resource_id = jsondecode(azapi_resource_action.add_role_assignment_subscription_creator.output).id
74+
resource_id = jsondecode(azapi_resource_action.add_role_assignment_subscription_creator[each.key].output).id
6975
method = "DELETE"
7076
when = "destroy"
7177
}
@@ -78,7 +84,9 @@ resource "time_rotating" "mca_secret_rotation" {
7884
}
7985

8086
resource "azuread_application_password" "mca" {
81-
application_id = azuread_application.mca.id
87+
for_each = toset(var.service_principal_names)
88+
89+
application_id = azuread_application.mca[each.key].id
8290
rotate_when_changed = {
8391
rotation = time_rotating.mca_secret_rotation.id
8492
}

modules/meshcloud-mca-service-principal/outputs.tf

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@ output "billing_scope" {
55
output "credentials" {
66
description = "Service Principal application id and object id"
77
value = {
8-
Enterprise_Application_Object_ID = azuread_service_principal.mca.id
9-
Application_Client_ID = azuread_application.mca.client_id
10-
Client_Secret = "Execute `terraform output mca_service_principal_password` to see the password"
8+
for name in var.service_principal_names : name => {
9+
Enterprise_Application_Object_ID = azuread_service_principal.mca[name].object_id
10+
Application_Client_ID = azuread_application.mca[name].client_id
11+
Client_Secret = "Execute `terraform output mca_service_principal_password` to see the password"
12+
}
1113
}
1214
}
1315

1416
output "application_client_secret" {
1517
description = "Client Secret Of the Application."
16-
value = azuread_application_password.mca.value
18+
value = { for name in var.service_principal_names : name => azuread_application_password.mca[name].value }
1719
sensitive = true
1820
}
1921

modules/meshcloud-mca-service-principal/variables.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
variable "service_principal_name" {
2-
type = string
1+
variable "service_principal_names" {
2+
type = list(string)
33
}
44

55
variable "billing_account_name" {

variables.tf

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,10 @@ variable "workload_identity_federation" {
107107

108108
variable "mca" {
109109
type = object({
110-
source_tenant = string
111-
service_principal_name = string
112-
billing_account_name = string
113-
billing_profile_name = string
114-
invoice_section_name = string
110+
service_principal_names = list(string)
111+
billing_account_name = string
112+
billing_profile_name = string
113+
invoice_section_name = string
115114
})
116115
default = null
117116
}

0 commit comments

Comments
 (0)