From 0dda704cbfa5852f96afb53ff7f98c3e7837388f Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 12 May 2015 13:24:32 -0500 Subject: [PATCH 1/5] provider/aws: Support multiple subnets in Network ACL --- .../providers/aws/resource_aws_network_acl.go | 134 ++++++++++++++++-- .../aws/resource_aws_network_acl_test.go | 109 +++++++++++++- 2 files changed, 228 insertions(+), 15 deletions(-) diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index 0d44ff321..bc751cab7 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "log" + "sort" "strconv" "time" @@ -30,10 +31,17 @@ func resourceAwsNetworkAcl() *schema.Resource { Computed: false, }, "subnet_id": &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: false, + Deprecated: "Attribute subnet_id is deprecated on network_acl resources. Use subnet_ids instead", + }, + "subnet_ids": &schema.Schema{ + Type: schema.TypeList, Optional: true, - ForceNew: true, - Computed: false, + // Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, "ingress": &schema.Schema{ Type: schema.TypeSet, @@ -168,6 +176,15 @@ func resourceAwsNetworkAclRead(d *schema.ResourceData, meta interface{}) error { d.Set("vpc_id", networkAcl.VPCID) d.Set("tags", tagsToMapSDK(networkAcl.Tags)) + var s []string + for _, a := range networkAcl.Associations { + s = append(s, *a.SubnetID) + } + sort.Strings(s) + if err := d.Set("subnet_ids", s); err != nil { + return err + } + if err := d.Set("ingress", networkAclEntriesToMapList(ingressEntries)); err != nil { return err } @@ -213,6 +230,64 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("subnet_ids") { + o, n := d.GetChange("subnet_ids") + + ol := o.([]interface{}) + var pre []string + for _, x := range ol { + pre = append(pre, x.(string)) + } + + nl := n.([]interface{}) + var post []string + for _, x := range nl { + post = append(post, x.(string)) + } + + remove := diffSubnets(pre, post) + add := diffSubnets(post, pre) + + if len(remove) > 0 { + // A Network ACL is required for each subnet. In order to disassociate a + // subnet from this ACL, we must associate it with the default ACL. + defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), conn) + if err != nil { + return fmt.Errorf("Failed to find Default ACL for VPC %s", d.Get("vpc_id").(string)) + } + for _, r := range remove { + association, err := findNetworkAclAssociation(r, conn) + if err != nil { + return fmt.Errorf("Failed to find acl association: acl %s with subnet %s: %s", d.Id(), r, err) + } + _, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{ + AssociationID: association.NetworkACLAssociationID, + NetworkACLID: defaultAcl.NetworkACLID, + }) + if err != nil { + return err + } + } + } + + if len(add) > 0 { + for _, a := range add { + association, err := findNetworkAclAssociation(a, conn) + if err != nil { + return fmt.Errorf("Failed to find acl association: acl %s with subnet %s: %s", d.Id(), a, err) + } + _, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{ + AssociationID: association.NetworkACLAssociationID, + NetworkACLID: aws.String(d.Id()), + }) + if err != nil { + return err + } + } + } + + } + if err := setTagsSDK(conn, d); err != nil { return err } else { @@ -326,18 +401,36 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error case "DependencyViolation": // In case of dependency violation, we remove the association between subnet and network acl. // This means the subnet is attached to default acl of vpc. - association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), conn) - if err != nil { - return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)} + var associations []*ec2.NetworkACLAssociation + if v, ok := d.GetOk("subnet_id"); ok { + a, err := findNetworkAclAssociation(v.(string), conn) + if err != nil { + return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)} + } + associations = append(associations, a) + } + + if v, ok := d.GetOk("subnet_ids"); ok { + ids := v.([]interface{}) + for _, i := range ids { + a, err := findNetworkAclAssociation(i.(string), conn) + if err != nil { + return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)} + } + associations = append(associations, a) + } } defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), conn) if err != nil { return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)} } - _, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{ - AssociationID: association.NetworkACLAssociationID, - NetworkACLID: defaultAcl.NetworkACLID, - }) + + for _, a := range associations { + _, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{ + AssociationID: a.NetworkACLAssociationID, + NetworkACLID: defaultAcl.NetworkACLID, + }) + } return resource.RetryError{Err: err} default: // Any other error, we want to quit the retry loop immediately @@ -417,7 +510,7 @@ func findNetworkAclAssociation(subnetId string, conn *ec2.EC2) (networkAclAssoci } } } - return nil, fmt.Errorf("could not find association for subnet %s ", subnetId) + return nil, fmt.Errorf("could not find association for subnet: %s ", subnetId) } // networkAclEntriesToMapList turns ingress/egress rules read from AWS into a list @@ -451,3 +544,22 @@ func networkAclEntriesToMapList(networkAcls []*ec2.NetworkACLEntry) []map[string return result } + +func diffSubnets(o, n []string) []string { + m := make(map[string]int) + + for _, y := range n { + m[y]++ + } + + var ret []string + for _, x := range o { + if m[x] > 0 { + m[x]-- + continue + } + ret = append(ret, x) + } + + return ret +} diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index 7a57a0012..32991f670 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -10,6 +10,72 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func TestDiffSubnets(t *testing.T) { + removal := []struct { + First []string + Second []string + Output []string + }{ + {[]string{"old"}, []string{"new"}, []string{"old"}}, + {[]string{"new"}, []string{"old"}, []string{"new"}}, + {[]string{"one", "two"}, []string{"two"}, []string{"one"}}, + { + []string{"subnet-1234", "subnet-5667", "subnet-897"}, + []string{"subnet-1234", "subnet-897"}, + []string{"subnet-5667"}, + }, + { + []string{"subnet-1234", "subnet-897"}, + []string{"subnet-1234", "subnet-5667", "subnet-897"}, + []string{}, + }, + } + for _, tc := range removal { + actual := diffSubnets(tc.First, tc.Second) + if len(actual) != len(tc.Output) { + t.Fatalf("\n\texpected: %#v \n\tactual: %#v\n", tc.Output, actual) + } + + for i, x := range tc.Output { + if x != actual[i] { + t.Fatalf("Network ACL diff does not match, expected %#v, got %#v", x, actual[i]) + } + } + } + + addition := []struct { + First []string + Second []string + Output []string + }{ + {[]string{"old"}, []string{"new"}, []string{"new"}}, + {[]string{"new"}, []string{"old"}, []string{"old"}}, + {[]string{"one", "two"}, []string{"two"}, []string{}}, + { + []string{"subnet-1234", "subnet-5667", "subnet-897"}, + []string{"subnet-1234", "subnet-897"}, + []string{}, + }, + { + []string{"subnet-1234", "subnet-897"}, + []string{"subnet-1234", "subnet-5667", "subnet-897"}, + []string{"subnet-5667"}, + }, + } + for _, tc := range addition { + actual := diffSubnets(tc.Second, tc.First) + if len(actual) != len(tc.Output) { + t.Fatalf("\n\texpected: %#v \n\tactual: %#v\n", tc.Output, actual) + } + + for i, x := range tc.Output { + if x != actual[i] { + t.Fatalf("Network ACL diff does not match, expected %#v, got %#v", x, actual[i]) + } + } + } +} + func TestAccAWSNetworkAcl_EgressAndIngressRules(t *testing.T) { var networkAcl ec2.NetworkACL @@ -181,6 +247,24 @@ func TestAccAWSNetworkAcl_SubnetChange(t *testing.T) { } +func TestAccAWSNetworkAcl_Subnets(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNetworkAclDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSNetworkAclSubnet_SubnetIds, + Check: resource.ComposeTestCheckFunc( + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.one"), + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.two"), + ), + }, + }, + }) + +} + func testAccCheckAWSNetworkAclDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -281,10 +365,6 @@ func testAccCheckSubnetIsAssociatedWithAcl(acl string, sub string) resource.Test return nil } - // r, _ := conn.NetworkACLs([]string{}, ec2.NewFilter()) - // fmt.Printf("\n\nall acls\n %#v\n\n", r.NetworkAcls) - // conn.NetworkAcls([]string{}, filter) - return fmt.Errorf("Network Acl %s is not associated with subnet %s", acl, sub) } } @@ -494,3 +574,24 @@ resource "aws_network_acl" "bar" { subnet_id = "${aws_subnet.new.id}" } ` + +const testAccAWSNetworkAclSubnet_SubnetIds = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" + tags { + Name = "acl-subnets-test" + } +} +resource "aws_subnet" "one" { + cidr_block = "10.1.111.0/24" + vpc_id = "${aws_vpc.foo.id}" +} +resource "aws_subnet" "two" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" +} +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" + subnet_ids = ["${aws_subnet.one.id}", "${aws_subnet.two.id}"] +} +` From 898fa915953caacd87e38bb9163eac42c6a34aaf Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 12 May 2015 22:23:55 -0500 Subject: [PATCH 2/5] network acl cleanups --- .../providers/aws/resource_aws_network_acl.go | 6 +-- .../aws/resource_aws_network_acl_test.go | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index bc751cab7..efdf1a525 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -233,15 +233,13 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error if d.HasChange("subnet_ids") { o, n := d.GetChange("subnet_ids") - ol := o.([]interface{}) var pre []string - for _, x := range ol { + for _, x := range o.([]interface{}) { pre = append(pre, x.(string)) } - nl := n.([]interface{}) var post []string - for _, x := range nl { + for _, x := range n.([]interface{}) { post = append(post, x.(string)) } diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index 32991f670..1b7ae81cc 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -260,6 +260,15 @@ func TestAccAWSNetworkAcl_Subnets(t *testing.T) { testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.two"), ), }, + + resource.TestStep{ + Config: testAccAWSNetworkAclSubnet_SubnetIdsUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.one"), + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.three"), + testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.four"), + ), + }, }, }) @@ -595,3 +604,37 @@ resource "aws_network_acl" "bar" { subnet_ids = ["${aws_subnet.one.id}", "${aws_subnet.two.id}"] } ` + +const testAccAWSNetworkAclSubnet_SubnetIdsUpdate = ` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" + tags { + Name = "acl-subnets-test" + } +} +resource "aws_subnet" "one" { + cidr_block = "10.1.111.0/24" + vpc_id = "${aws_vpc.foo.id}" +} +resource "aws_subnet" "two" { + cidr_block = "10.1.1.0/24" + vpc_id = "${aws_vpc.foo.id}" +} + +resource "aws_subnet" "three" { + cidr_block = "10.1.222.0/24" + vpc_id = "${aws_vpc.foo.id}" +} +resource "aws_subnet" "four" { + cidr_block = "10.1.4.0/24" + vpc_id = "${aws_vpc.foo.id}" +} +resource "aws_network_acl" "bar" { + vpc_id = "${aws_vpc.foo.id}" + subnet_ids = [ + "${aws_subnet.one.id}", + "${aws_subnet.three.id}", + "${aws_subnet.four.id}", + ] +} +` From 468de49265ada44dbba08b1e8870537b4f938d22 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Thu, 14 May 2015 17:09:50 -0500 Subject: [PATCH 3/5] upgrade to use typeset for subnet_ids --- .../providers/aws/resource_aws_network_acl.go | 64 +++++++----------- .../aws/resource_aws_network_acl_test.go | 66 ------------------- 2 files changed, 23 insertions(+), 107 deletions(-) diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index efdf1a525..e86b0aed5 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -31,17 +31,19 @@ func resourceAwsNetworkAcl() *schema.Resource { Computed: false, }, "subnet_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: false, - Deprecated: "Attribute subnet_id is deprecated on network_acl resources. Use subnet_ids instead", + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: false, + ConflictsWith: []string{"subnet_ids"}, + Deprecated: "Attribute subnet_id is deprecated on network_acl resources. Use subnet_ids instead", }, "subnet_ids": &schema.Schema{ - Type: schema.TypeList, - Optional: true, - // Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"subnet_id"}, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, }, "ingress": &schema.Schema{ Type: schema.TypeSet, @@ -232,19 +234,18 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error if d.HasChange("subnet_ids") { o, n := d.GetChange("subnet_ids") - - var pre []string - for _, x := range o.([]interface{}) { - pre = append(pre, x.(string)) + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) } - var post []string - for _, x := range n.([]interface{}) { - post = append(post, x.(string)) - } + os := o.(*schema.Set) + ns := n.(*schema.Set) - remove := diffSubnets(pre, post) - add := diffSubnets(post, pre) + remove := os.Difference(ns).List() + add := ns.Difference(os).List() if len(remove) > 0 { // A Network ACL is required for each subnet. In order to disassociate a @@ -254,7 +255,7 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Failed to find Default ACL for VPC %s", d.Get("vpc_id").(string)) } for _, r := range remove { - association, err := findNetworkAclAssociation(r, conn) + association, err := findNetworkAclAssociation(r.(string), conn) if err != nil { return fmt.Errorf("Failed to find acl association: acl %s with subnet %s: %s", d.Id(), r, err) } @@ -270,7 +271,7 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error if len(add) > 0 { for _, a := range add { - association, err := findNetworkAclAssociation(a, conn) + association, err := findNetworkAclAssociation(a.(string), conn) if err != nil { return fmt.Errorf("Failed to find acl association: acl %s with subnet %s: %s", d.Id(), a, err) } @@ -409,7 +410,7 @@ func resourceAwsNetworkAclDelete(d *schema.ResourceData, meta interface{}) error } if v, ok := d.GetOk("subnet_ids"); ok { - ids := v.([]interface{}) + ids := v.(*schema.Set).List() for _, i := range ids { a, err := findNetworkAclAssociation(i.(string), conn) if err != nil { @@ -542,22 +543,3 @@ func networkAclEntriesToMapList(networkAcls []*ec2.NetworkACLEntry) []map[string return result } - -func diffSubnets(o, n []string) []string { - m := make(map[string]int) - - for _, y := range n { - m[y]++ - } - - var ret []string - for _, x := range o { - if m[x] > 0 { - m[x]-- - continue - } - ret = append(ret, x) - } - - return ret -} diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index 1b7ae81cc..075158ef6 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -10,72 +10,6 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestDiffSubnets(t *testing.T) { - removal := []struct { - First []string - Second []string - Output []string - }{ - {[]string{"old"}, []string{"new"}, []string{"old"}}, - {[]string{"new"}, []string{"old"}, []string{"new"}}, - {[]string{"one", "two"}, []string{"two"}, []string{"one"}}, - { - []string{"subnet-1234", "subnet-5667", "subnet-897"}, - []string{"subnet-1234", "subnet-897"}, - []string{"subnet-5667"}, - }, - { - []string{"subnet-1234", "subnet-897"}, - []string{"subnet-1234", "subnet-5667", "subnet-897"}, - []string{}, - }, - } - for _, tc := range removal { - actual := diffSubnets(tc.First, tc.Second) - if len(actual) != len(tc.Output) { - t.Fatalf("\n\texpected: %#v \n\tactual: %#v\n", tc.Output, actual) - } - - for i, x := range tc.Output { - if x != actual[i] { - t.Fatalf("Network ACL diff does not match, expected %#v, got %#v", x, actual[i]) - } - } - } - - addition := []struct { - First []string - Second []string - Output []string - }{ - {[]string{"old"}, []string{"new"}, []string{"new"}}, - {[]string{"new"}, []string{"old"}, []string{"old"}}, - {[]string{"one", "two"}, []string{"two"}, []string{}}, - { - []string{"subnet-1234", "subnet-5667", "subnet-897"}, - []string{"subnet-1234", "subnet-897"}, - []string{}, - }, - { - []string{"subnet-1234", "subnet-897"}, - []string{"subnet-1234", "subnet-5667", "subnet-897"}, - []string{"subnet-5667"}, - }, - } - for _, tc := range addition { - actual := diffSubnets(tc.Second, tc.First) - if len(actual) != len(tc.Output) { - t.Fatalf("\n\texpected: %#v \n\tactual: %#v\n", tc.Output, actual) - } - - for i, x := range tc.Output { - if x != actual[i] { - t.Fatalf("Network ACL diff does not match, expected %#v, got %#v", x, actual[i]) - } - } - } -} - func TestAccAWSNetworkAcl_EgressAndIngressRules(t *testing.T) { var networkAcl ec2.NetworkACL From d9521efbf6e45bb48b018f82149e975622ef4861 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Thu, 14 May 2015 20:57:07 -0500 Subject: [PATCH 4/5] provider/aws: Add tests for Network ACL subnets --- .../aws/resource_aws_network_acl_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/builtin/providers/aws/resource_aws_network_acl_test.go b/builtin/providers/aws/resource_aws_network_acl_test.go index 075158ef6..ba9b8b018 100644 --- a/builtin/providers/aws/resource_aws_network_acl_test.go +++ b/builtin/providers/aws/resource_aws_network_acl_test.go @@ -182,6 +182,18 @@ func TestAccAWSNetworkAcl_SubnetChange(t *testing.T) { } func TestAccAWSNetworkAcl_Subnets(t *testing.T) { + var networkAcl ec2.NetworkACL + + checkACLSubnets := func(acl *ec2.NetworkACL, count int) resource.TestCheckFunc { + return func(*terraform.State) (err error) { + if count != len(acl.Associations) { + return fmt.Errorf("ACL association count does not match, expected %d, got %d", count, len(acl.Associations)) + } + + return nil + } + } + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -190,17 +202,21 @@ func TestAccAWSNetworkAcl_Subnets(t *testing.T) { resource.TestStep{ Config: testAccAWSNetworkAclSubnet_SubnetIds, Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.one"), testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.two"), + checkACLSubnets(&networkAcl, 2), ), }, resource.TestStep{ Config: testAccAWSNetworkAclSubnet_SubnetIdsUpdate, Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl), testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.one"), testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.three"), testAccCheckSubnetIsAssociatedWithAcl("aws_network_acl.bar", "aws_subnet.four"), + checkACLSubnets(&networkAcl, 3), ), }, }, From bf65f7c0138623e72b6791748bff29fcaea088d2 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Fri, 15 May 2015 09:35:38 -0500 Subject: [PATCH 5/5] document Network ACL Subnet IDs attribute --- website/source/docs/providers/aws/r/network_acl.html.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/source/docs/providers/aws/r/network_acl.html.markdown b/website/source/docs/providers/aws/r/network_acl.html.markdown index 71b93fda3..3451b55ff 100644 --- a/website/source/docs/providers/aws/r/network_acl.html.markdown +++ b/website/source/docs/providers/aws/r/network_acl.html.markdown @@ -45,7 +45,9 @@ resource "aws_network_acl" "main" { The following arguments are supported: * `vpc_id` - (Required) The ID of the associated VPC. -* `subnet_id` - (Optional) The ID of the associated subnet. +* `subnet_ids` - (Optional) A list of Subnet IDs to apply the ACL to +* `subnet_id` - (Optional, Deprecated) The ID of the associated Subnet. This +attribute is deprecated, please use the `subnet_ids` attribute instead * `ingress` - (Optional) Specifies an ingress rule. Parameters defined below. * `egress` - (Optional) Specifies an egress rule. Parameters defined below. * `tags` - (Optional) A mapping of tags to assign to the resource.