Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changes/unreleased/changed-20251223-145359.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: changed
body: Extended powerplatform_enterprise_policy resource to support Identity policy type
time: 2025-12-23T14:53:59.263648543Z
custom:
Issue: "917"
3 changes: 3 additions & 0 deletions .terraformrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ provider_installation {

# If GOBIN env is different from /go/bin, change it to the GOBIN value.
# If GOBIN is not set, and GOPATH is different from /go/bin, change it to ${GOPATH}/bin
# to add additional local binaries read this doc: https://developer.hashicorp.com/terraform/cli/config/config-file#locations
# and use:
# `export TF_CLI_CONFIG_FILE=/workspaces/terraform-provider-power-platform/.terraformrc`
dev_overrides {
"registry.terraform.io/microsoft/power-platform" = "${GOPATH}/bin"
}
Expand Down
32 changes: 25 additions & 7 deletions docs/resources/enterprise_policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,23 @@ resource "powerplatform_managed_environment" "managed_development" {
suppress_validation_emails = true
}

// module that creates all azure resources required for the identity policy and the policy itself
module "identity" {
source = "./identity"

should_register_provider = false

//Entra Object ID for administrator user that will configure Azure Synapse Link using Managed Identity
policy_reader_object_id = "00000000-0000-0000-0000-000000000000"

environment_id = powerplatform_environment.example_environment.id

resource_group_name = "rg_example_identity"
resource_group_location = local.europe_location[0].azure_regions[0]

enterprise_policy_name = "ep_example_identity_policy"
enterprise_policy_location = local.europe_location[0].name
}

// module that creates all azure resources required for the network injection policy and the policy itself
module "network_injection" {
Expand All @@ -90,6 +107,8 @@ module "network_injection" {
vnet_locations = local.europe_location[0].azure_regions
enterprise_policy_name = "ep_example_network_injection_policy"
enterprise_policy_location = local.europe_location[0].name
// let's wait for first policy to be executed
depends_on = [module.identity]
}

// module that creates all azure resources required for the encryption policy and the policy itself
Expand All @@ -100,14 +119,13 @@ module "encryption" {

environment_id = powerplatform_environment.example_environment.id

resource_group_name = "rg_example_encryption_policy8"
resource_group_name = "rg_example_encryption_policy"
resource_group_location = local.europe_location[0].azure_regions[0]
enterprise_policy_name = "ep_example_encryption_policy8"
enterprise_policy_name = "ep_example_encryption_policy"
enterprise_policy_location = "europe"
keyvault_name = "kv-ep-example8"

// let's wait for first policy to be executed
depends_on = [powerplatform_enterprise_policy.network_injection]
keyvault_name = "kv-ep-example"
// let's wait for second policy to be executed
depends_on = [module.network_injection]
}
```

Expand All @@ -117,7 +135,7 @@ module "encryption" {
### Required

- `environment_id` (String) Environment id
- `policy_type` (String) Policy type [NetworkInjection, Encryption]
- `policy_type` (String) Policy type [NetworkInjection, Encryption, Identity]
- `system_id` (String) Policy SystemId value in following format `/regions/<location>/providers/Microsoft.PowerPlatform/enterprisePolicies/<policyid>`

### Optional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
terraform {
required_version = "> 1.7.0"
required_providers {
powerplatform = {
source = "microsoft/power-platform"
version = "~>4.0"
}
azapi = {
source = "azure/azapi"
source = "azure/azapi"
version = "~>2.0"
}
azurerm = {
source = "hashicorp/azurerm"
source = "hashicorp/azurerm"
version = "~>4.8"
}
}
}
Expand Down
124 changes: 124 additions & 0 deletions examples/resources/powerplatform_enterprise_policy/identity/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
terraform {
required_version = "> 1.7.0"
required_providers {
powerplatform = {
source = "microsoft/power-platform"
version = "~>4.0"
}
azapi = {
source = "azure/azapi"
version = "~>2.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~>4.8"
}
}
}


variable "environment_id" {
description = "The ID of the environment"
type = string
validation {
condition = length(var.environment_id) > 0
error_message = "The environment ID must not be empty"
}
}

variable "should_register_provider" {
description = "A flag to determine if the PowerPlatform provider should be registered in the subscription"
type = bool
default = true
}

variable "resource_group_name" {
description = "The name of the resource group"
type = string
validation {
condition = length(var.resource_group_name) > 0
error_message = "The resource group name must not be empty"
}
}

variable "resource_group_location" {
description = "The location of the resource group"
type = string
validation {
condition = length(var.resource_group_location) > 0
error_message = "The resource group location must not be empty"
}
}

variable "enterprise_policy_name" {
description = "The name of the enterprise policy"
type = string
validation {
condition = length(var.enterprise_policy_name) > 0
error_message = "The enterprise policy name must not be empty"
}
}

variable "enterprise_policy_location" {
description = "The location of the enterprise policy"
type = string
validation {
condition = length(var.enterprise_policy_location) > 0
error_message = "The enterprise policy location must not be empty"
}
}

variable "policy_reader_object_id" {
description = "The object ID of the user to assign the Reader role to (needed to finish the setup of the Azure Synapse Link to Dataverse)"
type = string
validation {
condition = length(var.policy_reader_object_id) > 0
error_message = "The policy reader object ID must not be empty"
}
}

resource "azurerm_resource_group" "resource_group" {
name = var.resource_group_name
location = var.resource_group_location
}

resource "azurerm_resource_provider_registration" "provider_registration" {
count = var.should_register_provider ? 1 : 0
name = "Microsoft.PowerPlatform"
}

resource "azurerm_role_assignment" "policy_reader" {
scope = azapi_resource.powerplatform_policy.id
role_definition_name = "Reader"
principal_id = var.policy_reader_object_id
}

resource "azapi_resource" "powerplatform_policy" {
schema_validation_enabled = false

type = "Microsoft.PowerPlatform/enterprisePolicies@2020-10-30-preview"
name = var.enterprise_policy_name
location = var.enterprise_policy_location
parent_id = azurerm_resource_group.resource_group.id
body = {
identity = {
type = "SystemAssigned"
}
kind = "Identity"
}
}

resource "powerplatform_enterprise_policy" "identity_policy" {
environment_id = var.environment_id
system_id = azapi_resource.powerplatform_policy.output.properties.systemId
policy_type = "Identity"
}

output "enterprise_policy_system_id" {
value = azapi_resource.powerplatform_policy.output.properties.systemId
}

output "enterprise_policy_id" {
value = azapi_resource.powerplatform_policy.output.id
}

Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
terraform {
required_version = "> 1.7.0"
required_providers {
powerplatform = {
source = "microsoft/power-platform"
version = "~>4.0"
}
azapi = {
source = "azure/azapi"
version = "~>2.2.0"
version = "~>2.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~>4.16.0"
version = "~>4.8"
}
}
}
Expand Down
30 changes: 24 additions & 6 deletions examples/resources/powerplatform_enterprise_policy/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ resource "powerplatform_managed_environment" "managed_development" {
suppress_validation_emails = true
}

// module that creates all azure resources required for the identity policy and the policy itself
module "identity" {
source = "./identity"

should_register_provider = false

//Entra Object ID for administrator user that will configure Azure Synapse Link using Managed Identity
policy_reader_object_id = "00000000-0000-0000-0000-000000000000"

environment_id = powerplatform_environment.example_environment.id

resource_group_name = "rg_example_identity"
resource_group_location = local.europe_location[0].azure_regions[0]

enterprise_policy_name = "ep_example_identity_policy"
enterprise_policy_location = local.europe_location[0].name
}

// module that creates all azure resources required for the network injection policy and the policy itself
module "network_injection" {
Expand All @@ -75,6 +92,8 @@ module "network_injection" {
vnet_locations = local.europe_location[0].azure_regions
enterprise_policy_name = "ep_example_network_injection_policy"
enterprise_policy_location = local.europe_location[0].name
// let's wait for first policy to be executed
depends_on = [module.identity]
}

// module that creates all azure resources required for the encryption policy and the policy itself
Expand All @@ -85,12 +104,11 @@ module "encryption" {

environment_id = powerplatform_environment.example_environment.id

resource_group_name = "rg_example_encryption_policy8"
resource_group_name = "rg_example_encryption_policy"
resource_group_location = local.europe_location[0].azure_regions[0]
enterprise_policy_name = "ep_example_encryption_policy8"
enterprise_policy_name = "ep_example_encryption_policy"
enterprise_policy_location = "europe"
keyvault_name = "kv-ep-example8"

// let's wait for first policy to be executed
depends_on = [powerplatform_enterprise_policy.network_injection]
keyvault_name = "kv-ep-example"
// let's wait for second policy to be executed
depends_on = [module.network_injection]
}
1 change: 1 addition & 0 deletions internal/services/enterprise_policy/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package enterprise_policy
const (
NETWORK_INJECTION_POLICY_TYPE = "NetworkInjection"
ENCRYPTION_POLICY_TYPE = "Encryption"
IDENTITY_POLICY_TYPE = "Identity"
)

type linkEnterprosePolicyDto struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ func (r *Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp
},
},
"policy_type": schema.StringAttribute{
MarkdownDescription: fmt.Sprintf("Policy type [%s, %s]", NETWORK_INJECTION_POLICY_TYPE, ENCRYPTION_POLICY_TYPE),
MarkdownDescription: fmt.Sprintf("Policy type [%s, %s, %s]", NETWORK_INJECTION_POLICY_TYPE, ENCRYPTION_POLICY_TYPE, IDENTITY_POLICY_TYPE),
Required: true,
Validators: []validator.String{
stringvalidator.OneOf(NETWORK_INJECTION_POLICY_TYPE, ENCRYPTION_POLICY_TYPE),
stringvalidator.OneOf(NETWORK_INJECTION_POLICY_TYPE, ENCRYPTION_POLICY_TYPE, IDENTITY_POLICY_TYPE),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
Expand Down Expand Up @@ -162,6 +162,8 @@ func (r *Resource) Read(ctx context.Context, req resource.ReadRequest, resp *res
state.SystemId = types.StringValue(env.Properties.EnterprisePolicies.Vnets.SystemId)
} else if state.PolicyType.ValueString() == ENCRYPTION_POLICY_TYPE && env.Properties.EnterprisePolicies.CustomerManagedKeys != nil {
state.SystemId = types.StringValue(env.Properties.EnterprisePolicies.CustomerManagedKeys.SystemId)
} else if state.PolicyType.ValueString() == IDENTITY_POLICY_TYPE && env.Properties.EnterprisePolicies.Identity != nil {
state.SystemId = types.StringValue(env.Properties.EnterprisePolicies.Identity.SystemId)
}
} else {
state.SystemId = types.StringNull()
Expand Down
1 change: 1 addition & 0 deletions internal/services/environment/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type UsedByDto struct {
type EnvironmentEnterprisePoliciesDto struct {
Vnets *EnterprisePolicyDto `json:"vnets,omitempty"`
CustomerManagedKeys *EnterprisePolicyDto `json:"customerManagedKeys,omitempty"`
Identity *EnterprisePolicyDto `json:"identity,omitempty"`
}

type EnterprisePolicyDto struct {
Expand Down
20 changes: 20 additions & 0 deletions internal/services/environment/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,26 @@ func convertEnterprisePolicyModelFromDto(environmentDto EnvironmentDto, model *S
},
}
if environmentDto.Properties.EnterprisePolicies != nil {
if environmentDto.Properties.EnterprisePolicies.Identity != nil {
model.EnterprisePolicies = types.SetValueMust(enterprisePolicyAttrType, []attr.Value{
types.ObjectValueMust(
map[string]attr.Type{
"type": types.StringType,
"id": types.StringType,
"location": types.StringType,
"system_id": types.StringType,
"status": types.StringType,
},
map[string]attr.Value{
"type": types.StringValue("Identity"),
"id": types.StringValue(environmentDto.Properties.EnterprisePolicies.Identity.Id),
"location": types.StringValue(environmentDto.Properties.EnterprisePolicies.Identity.Location),
"system_id": types.StringValue(environmentDto.Properties.EnterprisePolicies.Identity.SystemId),
"status": types.StringValue(environmentDto.Properties.EnterprisePolicies.Identity.LinkStatus),
},
),
})
}
if environmentDto.Properties.EnterprisePolicies.Vnets != nil {
model.EnterprisePolicies = types.SetValueMust(enterprisePolicyAttrType, []attr.Value{
types.ObjectValueMust(
Expand Down