diff --git a/.changelog/29623.txt b/.changelog/29623.txt new file mode 100644 index 000000000000..e365de691bab --- /dev/null +++ b/.changelog/29623.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_networkmanager_core_network: Add `base_policy_regions` argument +``` + +```release-note:note +resource/aws_networkmanager_core_network: The `base_policy_region` argument is being deprecated in favor of the new `base_policy_regions` argument. +``` \ No newline at end of file diff --git a/internal/service/networkmanager/core_network.go b/internal/service/networkmanager/core_network.go index a80a24c34c17..4a51010f5b5d 100644 --- a/internal/service/networkmanager/core_network.go +++ b/internal/service/networkmanager/core_network.go @@ -2,6 +2,7 @@ package networkmanager import ( "context" + "encoding/json" "fmt" "log" "time" @@ -58,9 +59,21 @@ func ResourceCoreNetwork() *schema.Resource { Computed: true, }, "base_policy_region": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: verify.ValidRegionName, + Deprecated: "Use the base_policy_regions argument instead. " + + "This argument will be removed in the next major version of the provider.", + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidRegionName, + ConflictsWith: []string{"base_policy_regions"}, + }, + "base_policy_regions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidRegionName, + }, + ConflictsWith: []string{"base_policy_region"}, }, "create_base_policy": { Type: schema.TypeBool, @@ -178,13 +191,18 @@ func resourceCoreNetworkCreate(ctx context.Context, d *schema.ResourceData, meta // this is required for the first terraform apply if there attachments to the core network // and the core network is created without the policy_document argument set if _, ok := d.GetOk("create_base_policy"); ok { - // if user supplies a region use it in the base policy, otherwise use current region - region := meta.(*conns.AWSClient).Region + // if user supplies a region or multiple regions use it in the base policy, otherwise use current region + regions := []interface{}{meta.(*conns.AWSClient).Region} if v, ok := d.GetOk("base_policy_region"); ok { - region = v.(string) + regions = []interface{}{v.(string)} + } else if v, ok := d.GetOk("base_policy_regions"); ok && v.(*schema.Set).Len() > 0 { + regions = v.(*schema.Set).List() } - policyDocumentTarget := buildCoreNetworkBasePolicyDocument(region) + policyDocumentTarget, err := buildCoreNetworkBasePolicyDocument(regions) + if err != nil { + return diag.Errorf("Formatting Core Network Base Policy: %s", err) + } input.PolicyDocument = aws.String(policyDocumentTarget) } @@ -304,14 +322,21 @@ func resourceCoreNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta if d.HasChange("create_base_policy") { if _, ok := d.GetOk("create_base_policy"); ok { - // if user supplies a region use it in the base policy, otherwise use current region - region := meta.(*conns.AWSClient).Region + // if user supplies a region or multiple regions use it in the base policy, otherwise use current region + regions := []interface{}{meta.(*conns.AWSClient).Region} if v, ok := d.GetOk("base_policy_region"); ok { - region = v.(string) + regions = []interface{}{v.(string)} + } else if v, ok := d.GetOk("base_policy_regions"); ok && v.(*schema.Set).Len() > 0 { + regions = v.(*schema.Set).List() + } + + policyDocumentTarget, err := buildCoreNetworkBasePolicyDocument(regions) + + if err != nil { + return diag.Errorf("Formatting Core Network Base Policy: %s", err) } - policyDocumentTarget := buildCoreNetworkBasePolicyDocument(region) - err := PutAndExecuteCoreNetworkPolicy(ctx, conn, d.Id(), policyDocumentTarget) + err = PutAndExecuteCoreNetworkPolicy(ctx, conn, d.Id(), policyDocumentTarget) if err != nil { return diag.FromErr(err) @@ -609,6 +634,31 @@ func PutAndExecuteCoreNetworkPolicy(ctx context.Context, conn *networkmanager.Ne } // buildCoreNetworkBasePolicyDocument returns a base policy document -func buildCoreNetworkBasePolicyDocument(region string) string { - return fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}]},\"segments\":[{\"name\":\"segment\",\"description\":\"base-policy\"}],\"version\":\"2021.12\"}", region) +func buildCoreNetworkBasePolicyDocument(regions []interface{}) (string, error) { + edgeLocations := make([]*CoreNetworkEdgeLocation, len(regions)) + for i, location := range regions { + edgeLocations[i] = &CoreNetworkEdgeLocation{Location: location.(string)} + } + + basePolicy := &CoreNetworkPolicyDoc{ + Version: "2021.12", + CoreNetworkConfiguration: &CoreNetworkPolicyCoreNetworkConfiguration{ + AsnRanges: CoreNetworkPolicyDecodeConfigStringList([]interface{}{"64512-65534"}), + EdgeLocations: edgeLocations, + }, + Segments: []*CoreNetworkPolicySegment{ + { + Name: "segment", + Description: "base-policy", + }, + }, + } + + b, err := json.MarshalIndent(basePolicy, "", " ") + if err != nil { + // should never happen if the above code is correct + return "", fmt.Errorf("building base policy document: %s", err) + } + + return string(b), nil } diff --git a/internal/service/networkmanager/core_network_policy_attachment_test.go b/internal/service/networkmanager/core_network_policy_attachment_test.go index 725c11e2b7ee..a715648b14b8 100644 --- a/internal/service/networkmanager/core_network_policy_attachment_test.go +++ b/internal/service/networkmanager/core_network_policy_attachment_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/networkmanager" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -97,6 +98,42 @@ func TestAccNetworkManagerCoreNetworkPolicyAttachment_vpcAttachment(t *testing.T }) } +func TestAccNetworkManagerCoreNetworkPolicyAttachment_vpcAttachmentMultiRegion(t *testing.T) { + ctx := acctest.Context(t) + var providers []*schema.Provider + resourceName := "aws_networkmanager_core_network_policy_attachment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckMultipleRegion(t, 2) + }, + ErrorCheck: acctest.ErrorCheck(t, networkmanager.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesPlusProvidersAlternate(ctx, t, &providers), + CheckDestroy: testAccCheckCoreNetworkPolicyAttachmentDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCoreNetworkPolicyAttachmentConfig_vpcAttachmentMultiRegionCreate(), + Check: resource.ComposeTestCheckFunc( + testAccCheckCoreNetworkPolicyAttachmentExists(ctx, resourceName), + resource.TestMatchResourceAttr(resourceName, "policy_document", regexp.MustCompile(fmt.Sprintf(`{"core-network-configuration":{"asn-ranges":\["65022-65534"\],"edge-locations":\[{"location":"%s"},{"location":"%s"}\],"vpn-ecmp-support":true},"segment-actions":\[{"action":"create-route","destination-cidr-blocks":\["10.0.0.0/16"\],"destinations":\["attachment-.+"\],"segment":"segment"},{"action":"create-route","destination-cidr-blocks":\["10.1.0.0/16"\],"destinations":\["attachment-.+"\],"segment":"segment2"}\],"segments":\[{"isolate-attachments":false,"name":"segment","require-attachment-acceptance":true},{"isolate-attachments":false,"name":"segment2","require-attachment-acceptance":true}\],"version":"2021.12"}`, acctest.Region(), acctest.AlternateRegion()))), + // use test below if the order of locations is unordered + // resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"65022-65534\"],\"edge-locations\":[{\"location\":\"%s\"},{\"location\":\"%s\"}],\"vpn-ecmp-support\":true},\"segments\":[{\"description\":\"base-policy\",\"isolate-attachments\":false,\"name\":\"segment\",\"require-attachment-acceptance\":false}],\"version\":\"2021.12\"}", acctest.AlternateRegion(), acctest.Region())), + resource.TestCheckResourceAttrPair(resourceName, "core_network_id", "aws_networkmanager_core_network.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "id", "aws_networkmanager_core_network.test", "id"), + resource.TestCheckResourceAttr(resourceName, "state", networkmanager.CoreNetworkStateAvailable), + ), + }, + { + Config: testAccCoreNetworkPolicyAttachmentConfig_vpcAttachmentMultiRegionCreate(), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckCoreNetworkPolicyAttachmentDestroy(ctx context.Context) resource.TestCheckFunc { // policy document will not be reverted to empty if the attachment is deleted return nil @@ -216,3 +253,137 @@ resource "aws_networkmanager_vpc_attachment" "test" { } `, acctest.Region())) } + +func testAccCoreNetworkPolicyAttachmentConfig_vpcAttachmentMultiRegionCreate() string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(2), + acctest.ConfigAvailableAZsNoOptIn(), + fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "tf-acc-test-networkmanager-core-network-policy-attachment" + } +} + +resource "aws_subnet" "test" { + count = 2 + + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) + vpc_id = aws_vpc.test.id + + tags = { + Name = "tf-acc-test-networkmanager-core-network-policy-attachment" + } +} + +resource "aws_networkmanager_global_network" "test" {} + +data "aws_networkmanager_core_network_policy_document" "test" { + core_network_configuration { + asn_ranges = ["65022-65534"] + + edge_locations { + location = %[1]q + } + + edge_locations { + location = %[2]q + } + } + + segments { + name = "segment" + } + + segments { + name = "segment2" + } + + segment_actions { + action = "create-route" + segment = "segment" + destination_cidr_blocks = [ + "10.0.0.0/16" + ] + destinations = [ + aws_networkmanager_vpc_attachment.test.id, + ] + } + + segment_actions { + action = "create-route" + segment = "segment2" + destination_cidr_blocks = [ + "10.1.0.0/16" + ] + destinations = [ + aws_networkmanager_vpc_attachment.alternate_region.id, + ] + } +} + +resource "aws_networkmanager_core_network" "test" { + global_network_id = aws_networkmanager_global_network.test.id + base_policy_regions = [%[1]q, %[2]q] + create_base_policy = true +} + +resource "aws_networkmanager_core_network_policy_attachment" "test" { + core_network_id = aws_networkmanager_core_network.test.id + policy_document = data.aws_networkmanager_core_network_policy_document.test.json +} + +resource "aws_networkmanager_vpc_attachment" "test" { + core_network_id = aws_networkmanager_core_network.test.id + subnet_arns = aws_subnet.test[*].arn + vpc_arn = aws_vpc.test.arn +} + +# Alternate region +data "aws_availability_zones" "alternate_region_available" { + provider = "awsalternate" + + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +resource "aws_vpc" "alternate_region" { + provider = "awsalternate" + + cidr_block = "10.1.0.0/16" + + tags = { + Name = "tf-acc-test-networkmanager-core-network-policy-attachment" + } +} + +resource "aws_subnet" "alternate_region" { + provider = "awsalternate" + + count = 2 + + availability_zone = data.aws_availability_zones.alternate_region_available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.alternate_region.cidr_block, 8, count.index) + vpc_id = aws_vpc.alternate_region.id + + tags = { + Name = "tf-acc-test-networkmanager-core-network-policy-attachment" + } +} + +resource "aws_networkmanager_vpc_attachment" "alternate_region" { + provider = "awsalternate" + + core_network_id = aws_networkmanager_core_network.test.id + subnet_arns = aws_subnet.alternate_region[*].arn + vpc_arn = aws_vpc.alternate_region.arn +} +`, acctest.Region(), acctest.AlternateRegion())) +} diff --git a/internal/service/networkmanager/core_network_test.go b/internal/service/networkmanager/core_network_test.go index 20e2f6a77e89..4a0c96f7a9fd 100644 --- a/internal/service/networkmanager/core_network_test.go +++ b/internal/service/networkmanager/core_network_test.go @@ -224,7 +224,7 @@ func TestAccNetworkManagerCoreNetwork_createBasePolicyDocumentWithoutRegion(t *t Check: resource.ComposeTestCheckFunc( testAccCheckCoreNetworkExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "create_base_policy", "true"), - resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}]},\"segments\":[{\"description\":\"base-policy\",\"name\":\"segment\"}],\"version\":\"2021.12\"}", acctest.Region())), + resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}],\"vpn-ecmp-support\":false},\"segments\":[{\"description\":\"base-policy\",\"isolate-attachments\":false,\"name\":\"segment\",\"require-attachment-acceptance\":false}],\"version\":\"2021.12\"}", acctest.Region())), resource.TestCheckNoResourceAttr(resourceName, "base_policy_region"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "edges.*", map[string]string{ "asn": "64512", @@ -264,7 +264,7 @@ func TestAccNetworkManagerCoreNetwork_createBasePolicyDocumentWithRegion(t *test Check: resource.ComposeTestCheckFunc( testAccCheckCoreNetworkExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "create_base_policy", "true"), - resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}]},\"segments\":[{\"description\":\"base-policy\",\"name\":\"segment\"}],\"version\":\"2021.12\"}", acctest.AlternateRegion())), + resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}],\"vpn-ecmp-support\":false},\"segments\":[{\"description\":\"base-policy\",\"isolate-attachments\":false,\"name\":\"segment\",\"require-attachment-acceptance\":false}],\"version\":\"2021.12\"}", acctest.AlternateRegion())), resource.TestCheckResourceAttr(resourceName, "base_policy_region", acctest.AlternateRegion()), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "edges.*", map[string]string{ "asn": "64512", @@ -289,6 +289,54 @@ func TestAccNetworkManagerCoreNetwork_createBasePolicyDocumentWithRegion(t *test }) } +func TestAccNetworkManagerCoreNetwork_createBasePolicyDocumentWithMultiRegion(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_networkmanager_core_network.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, networkmanager.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCoreNetworkDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCoreNetworkConfig_basePolicyDocumentWithMultiRegion(), + Check: resource.ComposeTestCheckFunc( + testAccCheckCoreNetworkExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "create_base_policy", "true"), + resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"},{\"location\":\"%s\"}],\"vpn-ecmp-support\":false},\"segments\":[{\"description\":\"base-policy\",\"isolate-attachments\":false,\"name\":\"segment\",\"require-attachment-acceptance\":false}],\"version\":\"2021.12\"}", acctest.AlternateRegion(), acctest.Region())), + // use test below if locations are unordered + // resource.TestMatchResourceAttr(resourceName, "policy_document", regexp.MustCompile(`{"core-network-configuration":{"asn-ranges":\["64512-65534"\],"edge-locations":\[{"location":".+"},{"location":".+"}\],"vpn-ecmp-support":false},"segments":\[{"description":"base-policy","isolate-attachments":false,"name":"segment","require-attachment-acceptance":false}\],"version":"2021.12"}`)), + resource.TestCheckResourceAttr(resourceName, "base_policy_regions.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "base_policy_regions.*", acctest.AlternateRegion()), + resource.TestCheckTypeSetElemAttr(resourceName, "base_policy_regions.*", acctest.Region()), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "edges.*", map[string]string{ + "asn": "64512", + "edge_location": acctest.AlternateRegion(), + "inside_cidr_blocks.#": "0", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "edges.*", map[string]string{ + "asn": "64513", + "edge_location": acctest.Region(), + "inside_cidr_blocks.#": "0", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "segments.*", map[string]string{ + "edge_locations.#": "2", + "name": "segment", + "shared_segments.#": "0", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_policy_regions", "create_base_policy"}, + }, + }, + }) +} + func TestAccNetworkManagerCoreNetwork_withoutPolicyDocumentUpdateToCreateBasePolicyDocument(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_networkmanager_core_network.test" @@ -317,7 +365,7 @@ func TestAccNetworkManagerCoreNetwork_withoutPolicyDocumentUpdateToCreateBasePol Check: resource.ComposeTestCheckFunc( testAccCheckCoreNetworkExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "create_base_policy", "true"), - resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}]},\"segments\":[{\"description\":\"base-policy\",\"name\":\"segment\"}],\"version\":\"2021.12\"}", acctest.Region())), + resource.TestCheckResourceAttr(resourceName, "policy_document", fmt.Sprintf("{\"core-network-configuration\":{\"asn-ranges\":[\"64512-65534\"],\"edge-locations\":[{\"location\":\"%s\"}],\"vpn-ecmp-support\":false},\"segments\":[{\"description\":\"base-policy\",\"isolate-attachments\":false,\"name\":\"segment\",\"require-attachment-acceptance\":false}],\"version\":\"2021.12\"}", acctest.Region())), resource.TestCheckNoResourceAttr(resourceName, "base_policy_region"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "edges.*", map[string]string{ "asn": "64512", @@ -477,3 +525,15 @@ resource "aws_networkmanager_core_network" "test" { } `, acctest.AlternateRegion()) } + +func testAccCoreNetworkConfig_basePolicyDocumentWithMultiRegion() string { + return fmt.Sprintf(` +resource "aws_networkmanager_global_network" "test" {} + +resource "aws_networkmanager_core_network" "test" { + global_network_id = aws_networkmanager_global_network.test.id + base_policy_regions = [%[1]q, %[2]q] + create_base_policy = true +} +`, acctest.AlternateRegion(), acctest.Region()) +} diff --git a/website/docs/r/networkmanager_core_network.html.markdown b/website/docs/r/networkmanager_core_network.html.markdown index fd1fda0691f8..0fa9ee9c95d7 100644 --- a/website/docs/r/networkmanager_core_network.html.markdown +++ b/website/docs/r/networkmanager_core_network.html.markdown @@ -43,7 +43,7 @@ resource "aws_networkmanager_core_network" "example" { } ``` -### With VPC Attachment +### With VPC Attachment (Single Region) The example below illustrates the scenario where your policy document has static routes pointing to VPC attachments and you want to attach your VPCs to the core network before applying the desired policy document. Set the `create_base_policy` argument to `true` if your core network does not currently have any `LIVE` policies (e.g. this is the first `terraform apply` with the core network resource), since a `LIVE` policy is required before VPCs can be attached to the core network. Otherwise, if your core network already has a `LIVE` policy, you may exclude the `create_base_policy` argument. @@ -92,13 +92,91 @@ resource "aws_networkmanager_vpc_attachment" "example" { } ``` +### With VPC Attachment (Multi-Region) + +The example below illustrates the scenario where your policy document has static routes pointing to VPC attachments and you want to attach your VPCs to the core network before applying the desired policy document. Set the `create_base_policy` argument of the [`aws_networkmanager_core_network` resource](/docs/providers/aws/r/networkmanager_core_network.html) to `true` if your core network does not currently have any `LIVE` policies (e.g. this is the first `terraform apply` with the core network resource), since a `LIVE` policy is required before VPCs can be attached to the core network. Otherwise, if your core network already has a `LIVE` policy, you may exclude the `create_base_policy` argument. For multi-region in a core network that does not yet have a `LIVE` policy, pass a list of regions to the `aws_networkmanager_core_network` `base_policy_regions` argument. In the example below, `us-west-2` and `us-east-1` are specified in the base policy. + +```terraform +resource "aws_networkmanager_global_network" "example" {} + +data "aws_networkmanager_core_network_policy_document" "example" { + core_network_configuration { + asn_ranges = ["65022-65534"] + + edge_locations { + location = "us-west-2" + } + + edge_locations { + location = "us-east-1" + } + } + + segments { + name = "segment" + } + + segments { + name = "segment2" + } + + segment_actions { + action = "create-route" + segment = "segment" + destination_cidr_blocks = [ + "10.0.0.0/16" + ] + destinations = [ + aws_networkmanager_vpc_attachment.example_us_west_2.id, + ] + } + + segment_actions { + action = "create-route" + segment = "segment" + destination_cidr_blocks = [ + "10.1.0.0/16" + ] + destinations = [ + aws_networkmanager_vpc_attachment.example_us_east_1.id, + ] + } +} + +resource "aws_networkmanager_core_network" "example" { + global_network_id = aws_networkmanager_global_network.example.id + base_policy_regions = ["us-west-2", "us-east-1"] + create_base_policy = true +} + +resource "aws_networkmanager_core_network_policy_attachment" "example" { + core_network_id = aws_networkmanager_core_network.example.id + policy_document = data.aws_networkmanager_core_network_policy_document.example.json +} + +resource "aws_networkmanager_vpc_attachment" "example_us_west_2" { + core_network_id = aws_networkmanager_core_network.example.id + subnet_arns = aws_subnet.example_us_west_2[*].arn + vpc_arn = aws_vpc.example_us_west_2.arn +} + +resource "aws_networkmanager_vpc_attachment" "example_us_east_1" { + provider = "alternate" + + core_network_id = aws_networkmanager_core_network.example.id + subnet_arns = aws_subnet.example_us_east_1[*].arn + vpc_arn = aws_vpc.example_us_east_1.arn +} +``` + ## Argument Reference The following arguments are supported: * `description` - (Optional) Description of the Core Network. -* `base_policy_region` - (Optional) The base policy created by setting the `create_base_policy` argument to `true` requires a region to be set in the `edge-locations`, `location` key. If `base_policy_region` is not specified, the region used in the base policy defaults to the region specified in the `provider` block. -* `create_base_policy` - (Optional) Specifies whether to create a base policy when a core network is created or updated. A base policy is created and set to `LIVE` to allow attachments to the core network (e.g. VPC Attachments) before applying a policy document provided using the [`aws_networkmanager_core_network_policy_attachment` resource](/docs/providers/aws/r/networkmanager_core_network_policy_attachment.html). This base policy is needed if your core network does not have any `LIVE` policies (e.g. a core network resource created without the `policy_document` argument) and your policy document has static routes pointing to VPC attachments and you want to attach your VPCs to the core network before applying the desired policy document. Valid values are `true` or `false`. Conflicts with `policy_document`. An example of this Terraform snippet can be found [above](#with-vpc-attachment). An example of a base policy created is shown below. The region specified in the `location` key can be configured using the `base_policy_region` argument. If `base_policy_region` is not specified, the region defaults to the region specified in the `provider` block. This base policy is overridden with the policy that you specify in the [`aws_networkmanager_core_network_policy_attachment` resource](/docs/providers/aws/r/networkmanager_core_network_policy_attachment.html). +* `base_policy_region` - (Optional, **Deprecated** use the `base_policy_regions` argument instead) The base policy created by setting the `create_base_policy` argument to `true` requires a region to be set in the `edge-locations`, `location` key. If `base_policy_region` is not specified, the region used in the base policy defaults to the region specified in the `provider` block. +* `base_policy_regions` - (Optional) A list of regions to add to the base policy. The base policy created by setting the `create_base_policy` argument to `true` requires one or more regions to be set in the `edge-locations`, `location` key. If `base_policy_regions` is not specified, the region used in the base policy defaults to the region specified in the `provider` block. +* `create_base_policy` - (Optional) Specifies whether to create a base policy when a core network is created or updated. A base policy is created and set to `LIVE` to allow attachments to the core network (e.g. VPC Attachments) before applying a policy document provided using the [`aws_networkmanager_core_network_policy_attachment` resource](/docs/providers/aws/r/networkmanager_core_network_policy_attachment.html). This base policy is needed if your core network does not have any `LIVE` policies (e.g. a core network resource created without the `policy_document` argument) and your policy document has static routes pointing to VPC attachments and you want to attach your VPCs to the core network before applying the desired policy document. Valid values are `true` or `false`. Conflicts with `policy_document`. An example of this Terraform snippet can be found above [for VPC Attachment in a single region](#with-vpc-attachment-single-region) and [for VPC Attachment multi-region](#with-vpc-attachment-multi-region). An example base policy is shown below. This base policy is overridden with the policy that you specify in the [`aws_networkmanager_core_network_policy_attachment` resource](/docs/providers/aws/r/networkmanager_core_network_policy_attachment.html). ```json { @@ -107,6 +185,7 @@ The following arguments are supported: "asn-ranges": [ "64512-65534" ], + "vpn-ecmp-support": false, "edge-locations": [ { "location": "us-east-1" @@ -116,7 +195,9 @@ The following arguments are supported: "segments": [ { "name": "segment", - "description": "base-policy" + "description": "base-policy", + "isolate-attachments": false, + "require-attachment-acceptance": false } ] } diff --git a/website/docs/r/networkmanager_core_network_policy_attachment.html.markdown b/website/docs/r/networkmanager_core_network_policy_attachment.html.markdown index d577ca651520..296993157add 100644 --- a/website/docs/r/networkmanager_core_network_policy_attachment.html.markdown +++ b/website/docs/r/networkmanager_core_network_policy_attachment.html.markdown @@ -29,7 +29,7 @@ resource "aws_networkmanager_core_network_policy_attachment" "example" { } ``` -### With VPC Attachment +### With VPC Attachment (Single Region) The example below illustrates the scenario where your policy document has static routes pointing to VPC attachments and you want to attach your VPCs to the core network before applying the desired policy document. Set the `create_base_policy` argument of the [`aws_networkmanager_core_network` resource](/docs/providers/aws/r/networkmanager_core_network.html) to `true` if your core network does not currently have any `LIVE` policies (e.g. this is the first `terraform apply` with the core network resource), since a `LIVE` policy is required before VPCs can be attached to the core network. Otherwise, if your core network already has a `LIVE` policy, you may exclude the `create_base_policy` argument. @@ -78,6 +78,83 @@ resource "aws_networkmanager_vpc_attachment" "example" { } ``` +### With VPC Attachment (Multi-Region) + +The example below illustrates the scenario where your policy document has static routes pointing to VPC attachments and you want to attach your VPCs to the core network before applying the desired policy document. Set the `create_base_policy` argument of the [`aws_networkmanager_core_network` resource](/docs/providers/aws/r/networkmanager_core_network.html) to `true` if your core network does not currently have any `LIVE` policies (e.g. this is the first `terraform apply` with the core network resource), since a `LIVE` policy is required before VPCs can be attached to the core network. Otherwise, if your core network already has a `LIVE` policy, you may exclude the `create_base_policy` argument. For multi-region in a core network that does not yet have a `LIVE` policy, pass a list of regions to the `aws_networkmanager_core_network` `base_policy_regions` argument. In the example below, `us-west-2` and `us-east-1` are specified in the base policy. + +```terraform +resource "aws_networkmanager_global_network" "example" {} + +data "aws_networkmanager_core_network_policy_document" "example" { + core_network_configuration { + asn_ranges = ["65022-65534"] + + edge_locations { + location = "us-west-2" + } + + edge_locations { + location = "us-east-1" + } + } + + segments { + name = "segment" + } + + segments { + name = "segment2" + } + + segment_actions { + action = "create-route" + segment = "segment" + destination_cidr_blocks = [ + "10.0.0.0/16" + ] + destinations = [ + aws_networkmanager_vpc_attachment.example_us_west_2.id, + ] + } + + segment_actions { + action = "create-route" + segment = "segment" + destination_cidr_blocks = [ + "10.1.0.0/16" + ] + destinations = [ + aws_networkmanager_vpc_attachment.example_us_east_1.id, + ] + } +} + +resource "aws_networkmanager_core_network" "example" { + global_network_id = aws_networkmanager_global_network.example.id + base_policy_regions = ["us-west-2", "us-east-1"] + create_base_policy = true +} + +resource "aws_networkmanager_core_network_policy_attachment" "example" { + core_network_id = aws_networkmanager_core_network.example.id + policy_document = data.aws_networkmanager_core_network_policy_document.example.json +} + +resource "aws_networkmanager_vpc_attachment" "example_us_west_2" { + core_network_id = aws_networkmanager_core_network.example.id + subnet_arns = aws_subnet.example_us_west_2[*].arn + vpc_arn = aws_vpc.example_us_west_2.arn +} + +resource "aws_networkmanager_vpc_attachment" "example_us_east_1" { + provider = "alternate" + + core_network_id = aws_networkmanager_core_network.example.id + subnet_arns = aws_subnet.example_us_east_1[*].arn + vpc_arn = aws_vpc.example_us_east_1.arn +} +``` + ## Argument Reference The following arguments are supported: