Open stephan2012 opened 2 years ago
Expected Behaviour Terraform should process the role assignment scope whether it comes from a resource or data.
That's not how this works. You can't expect TF to create a subscription and deploy an RBAC policy to it in the same config. It needs to obtain that information from a data call. Your alias effectively utilised a pseudonym ID which is why you see different values. Keep the RBAC separate to the creation of the subscription
@Lucero7919, thanks for your feedback.
Anyway, I think having two identical identifier with different semantics is at least confusing. Is there any documentation that I missed?
@Lucero7919 This is not an expected behaviour and yes you can expect TF to create a subscription and deploy an RBAC policy. This is how CAF Terraform modules work as well - after the subscription is created they update the token so the subscription is visible by the principle. This means you can deploy anything you want in the same config - it's also called a landing zone vending machine.
@stephan2012 Try
provider "azurerm" {
alias = "asa_dev"
features {}
subscription_id = azurerm_subscription.asa_dev.subscription_id
}
data "azurerm_subscription" "asa_dev" {
provider = azurerm.asa_dev
}
resource "azurerm_role_assignment" "asa_dev" {
scope = data.azurerm_subscription.asa_dev.id
role_definition_name = "Reader"
principal_id = azuread_service_principal.asa_tf_user.id
provider = azurerm.asa_dev
}
I would like to add something here. In Azure, you can actually configure Role Assignments on the Subscription, but also on the Alias. Even better: you will have to set role assignments on the Alias, otherwise other people cannot read the alias. If I create a subscription using Terraform, and my colleague tries to run Terraform on the same code, he will get the following error message:
Error: reading Subscription Alias "REDACTED": subscription.AliasClient#Get: Failure responding to request: StatusCode=401 -- Original Error: autorest/azure: Service returned an error. Status=401 Code="UserNotAuthorized" Message="User does not have access Microsoft.Subscription/aliases/read over scope providers/Microsoft.Subscription/aliases/REDACTED"
This is despite having Reader access on the subscription itself. Using az role assignment create --role "Reader" --scope providers/Microsoft.Subscription/aliases/REDACTED --assignee <COLLEAGUE>
, I can manually create a role assignment on the Alias, which allows my colleague to see the alias.
However, Terraform will not allow you to do that. If you try to create a role assignment on the Alias, it will set it on the Subscription, not on the Alias. This is despite the fact that the subscription id
is the alias.
resource "azurerm_role_assignment" "sub-readers" {
scope = data.azurerm_subscription.sub.id
role_definition_name = "Reader"
principal_id = data.azuread_group.my_group.id
}
❯ terraform state show module.REDACTED-subscription.azurerm_subscription.sub
# module.test-incident1-subscription.azurerm_subscription.sub:
resource "azurerm_subscription" "sub" {
alias = "7c7f69e2-BBBB-BBBB-BBBB-BBBBBBBBBB"
billing_scope_id = "/providers/Microsoft.Billing/billingAccounts/REDACTED/billingProfiles/REDACTED/invoiceSections/REDACTED"
id = "/providers/Microsoft.Subscription/aliases/7c7f69e2-BBBB-BBBB-BBBB-BBBBBBBBBB"
subscription_id = "fac33ee6-AAAA-AAAA-AAAA-AAAAAAAAA"
subscription_name = "REDACTED subscription"
tags = {}
tenant_id = "REDACTED"
}
So I can make Terraform-created subscriptions work with co-workers, but not with the native Terraform azurerm_role_assignment
resource, despite the fact that I just need a simple role assignment. Which seems to be because the scope
parameter is interpolated and not used literally.
@mb-northwave did you find a workaround to that error? I've started getting it and can't get around it!
Hello
I found a workaround for this issue. What we see, is that the data
resource does not contain the alias
reference. The original azurerm_subscription
resource does contain the alias
. Compare the below outputs:
❯ terraform state show module.SUBSCRIPTION.data.azurerm_subscription.sub
# module.SUBSCRIPTION.data.azurerm_subscription.sub:
data "azurerm_subscription" "sub" {
display_name = "My first subscription"
id = "/subscriptions/<SUB_GUID>"
location_placement_id = "Public_2014-09-01"
quota_id = "PayAsYouGo_2014-09-01"
spending_limit = "Off"
state = "Enabled"
subscription_id = "<SUB_GUID>"
tags = {}
tenant_id = "<TENANT_ID>"
}
❯ terraform state show module.SUBSCRIPTION.azurerm_subscription.sub
# module.SUBSCRIPTION.azurerm_subscription.sub:
resource "azurerm_subscription" "sub" {
alias = "<SUB_GUID_OR_ALIAS>"
billing_scope_id = "/providers/Microsoft.Billing/billingAccounts/<ID>/billingProfiles/<ID>invoiceSections<ID>"
id = "/providers/Microsoft.Subscription/aliases/<ALIAS>"
subscription_id = "<SUB_GUID>"
subscription_name = "My first subscription"
tags = {}
tenant_id = "<TENANT_ID>"
}
To work around the problem, I created the following resource:
resource "null_resource" "set_TEAM_as_Alias_Reader" {
provisioner "local-exec" {
command = "az role assignment create --role \"Reader\" --scope \"${azurerm_subscription.sub.id}\" --assignee ${data.azuread_group.myteam.id}"
}
}
Note that this works against the azurerm_subscription
resource, not against the data
field, as the data
field does not contain the alias
itself.
This creates the role assignment on the Alias scope instead of the Subscription scope, and allows my colleagues to use the subscription alias using Terraform.
Another note, that trying to set the role_assignment using the azurerm_role_assignment
resource does not work, as that tries to be cleverer than it should have been. The following code references the resource
, not the data
block, as scope:
resource "azurerm_role_assignment" "sub-readers" {
scope = azurerm_subscription.sub.id
role_definition_name = "Reader"
principal_id = data.azuread_group.my_group.id
}
And that generates the following errors:
╷
│ Error: ID was missing the `enrollmentAccounts` element
│
│ with module.SUBSCRIPTION.azurerm_role_assignment.sub-alias-readers,
│ on modules/AzureSubscriptionMCA/main.tf line 83, in resource "azurerm_role_assignment" "sub-alias-readers":
│ 83: scope = azurerm_subscription.sub.id
│
╵
╷
│ Error: parsing "/providers/Microsoft.Subscription/aliases/<ALIAS>": parsing segment "resourceProvider": expected the segment "Microsoft.Subscription" to be "Microsoft.Management"
│
│ with module.SUBSCRIPTION.azurerm_role_assignment.sub-alias-readers,
│ on modules/AzureSubscriptionMCA/main.tf line 83, in resource "azurerm_role_assignment" "sub-alias-readers":
│ 83: scope = azurerm_subscription.sub.id
│
╵
╷
│ Error: parsing "/providers/Microsoft.Subscription/aliases/<ALIAS>": parsing segment "subscriptions": expected the segment "providers" to be "subscriptions"
│
│ with module.SUBSCRIPTION.azurerm_role_assignment.sub-alias-readers,
│ on modules/AzureSubscriptionMCA/main.tf line 83, in resource "azurerm_role_assignment" "sub-alias-readers":
│ 83: scope = azurerm_subscription.sub.id
│
╵
╷
│ Error: parsing "/providers/Microsoft.Subscription/aliases/<ALIAS>": parsing segment "subscriptions": expected the segment "providers" to be "subscriptions"
│
│ with module.SUBSCRIPTION.azurerm_role_assignment.sub-alias-readers,
│ on modules/AzureSubscriptionMCA/main.tf line 83, in resource "azurerm_role_assignment" "sub-alias-readers":
│ 83: scope = azurerm_subscription.sub.id
│
╵
╷
│ Error: Can not parse "scope" as a resource id: No subscription ID found in: "providers/Microsoft.Subscription/aliases/<ALIAS>"
│
│ with module.SUBSCRIPTION.azurerm_role_assignment.sub-alias-readers,
│ on modules/AzureSubscriptionMCA/main.tf line 83, in resource "azurerm_role_assignment" "sub-alias-readers":
│ 83: scope = azurerm_subscription.sub.id
│
So the azurerm_role_assignment
resource is actively being unhelpful here.
@fleetwoodstack FYI.
Ran into this issue as well... Another workaround is to use the azapi
provider for the role assignment:
resource "azapi_resource" "role_assignment" {
type = "Microsoft.Authorization/roleAssignments@2022-04-01"
name = var.guid
parent_id = azurerm_subscription.sub.id
body = jsonencode({
properties = {
principalId = var.principal_id
roleDefinitionId = "/providers/Microsoft.Authorization/roleDefinitions/${var.role_assignment_id}"
principalType = "User"
}
})
}
I just ran into this issue today, and here is my fix in case anyone needs it:
resource "azurerm_subscription" "subscription" {
subscription_name = var.subscriptionName
billing_scope_id = data.azurerm_billing_mca_account_scope.billingScope.id
}
data "azurerm_subscriptions" "available" {
display_name_contains = var.subscriptionName
depends_on = [
azurerm_subscription.subscription
]
}
resource "azurerm_role_assignment" "SPNOwnership" {
scope = data.azurerm_subscriptions.available.subscriptions[0].id
role_definition_name = "Owner"
principal_id = var.SubscriptionOwnerId
depends_on = [
azurerm_subscription.subscription
]
}
Note: the data provider is azurerm_subscriptions
and the resource provider is azurerm_subscription
.
Note2: This only works if display_name_contains
can return unique subscription names. For example, if you have 2 subscriptions named My subscription
and My subscription - The Return
, and you set display_name_contains = "My subscription"
, both will be returned, and I'm not sure in what order, so taking value 0
may not work.
Looks like https://github.com/hashicorp/terraform-provider-azurerm/pull/20895 has fixed this problem, released in 3.49.0.
This issue still happens in azurerm version 3.96.0
We can use the format function to assign directly to subscription_id
instead of the alias.
resource "azurerm_subscription" "subscription_1" {
alias = "00000000-0000-0000-0000-000000000000"
subscription_name = "Subscription 1"
subscription_id = "00000000-0000-0000-0000-000000000000"
}
resource "azurerm_role_assignment" "user_1" {
scope = format(
"/subscriptions/%s",
azurerm_subscription.subscription_1.subscription_id
)
role_definition_name = "Contributor"
principal_id = azuread_user.user_1.id
}
Community Note
Terraform (and AzureRM Provider) Version
Affected Resource(s)
azurerm_subscription
azurerm_role_assignment
Terraform Configuration Files
Debug Output
Panic Output
N/A
Expected Behaviour
Terraform should process the role assignment scope whether it comes from a resource or data.
Actual Behaviour
Execution of the above configuration code failed:
However, adding a data source (yielding the very same information) and refering to it in the role assignment makes things work:
A closer look to the
id
shows different values forresource.azurerm_subscription..id
(alias,/providers/Microsoft.Subscription/aliases/asa-dev
) anddata.azurerm_subscription..id
(actual id,/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
).Steps to Reproduce
terraform apply
Important Factoids
N/A
References
N/A
0000