diff --git a/builtin/providers/aws/network_acl_entry.go b/builtin/providers/aws/network_acl_entry.go index 9c93544c1..7ba87712c 100644 --- a/builtin/providers/aws/network_acl_entry.go +++ b/builtin/providers/aws/network_acl_entry.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "net" "strconv" "github.com/awslabs/aws-sdk-go/aws" @@ -82,3 +83,17 @@ func validatePorts(to int64, from int64, expected expectedPortPair) bool { return true } + +// validateCIDRBlock ensures the passed CIDR block represents an implied +// network, and not an overly-specified IP address. +func validateCIDRBlock(cidr string) error { + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return err + } + if ipnet.String() != cidr { + return fmt.Errorf("%s is not a valid mask; did you mean %s?", cidr, ipnet) + } + + return nil +} diff --git a/builtin/providers/aws/network_acl_entry_test.go b/builtin/providers/aws/network_acl_entry_test.go index 7ca66dcd8..95fa69dae 100644 --- a/builtin/providers/aws/network_acl_entry_test.go +++ b/builtin/providers/aws/network_acl_entry_test.go @@ -152,3 +152,23 @@ func Test_validatePorts(t *testing.T) { } } } + +func Test_validateCIDRBlock(t *testing.T) { + for _, ts := range []struct { + cidr string + shouldErr bool + }{ + {"10.2.2.0/24", false}, + {"10.2.2.0/1234", true}, + {"10/24", true}, + {"10.2.2.2/24", true}, + } { + err := validateCIDRBlock(ts.cidr) + if ts.shouldErr && err == nil { + t.Fatalf("Input '%s' should error but didn't!", ts.cidr) + } + if !ts.shouldErr && err != nil { + t.Fatalf("Got unexpected error for '%s' input: %s", ts.cidr, err) + } + } +} diff --git a/builtin/providers/aws/resource_aws_network_acl.go b/builtin/providers/aws/resource_aws_network_acl.go index af91f9cce..e37b04ca4 100644 --- a/builtin/providers/aws/resource_aws_network_acl.go +++ b/builtin/providers/aws/resource_aws_network_acl.go @@ -284,8 +284,16 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2 } } + // AWS mutates the CIDR block into a network implied by the IP and + // mask provided. This results in hashing inconsistencies between + // the local config file and the state returned by the API. Error + // if the user provides a CIDR block with an inappropriate mask + if err := validateCIDRBlock(*add.CIDRBlock); err != nil { + return err + } + // Add new Acl entry - _, err := conn.CreateNetworkACLEntry(&ec2.CreateNetworkACLEntryInput{ + _, connErr := conn.CreateNetworkACLEntry(&ec2.CreateNetworkACLEntryInput{ NetworkACLID: aws.String(d.Id()), CIDRBlock: add.CIDRBlock, Egress: add.Egress, @@ -294,7 +302,7 @@ func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2 RuleAction: add.RuleAction, RuleNumber: add.RuleNumber, }) - if err != nil { + if connErr != nil { return fmt.Errorf("Error creating %s entry: %s", entryType, err) } }