diff --git a/internal/services/network/nat_gateway_public_ip_prefix_ipv6_association_resource.go b/internal/services/network/nat_gateway_public_ip_prefix_ipv6_association_resource.go new file mode 100644 index 000000000000..b2fb2118097f --- /dev/null +++ b/internal/services/network/nat_gateway_public_ip_prefix_ipv6_association_resource.go @@ -0,0 +1,285 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package network + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-sdk/resource-manager/network/2025-01-01/natgateways" + "github.com/hashicorp/go-azure-sdk/resource-manager/network/2025-01-01/publicipprefixes" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type NatGatewayPublicIpPrefixIPv6AssociationResource struct{} + +var _ sdk.ResourceWithCustomizeDiff = NatGatewayPublicIpPrefixIPv6AssociationResource{} + +type NatGatewayPublicIpPrefixIPv6AssociationModel struct { + NATGatewayId string `tfschema:"nat_gateway_id"` + PublicIPPrefixId string `tfschema:"public_ip_prefix_id"` +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "nat_gateway_id": commonschema.ResourceIDReferenceRequiredForceNew(&natgateways.NatGatewayId{}), + + "public_ip_prefix_id": commonschema.ResourceIDReferenceRequiredForceNew(&publicipprefixes.PublicIPPrefixId{}), + } +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) ModelObject() interface{} { + return &NatGatewayPublicIpPrefixIPv6AssociationModel{} +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) ResourceType() string { + return "azurerm_nat_gateway_public_ip_prefix_ipv6_association" +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) CustomizeDiff() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + rawNatGatewayId := metadata.ResourceDiff.GetRawConfig().AsValueMap()["nat_gateway_id"] + if rawNatGatewayId.IsNull() || !rawNatGatewayId.IsKnown() { + return nil + } + + rawPublicIPPrefixId := metadata.ResourceDiff.GetRawConfig().AsValueMap()["public_ip_prefix_id"] + if rawPublicIPPrefixId.IsNull() || !rawPublicIPPrefixId.IsKnown() { + return nil + } + + var model NatGatewayPublicIpPrefixIPv6AssociationModel + if err := metadata.DecodeDiff(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + natGatewayId, err := natgateways.ParseNatGatewayID(model.NATGatewayId) + if err != nil { + return err + } + + natGatewayResp, err := metadata.Client.Network.NatGateways.Get(ctx, *natGatewayId, natgateways.DefaultGetOperationOptions()) + if err != nil { + if response.WasNotFound(natGatewayResp.HttpResponse) { + return nil + } + return fmt.Errorf("retrieving %s: %+v", *natGatewayId, err) + } + + if natGatewayResp.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", *natGatewayId) + } + + natGatewaySku := pointer.From(pointer.From(natGatewayResp.Model.Sku).Name) + if natGatewaySku == natgateways.NatGatewaySkuNameStandard { + return errors.New("`nat_gateway_id` must reference a NAT Gateway with SKU `StandardV2`") + } + + publicIPPrefixId, err := publicipprefixes.ParsePublicIPPrefixID(model.PublicIPPrefixId) + if err != nil { + return err + } + + resp, err := metadata.Client.Network.PublicIPPrefixes.Get(ctx, *publicIPPrefixId, publicipprefixes.DefaultGetOperationOptions()) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return nil + } + return fmt.Errorf("retrieving %s: %+v", *publicIPPrefixId, err) + } + + if resp.Model == nil || resp.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `model` or `properties` was nil", *publicIPPrefixId) + } + + if natGatewaySku == natgateways.NatGatewaySkuNameStandardVTwo && (pointer.From(pointer.From(resp.Model.Sku).Name) != publicipprefixes.PublicIPPrefixSkuNameStandardVTwo || pointer.From(resp.Model.Properties.PublicIPAddressVersion) != publicipprefixes.IPVersionIPvSix) { + return errors.New("`public_ip_prefix_id` must reference an `IPv6` Public IP Prefix with SKU `StandardV2`") + } + + return nil + }, + } +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Network.NatGateways + + var state NatGatewayPublicIpPrefixIPv6AssociationModel + if err := metadata.Decode(&state); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + publicIPPrefixId, err := publicipprefixes.ParsePublicIPPrefixID(state.PublicIPPrefixId) + if err != nil { + return err + } + + natGatewayId, err := natgateways.ParseNatGatewayID(state.NATGatewayId) + if err != nil { + return err + } + + locks.ByID(natGatewayId.ID()) + defer locks.UnlockByID(natGatewayId.ID()) + + natGateway, err := client.Get(ctx, *natGatewayId, natgateways.DefaultGetOperationOptions()) + if err != nil { + if response.WasNotFound(natGateway.HttpResponse) { + return fmt.Errorf("%s was not found", *natGatewayId) + } + return fmt.Errorf("retrieving %s: %+v", *natGatewayId, err) + } + if natGateway.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", *natGatewayId) + } + if natGateway.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `properties` was nil", *natGatewayId) + } + + id := commonids.NewCompositeResourceID(natGatewayId, publicIPPrefixId) + + existingPrefixes := pointer.From(natGateway.Model.Properties.PublicIPPrefixesV6) + for _, existingPublicIPPrefix := range existingPrefixes { + if strings.EqualFold(pointer.From(existingPublicIPPrefix.Id), publicIPPrefixId.ID()) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + } + + existingPrefixes = append(existingPrefixes, natgateways.SubResource{ + Id: pointer.To(publicIPPrefixId.ID()), + }) + natGateway.Model.Properties.PublicIPPrefixesV6 = pointer.To(existingPrefixes) + + if err := client.CreateOrUpdateThenPoll(ctx, *natGatewayId, *natGateway.Model); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Network.NatGateways + + id, err := commonids.ParseCompositeResourceID(metadata.ResourceData.Id(), &natgateways.NatGatewayId{}, &publicipprefixes.PublicIPPrefixId{}) + if err != nil { + return err + } + + natGateway, err := client.Get(ctx, *id.First, natgateways.DefaultGetOperationOptions()) + if err != nil { + if response.WasNotFound(natGateway.HttpResponse) { + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", *id.First, err) + } + + found := false + if natGateway.Model == nil || natGateway.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `model` or `properties` was nil", id.First) + } + + for _, publicIPPrefix := range pointer.From(natGateway.Model.Properties.PublicIPPrefixesV6) { + if strings.EqualFold(pointer.From(publicIPPrefix.Id), id.Second.ID()) { + found = true + break + } + } + + if !found { + return metadata.MarkAsGone(id) + } + + return metadata.Encode(&NatGatewayPublicIpPrefixIPv6AssociationModel{ + NATGatewayId: id.First.ID(), + PublicIPPrefixId: id.Second.ID(), + }) + }, + } +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Network.NatGateways + + id, err := commonids.ParseCompositeResourceID(metadata.ResourceData.Id(), &natgateways.NatGatewayId{}, &publicipprefixes.PublicIPPrefixId{}) + if err != nil { + return err + } + + locks.ByID(id.First.ID()) + defer locks.UnlockByID(id.First.ID()) + + natGateway, err := client.Get(ctx, *id.First, natgateways.DefaultGetOperationOptions()) + if err != nil { + if response.WasNotFound(natGateway.HttpResponse) { + return fmt.Errorf("%s was not found", *id.First) + } + return fmt.Errorf("retrieving %s: %+v", *id.First, err) + } + if natGateway.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", *id.First) + } + if natGateway.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `properties` was nil", *id.First) + } + + publicIPPrefixesV6 := make([]natgateways.SubResource, 0) + needToDelete := false + for _, publicIPPrefix := range pointer.From(natGateway.Model.Properties.PublicIPPrefixesV6) { + if !strings.EqualFold(pointer.From(publicIPPrefix.Id), id.Second.ID()) { + publicIPPrefixesV6 = append(publicIPPrefixesV6, publicIPPrefix) + } else { + needToDelete = true + } + } + + if !needToDelete { + return nil + } + + natGateway.Model.Properties.PublicIPPrefixesV6 = pointer.To(publicIPPrefixesV6) + + if err := client.CreateOrUpdateThenPoll(ctx, *id.First, *natGateway.Model); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return func(input interface{}, key string) (warnings []string, errors []error) { + if _, err := commonids.ParseCompositeResourceID(input.(string), &natgateways.NatGatewayId{}, &publicipprefixes.PublicIPPrefixId{}); err != nil { + errors = append(errors, err) + } + return warnings, errors + } +} diff --git a/internal/services/network/nat_gateway_public_ip_prefix_ipv6_association_resource_test.go b/internal/services/network/nat_gateway_public_ip_prefix_ipv6_association_resource_test.go new file mode 100644 index 000000000000..ac7cff628549 --- /dev/null +++ b/internal/services/network/nat_gateway_public_ip_prefix_ipv6_association_resource_test.go @@ -0,0 +1,288 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package network_test + +import ( + "context" + "fmt" + "regexp" + "strings" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/network/2025-01-01/natgateways" + "github.com/hashicorp/go-azure-sdk/resource-manager/network/2025-01-01/publicipprefixes" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type NatGatewayPublicIpPrefixIPv6AssociationResource struct{} + +func TestAccNatGatewayPublicIpPrefixIPv6Association_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_prefix_ipv6_association", "test") + r := NatGatewayPublicIpPrefixIPv6AssociationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccNatGatewayPublicIpPrefixIPv6Association_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_prefix_ipv6_association", "test") + r := NatGatewayPublicIpPrefixIPv6AssociationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccNatGatewayPublicIpPrefixIPv6Association_multipleAssociations(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_prefix_ipv6_association", "test") + r := NatGatewayPublicIpPrefixIPv6AssociationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.multipleAssociations(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccNatGatewayPublicIpPrefixIPv6Association_publicIPPrefixMustBeIPv6(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_prefix_ipv6_association", "test") + r := NatGatewayPublicIpPrefixIPv6AssociationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.prerequisites(data, "StandardV2", "StandardV2", "IPv4"), + }, + { + Config: r.publicIPPrefixMustBeIPv6(data), + ExpectError: regexp.MustCompile("`public_ip_prefix_id` must reference an `IPv6` Public IP Prefix with SKU `StandardV2`"), + }, + }) +} + +func TestAccNatGatewayPublicIpPrefixIPv6Association_standardSkuNatGatewayCannotUseIPv6PublicIPAddressesOrPrefixes(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_prefix_ipv6_association", "test") + r := NatGatewayPublicIpPrefixIPv6AssociationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.prerequisites(data, "Standard", "StandardV2", "IPv6"), + }, + { + Config: r.standardSkuNatGatewayCannotUseIPv6PublicIPAddressesOrPrefixes(data), + ExpectError: regexp.MustCompile("`nat_gateway_id` must reference a NAT Gateway with SKU `StandardV2`"), + }, + }) +} + +func TestAccNatGatewayPublicIpPrefixIPv6Association_standardV2SkuNatGatewayRequiresPublicIPPrefixWithStandardV2Sku(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_nat_gateway_public_ip_prefix_ipv6_association", "test") + r := NatGatewayPublicIpPrefixIPv6AssociationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.prerequisites(data, "StandardV2", "Standard", "IPv6"), + }, + { + Config: r.standardV2SkuNatGatewayRequiresPublicIPPrefixWithStandardV2Sku(data), + ExpectError: regexp.MustCompile("`public_ip_prefix_id` must reference an `IPv6` Public IP Prefix with SKU `StandardV2`"), + }, + }) +} + +func (t NatGatewayPublicIpPrefixIPv6AssociationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := commonids.ParseCompositeResourceID(state.ID, &natgateways.NatGatewayId{}, &publicipprefixes.PublicIPPrefixId{}) + if err != nil { + return nil, err + } + + resp, err := clients.Network.NatGateways.Get(ctx, *id.First, natgateways.DefaultGetOperationOptions()) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", *id.First, err) + } + + found := false + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + if props.PublicIPPrefixesV6 != nil { + for _, pip := range *props.PublicIPPrefixesV6 { + if pip.Id == nil { + continue + } + + if strings.EqualFold(*pip.Id, id.Second.ID()) { + found = true + break + } + } + } + } + } + + return pointer.To(found), nil +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_nat_gateway" "test" { + name = "acctest-NatGateway-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "StandardV2" +} + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_prefix_id = azurerm_public_ip_prefix.test.id +} +`, r.template(data), data.RandomInteger) +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "import" { + nat_gateway_id = azurerm_nat_gateway_public_ip_prefix_ipv6_association.test.nat_gateway_id + public_ip_prefix_id = azurerm_nat_gateway_public_ip_prefix_ipv6_association.test.public_ip_prefix_id +} +`, r.basic(data)) +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) multipleAssociations(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_nat_gateway" "test" { + name = "acctest-NatGateway-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "StandardV2" +} + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_prefix_id = azurerm_public_ip_prefix.test.id +} + +resource "azurerm_public_ip_prefix" "test2" { + name = "acctest-pipPrefix2V6-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + ip_version = "IPv6" + prefix_length = 127 + sku = "StandardV2" +} + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "test2" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_prefix_id = azurerm_public_ip_prefix.test2.id +} +`, r.template(data), data.RandomInteger, data.RandomInteger) +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) publicIPPrefixMustBeIPv6(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_prefix_id = azurerm_public_ip_prefix.test.id +} +`, r.prerequisites(data, "StandardV2", "StandardV2", "IPv4")) +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) standardSkuNatGatewayCannotUseIPv6PublicIPAddressesOrPrefixes(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_prefix_id = azurerm_public_ip_prefix.test.id +} +`, r.prerequisites(data, "Standard", "StandardV2", "IPv6")) +} + +func (r NatGatewayPublicIpPrefixIPv6AssociationResource) standardV2SkuNatGatewayRequiresPublicIPPrefixWithStandardV2Sku(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "test" { + nat_gateway_id = azurerm_nat_gateway.test.id + public_ip_prefix_id = azurerm_public_ip_prefix.test.id +} +`, r.prerequisites(data, "StandardV2", "Standard", "IPv6")) +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) prerequisites(data acceptance.TestData, natGatewaySkuName, publicIPPrefixSku, publicIPPrefixVersion string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-ngpipv6-%d" + location = "%s" +} + +resource "azurerm_public_ip_prefix" "test" { + name = "acctest-pipPrefixV6-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + ip_version = "%s" + prefix_length = 127 + sku = "%s" +} + +resource "azurerm_nat_gateway" "test" { + name = "acctest-NatGateway-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "%s" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, publicIPPrefixVersion, publicIPPrefixSku, data.RandomInteger, natGatewaySkuName) +} + +func (NatGatewayPublicIpPrefixIPv6AssociationResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-ngpipv6-%d" + location = "%s" +} + +resource "azurerm_public_ip_prefix" "test" { + name = "acctest-pipPrefixV6-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + ip_version = "IPv6" + prefix_length = 127 + sku = "StandardV2" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/network/registration.go b/internal/services/network/registration.go index d04f7b42b85f..8e0ef41cac03 100644 --- a/internal/services/network/registration.go +++ b/internal/services/network/registration.go @@ -69,6 +69,7 @@ func (r Registration) Resources() []sdk.Resource { ManagerSubscriptionConnectionResource{}, ManagerVerifierWorkspaceResource{}, ManagerVerifierWorkspaceReachabilityAnalysisIntentResource{}, + NatGatewayPublicIpPrefixIPv6AssociationResource{}, NetworkSecurityPerimeterAccessRuleResource{}, NetworkSecurityPerimeterAssociationResource{}, NetworkSecurityPerimeterResource{}, diff --git a/website/docs/r/nat_gateway_public_ip_prefix_ipv6_association.html.markdown b/website/docs/r/nat_gateway_public_ip_prefix_ipv6_association.html.markdown new file mode 100644 index 000000000000..6475dc4d4e3e --- /dev/null +++ b/website/docs/r/nat_gateway_public_ip_prefix_ipv6_association.html.markdown @@ -0,0 +1,83 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_nat_gateway_public_ip_prefix_ipv6_association" +description: |- + Manages the association between a NAT Gateway and an IPv6 Public IP Prefix. +--- + +# azurerm_nat_gateway_public_ip_prefix_ipv6_association + +Manages the association between a NAT Gateway and an IPv6 Public IP Prefix. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resource-group" + location = "West Europe" +} + +resource "azurerm_public_ip_prefix" "example" { + name = "example-public-ip-prefix" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + ip_version = "IPv6" + prefix_length = 127 + sku = "StandardV2" +} + +resource "azurerm_nat_gateway" "example" { + name = "example-nat-gateway" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku_name = "StandardV2" +} + +resource "azurerm_nat_gateway_public_ip_prefix_ipv6_association" "example" { + nat_gateway_id = azurerm_nat_gateway.example.id + public_ip_prefix_id = azurerm_public_ip_prefix.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `nat_gateway_id` - (Required) The ID of the NAT Gateway. Changing this forces a new resource to be created. + +~> **Note:** `nat_gateway_id` must reference a NAT Gateway with SKU `StandardV2`. + +* `public_ip_prefix_id` - (Required) The ID of the IPv6 Public IP Prefix which this NAT Gateway should be connected to. Changing this forces a new resource to be created. + +~> **Note:** `public_ip_prefix_id` must reference an `IPv6` Public IP Prefix with SKU `StandardV2`. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the NAT Gateway and IPv6 Public IP Prefix association. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://developer.hashicorp.com/terraform/language/resources/configure#define-operation-timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the NAT Gateway and IPv6 Public IP Prefix association. +* `read` - (Defaults to 5 minutes) Used when retrieving the NAT Gateway and IPv6 Public IP Prefix association. +* `delete` - (Defaults to 30 minutes) Used when deleting the NAT Gateway and IPv6 Public IP Prefix association. + +## Import + +A NAT Gateway and IPv6 Public IP Prefix association can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_nat_gateway_public_ip_prefix_ipv6_association.example "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup1/providers/Microsoft.Network/natGateways/natGateway1|/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup1/providers/Microsoft.Network/publicIPPrefixes/publicIPPrefix1" +``` + +-> **Note:** This is a Terraform-specific ID in the format `{natGatewayID}|{publicIPPrefixID}`. + +## API Providers + +This resource uses the following Azure API Providers: + +* `Microsoft.Network` - 2025-01-01 \ No newline at end of file