diff --git a/internal/services/network/private_endpoint_resource.go b/internal/services/network/private_endpoint_resource.go index 548acbeadba2..fbfe33c0a231 100644 --- a/internal/services/network/private_endpoint_resource.go +++ b/internal/services/network/private_endpoint_resource.go @@ -165,6 +165,34 @@ func resourcePrivateEndpoint() *pluginsdk.Resource { }, }, + "ip_configuration": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.PrivateLinkName, + }, + "private_ip_address": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "subresource_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "custom_dns_configs": { Type: pluginsdk.TypeList, Computed: true, @@ -269,6 +297,7 @@ func resourcePrivateEndpointCreate(d *pluginsdk.ResourceData, meta interface{}) location := azure.NormalizeLocation(d.Get("location").(string)) privateDnsZoneGroup := d.Get("private_dns_zone_group").([]interface{}) privateServiceConnections := d.Get("private_service_connection").([]interface{}) + ipConfigurations := d.Get("ip_configuration").([]interface{}) subnetId := d.Get("subnet_id").(string) parameters := network.PrivateEndpoint{ @@ -279,6 +308,7 @@ func resourcePrivateEndpointCreate(d *pluginsdk.ResourceData, meta interface{}) Subnet: &network.Subnet{ ID: utils.String(subnetId), }, + IPConfigurations: expandPrivateEndpointIPConfigurations(ipConfigurations), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } @@ -416,6 +446,7 @@ func resourcePrivateEndpointUpdate(d *pluginsdk.ResourceData, meta interface{}) location := azure.NormalizeLocation(d.Get("location").(string)) privateDnsZoneGroup := d.Get("private_dns_zone_group").([]interface{}) privateServiceConnections := d.Get("private_service_connection").([]interface{}) + ipConfigurations := d.Get("ip_configuration").([]interface{}) subnetId := d.Get("subnet_id").(string) // TODO: in future it'd be nice to support conditional updates here, but one problem at a time @@ -427,6 +458,7 @@ func resourcePrivateEndpointUpdate(d *pluginsdk.ResourceData, meta interface{}) Subnet: &network.Subnet{ ID: utils.String(subnetId), }, + IPConfigurations: expandPrivateEndpointIPConfigurations(ipConfigurations), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } @@ -584,6 +616,11 @@ func resourcePrivateEndpointRead(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("setting `private_service_connection`: %+v", err) } + flattenedipconfiguration := flattenPrivateEndpointIPConfigurations(props.IPConfigurations) + if err := d.Set("ip_configuration", flattenedipconfiguration); err != nil { + return fmt.Errorf("setting `ip_configuration`: %+v", err) + } + subnetId := "" if props.Subnet != nil && props.Subnet.ID != nil { subnetId = *props.Subnet.ID @@ -703,6 +740,45 @@ func expandPrivateLinkEndpointServiceConnection(input []interface{}, parseManual return &results } +func expandPrivateEndpointIPConfigurations(input []interface{}) *[]network.PrivateEndpointIPConfiguration { + results := make([]network.PrivateEndpointIPConfiguration, 0) + + for _, item := range input { + v := item.(map[string]interface{}) + privateIPAddress := v["private_ip_address"].(string) + subResourceName := v["subresource_name"].(string) + name := v["name"].(string) + result := network.PrivateEndpointIPConfiguration{ + Name: utils.String(name), + PrivateEndpointIPConfigurationProperties: &network.PrivateEndpointIPConfigurationProperties{ + PrivateIPAddress: utils.String(privateIPAddress), + GroupID: utils.String(subResourceName), + MemberName: utils.String(subResourceName), + }, + } + results = append(results, result) + } + + return &results +} + +func flattenPrivateEndpointIPConfigurations(ipConfigurations *[]network.PrivateEndpointIPConfiguration) []interface{} { + results := make([]interface{}, 0) + if ipConfigurations == nil { + return results + } + + for _, item := range *ipConfigurations { + results = append(results, map[string]interface{}{ + "name": item.Name, + "private_ip_address": item.PrivateIPAddress, + "subresource_name": item.GroupID, + }) + } + + return results +} + func flattenCustomDnsConfigs(customDnsConfigs *[]network.CustomDNSConfigPropertiesFormat) []interface{} { results := make([]interface{}, 0) if customDnsConfigs == nil { diff --git a/website/docs/r/private_endpoint.html.markdown b/website/docs/r/private_endpoint.html.markdown index 484ad1f78524..8343986b50a6 100644 --- a/website/docs/r/private_endpoint.html.markdown +++ b/website/docs/r/private_endpoint.html.markdown @@ -144,6 +144,8 @@ The following arguments are supported: * `private_service_connection` - (Required) A `private_service_connection` block as defined below. +* `ip_configuration` - (Optional) An `ip_configuration` block as defined below. This allows a static IP address to be set for this Private Endpoint, otherwise an address is dynamically allocated from the Subnet. At most one IP configuration is allowed. Changing this forces a new resource to be created. + * `tags` - (Optional) A mapping of tags to assign to the resource. --- @@ -189,6 +191,16 @@ See the product [documentation](https://docs.microsoft.com/azure/private-link/pr * `request_message` - (Optional) A message passed to the owner of the remote resource when the private endpoint attempts to establish the connection to the remote resource. The request message can be a maximum of `140` characters in length. Only valid if `is_manual_connection` is set to `true`. +--- + +An `ip_configuration` supports the following: + +* `name` - (Required) Specifies the Name of the IP Configuration. Changing this forces a new resource to be created. + +* `private_ip_address` - (Required) Specifies the static IP address within the private endpoint's subnet to be used. Changing this forces a new resource to be created. + +* `subresource_name` - (Required) Specifies the subresource this IP address applies to. `subresource_names` corresponds to `group_id` and in this context is also used for `member_name`. Changing this forces a new resource to be created. + ## Attributes Reference The following attributes are exported: @@ -239,6 +251,16 @@ A `private_service_connection` block exports: --- +An `ip_configuration` block exports: + +* `name` - The Name of the IP Configuration. + +* `private_ip_address` - The static IP address set by this configuration. It is recommended to use the private IP address exported in the `private_service_connection` block to obtain the address associated with the private endpoint. + +* `subresource_name` - The subresource this IP address applies to, which corresponds to the `group_id`. + +--- + A `record_sets` block exports: * `name` - The name of the Private DNS Zone that the config belongs to.