Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
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 PowerPlatfomr 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
28 changes: 23 additions & 5 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
keyvault_name = "kv-ep-example"
// let's wait for second policy to be executed
depends_on = [powerplatform_enterprise_policy.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
Loading