Skip to content

Commit

Permalink
feat: grant replicator access on EA
Browse files Browse the repository at this point in the history
  • Loading branch information
Felix Zieger committed Sep 9, 2024
1 parent a69615e commit 212d960
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 10 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Before opening a Pull Request, please do the following:
| Name | Version |
|------|---------|
| <a name="provider_azuread"></a> [azuread](#provider\_azuread) | 2.53.1 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.114.0 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.111.0 |

## Modules

Expand Down Expand Up @@ -208,6 +208,7 @@ Before opening a Pull Request, please do the following:
| <a name="input_additional_required_resource_accesses"></a> [additional\_required\_resource\_accesses](#input\_additional\_required\_resource\_accesses) | Additional AAD-Level Resource Accesses the replicator Service Principal needs. | `list(object({ resource_app_id = string, resource_accesses = list(object({ id = string, type = string })) }))` | `[]` | no |
| <a name="input_application_owners"></a> [application\_owners](#input\_application\_owners) | List of user principals that should be added as owners to the created service principals. | `list(string)` | `[]` | no |
| <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 |
| <a name="input_can_create_subscriptions_in_enterprise_enrollment_account"></a> [can\_create\_subscriptions\_in\_enterprise\_enrollment\_account](#input\_can\_create\_subscriptions\_in\_enterprise\_enrollment\_account) | The billing account and enrollment account for which Service Principal will create subscriptions. | `object({ billing_account_id = string, enrollment_account_id = string })` | `null` | no |
| <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 |
| <a name="input_create_passwords"></a> [create\_passwords](#input\_create\_passwords) | Create passwords for service principals. | `bool` | `true` | no |
| <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 |
Expand Down
11 changes: 6 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ module "replicator_service_principal" {

replicator_rg_enabled = var.replicator_rg_enabled

service_principal_name = var.replicator_service_principal_name
custom_role_scope = data.azurerm_management_group.replicator_custom_role_scope.id
assignment_scopes = local.replicator_assignment_scopes
can_cancel_subscriptions_in_scopes = var.can_cancel_subscriptions_in_scopes
can_delete_rgs_in_scopes = var.can_delete_rgs_in_scopes
service_principal_name = var.replicator_service_principal_name
custom_role_scope = data.azurerm_management_group.replicator_custom_role_scope.id
assignment_scopes = local.replicator_assignment_scopes
can_cancel_subscriptions_in_scopes = var.can_cancel_subscriptions_in_scopes
can_delete_rgs_in_scopes = var.can_delete_rgs_in_scopes
can_create_subscriptions_in_enterprise_enrollment_account = var.can_create_subscriptions_in_enterprise_enrollment_account

additional_required_resource_accesses = var.additional_required_resource_accesses
additional_permissions = var.additional_permissions
Expand Down
7 changes: 5 additions & 2 deletions modules/meshcloud-replicator-service-principal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
| Name | Version |
|------|---------|
| <a name="provider_azuread"></a> [azuread](#provider\_azuread) | 2.53.1 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.114.0 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.111.0 |
| <a name="provider_terraform"></a> [terraform](#provider\_terraform) | n/a |
| <a name="provider_time"></a> [time](#provider\_time) | 0.12.0 |
| <a name="provider_time"></a> [time](#provider\_time) | 0.11.2 |

## Modules

Expand All @@ -40,9 +40,11 @@ No modules.
| [azurerm_role_definition.meshcloud_replicator_rg_deleter](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
| [azurerm_role_definition.meshcloud_replicator_subscription_canceler](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
| [terraform_data.allowed_assignments](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |
| [terraform_data.set_enrollment_account_permission](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |
| [time_rotating.replicator_secret_rotation](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/rotating) | resource |
| [azuread_application_published_app_ids.well_known](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/application_published_app_ids) | data source |
| [azuread_application_template.enterprise_app](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/application_template) | data source |
| [azuread_client_config.current](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/client_config) | data source |
| [azuread_service_principal.msgraph](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/service_principal) | data source |

## Inputs
Expand All @@ -54,6 +56,7 @@ No modules.
| <a name="input_application_owners"></a> [application\_owners](#input\_application\_owners) | List of user principals that should be added as owners to the replicator service principal. | `list(string)` | `[]` | no |
| <a name="input_assignment_scopes"></a> [assignment\_scopes](#input\_assignment\_scopes) | The scopes to which Service Principal permissions is assigned to. List of management group id of form `/providers/Microsoft.Management/managementGroups/<mgmtGroupId>/`. | `list(string)` | n/a | yes |
| <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 |
| <a name="input_can_create_subscriptions_in_enterprise_enrollment_account"></a> [can\_create\_subscriptions\_in\_enterprise\_enrollment\_account](#input\_can\_create\_subscriptions\_in\_enterprise\_enrollment\_account) | The billing account and enrollment account for which Service Principal will create subscriptions. | `object({ billing_account_id = string, enrollment_account_id = string })` | `null` | no |
| <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 |
| <a name="input_create_password"></a> [create\_password](#input\_create\_password) | Create a password for the enterprise application. | `bool` | n/a | yes |
| <a name="input_custom_role_scope"></a> [custom\_role\_scope](#input\_custom\_role\_scope) | The scope to which Service Principal permissions can be assigned to. Usually this is the management group id of form `/providers/Microsoft.Management/managementGroups/<tenantId>` that sits atop the subscriptions. | `string` | n/a | yes |
Expand Down
23 changes: 21 additions & 2 deletions modules/meshcloud-replicator-service-principal/module.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ locals {
}

//---------------------------------------------------------------------------
// Role Definition for the Replicator on the specified Scope
//---------------------------------------------------------------------------
// Role Definition for the Replicator on the specified Scope ---------------------------------------------------------------------------
resource "azurerm_role_definition" "meshcloud_replicator" {
name = "${var.service_principal_name}-base"
scope = var.custom_role_scope
Expand Down Expand Up @@ -238,6 +237,26 @@ resource "azuread_app_role_assignment" "meshcloud_replicator-user" {
depends_on = [azuread_application.meshcloud_replicator]
}

//---------------------------------------------------------------------------
// Assign Enrollment Account Subscription Creator Role to the Enterprise application
//---------------------------------------------------------------------------
data "azuread_client_config" "current" {}

resource "terraform_data" "set_enrollment_account_permission" {
triggers_replace = [uuid()] # The script is idempotent so we run it every time

provisioner "local-exec" {
command = <<COMMAND
.'${path.module}\\set-enrollment-account-permission.ps1'
-principalId '${azuread_service_principal.meshcloud_replicator.object_id}'
-aadTenantId '${data.azuread_client_config.current.tenant_id}'
-billingAccountId '${var.can_create_subscriptions_in_enterprise_enrollment_account.billing_account_id}'
-enrollmentAccountId '${var.can_create_subscriptions_in_enterprise_enrollment_account.enrollment_account_id}'
COMMAND
interpreter = ["PowerShell", "-Command"]
}
}

//---------------------------------------------------------------------------
// Policy Definition for preventing the Application from assigning other privileges to itself
// Assign it to the specified scope
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
param (
[Parameter(Mandatory = $true), HelpMessage="The object ID of the replicator enterprise application"]
[string]
$principalId

[Parameter(Mandatory = $true), HelpMessage="Your AAD tenant id"]
[string]
$aadTenantId

[Parameter(Mandatory = $true), HelpMessage="You can find the billing account id in the Azure portal on the Cost Management + Billing overview page."]
[Int]
$billingAccountId


[Parameter(Mandatory = $true), HelpMessage="You can find the enrollment account id in the Azure portal on the Detail page of your enrollment account."]
[Int]
$enrollmentAccountId
)

# Build the request
$token = (Get-AzAccessToken -ResourceUrl 'https://management.azure.com').Token
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")
$headers.Add("Authorization","Bearer $token")
$billingRoleAssignmentName = (New-Guid).Guid

$url = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$billingAccountId/enrollmentAccounts/$enrollmentAccountId/billingRoleAssignments/$billingRoleAssignmentName`?api-version=2019-10-01-preview"

# Subscription Creator. See https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/assign-roles-azure-service-principals#permissions-that-can-be-assigned-to-the-spn
$roleDefinitionId = "/providers/Microsoft.Billing/billingAccounts/$billingAccountId/enrollmentAccounts/$enrollmentAccountId/billingRoleDefinitions/a0bcee42-bf30-4d1b-926a-48d21664ef71"

$body = "{
`"properties`": {
`"principalId`": `"$principalId`",
`"principalTenantId`": `"$aadTenantId`",
`"roleDefinitionId`": `"$roleDefinitionId`"}`n}"

# Send request
Invoke-RestMethod $url -Method 'Put' -Headers $headers -Body $body | Format-List

# Check that the creation was successfull
Invoke-RestMethod $url -Method 'Get' -Headers $headers | Format-List
6 changes: 6 additions & 0 deletions modules/meshcloud-replicator-service-principal/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,9 @@ variable "application_owners" {
description = "List of user principals that should be added as owners to the replicator service principal."
default = []
}

variable "can_create_subscriptions_in_enterprise_enrollment_account" {
default = null
type = object({ billing_account_id = string, enrollment_account_id = string })
description = "The billing account and enrollment account for which Service Principal will create subscriptions."
}
8 changes: 8 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ variable "can_delete_rgs_in_scopes" {
default = []
}

variable "can_create_subscriptions_in_enterprise_enrollment_account" {
type = object({ billing_account_id = string, enrollment_account_id = string })
description = "The billing account and enrollment account for which Service Principal will create subscriptions."
default = null
}

# Metering inputs

variable "metering_service_principal_name" {
type = string
default = "kraken"
Expand Down

0 comments on commit 212d960

Please sign in to comment.