Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: grant replicator access on EA #48

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) | 4.2.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
4 changes: 2 additions & 2 deletions modules/meshcloud-metering-service-principal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
| 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_time"></a> [time](#provider\_time) | 0.12.0 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 3.111.0 |
| <a name="provider_time"></a> [time](#provider\_time) | 0.11.2 |

## Modules

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
Loading