hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.6k stars 4.64k forks source link

Support for `azurerm_monitor_workspace_private_endpoint_connection_approval` #27903

Open djryanj opened 3 days ago

djryanj commented 3 days ago

Is there an existing issue for this?

Community Note

Description

When using Terraform to create a managed private endpoint from (e.g.,) an azurerm_dashboard_grafana_managed_private_endpoint resource, manual approval is required or use of the AzAPI provider.

This resource will provide a way to approve the private endpoint connection request using the AzureRM provider directly.

New or Affected Resource(s)/Data Source(s)

azurerm_monitor_workspace_private_endpoint_connection_approval

Potential Terraform Configuration

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "Canada Central"
}

resource "azurerm_monitor_workspace" "example" {
  name                          = "example-mamw"
  resource_group_name           = azurerm_resource_group.example.name
  location                      = azurerm_resource_group.example.location
  public_network_access_enabled = false
}

resource "azurerm_dashboard_grafana" "example" {
  name                          = "example-dg"
  resource_group_name           = azurerm_resource_group.example.name
  location                      = azurerm_resource_group.example.location
  grafana_major_version         = 10
  public_network_access_enabled = false

  azure_monitor_workspace_integrations {
    resource_id = azurerm_monitor_workspace.example.id
  }
}

resource "azurerm_dashboard_grafana_managed_private_endpoint" "example" {
  grafana_id                   = azurerm_dashboard_grafana.example.id
  name                         = "example-mpe"
  location                     = azurerm_dashboard_grafana.example.location
  private_link_resource_id     = azurerm_monitor_workspace.example.id
  group_ids                    = ["prometheusMetrics"]
  private_link_resource_region = azurerm_dashboard_grafana.example.location
}

resource "azurerm_monitor_workspace_private_endpoint_connection_approval" {
  workspace_id = azurerm_monitor_workspace.example.id
  private_endpoint_connection_id = azurerm_monitor_workspace.example.private_endpoint_connections[0].id
  service_private_endpoint_id = azurerm_dashboard_grafana_managed_private_endpoint.example.id
  approval_message = "approved by terraform"
}

References

23950

27786

djryanj commented 3 days ago

This comment contains some hidden notes for myself.

djryanj commented 2 days ago

I could really use the input of a maintainer here.

The SDK for Azure Monitor Workspaces does not contain a separate ID parser for private endpoint connections: https://github.com/hashicorp/terraform-provider-azurerm/tree/main/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/insights/2023-04-03/azuremonitorworkspaces

Meaning that it could be argued based on the contributor documents that this should be an inline resource only.

However, that would cause a loop error on apply; since the azurerm_dashboard_grafana_managed_private_endpoint resource (or, presumably, another type which can connect to an azurerm_monitor_workspace) references the azurerm_monitor_workspace resource id directly, it would not be possible to reference azurerm_dashboard_grafana_managed_private_endpoint in the azurerm_monitor_workspace resource inline block (and actually, as it stands, the proposed HCL for azurerm_monitor_workspace_private_endpoint_connection_approval only includes a link to the service_private_endpoint_id to satisfy the dependency graph; the id would not be used otherwise in the code).

I'm thinking that what's really required here is upstream work in go-azure-sdk to expose the private endpoint connections as a totally separate client. Otherwise I'm inventing a composite resource ID, or I'm making up my own just to have the subresource ID get parsed properly.

djryanj commented 2 days ago

In case someone happens to come across this before it gets implemented, a workaround is mentioned in #23950 but with the merging of #27781 and once #27902 is merged you'll be able to do this with an AzAPI resource in place of a azurerm_monitor_workspace_private_endpoint_connection_approval resource:

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "Canada Central"
}

resource "azurerm_monitor_workspace" "example" {
  name                          = "example-mamw"
  resource_group_name           = azurerm_resource_group.example.name
  location                      = azurerm_resource_group.example.location
  public_network_access_enabled = false
}

resource "azurerm_dashboard_grafana" "example" {
  name                          = "example-dg"
  resource_group_name           = azurerm_resource_group.example.name
  location                      = azurerm_resource_group.example.location
  grafana_major_version         = 10
  public_network_access_enabled = false

  azure_monitor_workspace_integrations {
    resource_id = azurerm_monitor_workspace.example.id
  }
}

resource "azurerm_dashboard_grafana_managed_private_endpoint" "example" {
  grafana_id                   = azurerm_dashboard_grafana.example.id
  name                         = "example-mpe"
  location                     = azurerm_dashboard_grafana.example.location
  private_link_resource_id     = azurerm_monitor_workspace.example.id
  group_ids                    = ["prometheusMetrics"]
  private_link_resource_region = azurerm_dashboard_grafana.example.location
}

resource "azapi_update_resource" "grafana_managed_private_endpoint_connection_approval" {
  type      = "Microsoft.Monitor/accounts/privateEndpointConnections@2023-04-03"
  name      = azurerm_monitor_workspace.example.private_endpoint_connections[0].name
  parent_id = azurerm_monitor_workspace.example.id

  body = jsonencode({
    properties = {
      privateLinkServiceConnectionState = {
        actionsRequired = "None"
        description     = "Approved via Terraform"
        status          = "Approved"
      }
    }
  })
  depends_on = [ azurerm_dashboard_grafana_managed_private_endpoint.example ]
}

This is significantly improved from the previous workaround that needed a ton of faffing about with local resources and such.