Merge pull request #4286 from stack72/aws-network-acl-rule
provider/aws: aws_network_acl_rule
This commit is contained in:
commit
7c1811df36
|
@ -69,6 +69,15 @@ func flattenNetworkAclEntries(list []*ec2.NetworkAclEntry) []map[string]interfac
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func protocolStrings(protocolIntegers map[string]int) map[int]string {
|
||||||
|
protocolStrings := make(map[int]string, len(protocolIntegers))
|
||||||
|
for k, v := range protocolIntegers {
|
||||||
|
protocolStrings[v] = k
|
||||||
|
}
|
||||||
|
|
||||||
|
return protocolStrings
|
||||||
|
}
|
||||||
|
|
||||||
func protocolIntegers() map[string]int {
|
func protocolIntegers() map[string]int {
|
||||||
var protocolIntegers = make(map[string]int)
|
var protocolIntegers = make(map[string]int)
|
||||||
protocolIntegers = map[string]int{
|
protocolIntegers = map[string]int{
|
||||||
|
|
|
@ -153,6 +153,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_main_route_table_association": resourceAwsMainRouteTableAssociation(),
|
"aws_main_route_table_association": resourceAwsMainRouteTableAssociation(),
|
||||||
"aws_nat_gateway": resourceAwsNatGateway(),
|
"aws_nat_gateway": resourceAwsNatGateway(),
|
||||||
"aws_network_acl": resourceAwsNetworkAcl(),
|
"aws_network_acl": resourceAwsNetworkAcl(),
|
||||||
|
"aws_network_acl_rule": resourceAwsNetworkAclRule(),
|
||||||
"aws_network_interface": resourceAwsNetworkInterface(),
|
"aws_network_interface": resourceAwsNetworkInterface(),
|
||||||
"aws_opsworks_stack": resourceAwsOpsworksStack(),
|
"aws_opsworks_stack": resourceAwsOpsworksStack(),
|
||||||
"aws_opsworks_java_app_layer": resourceAwsOpsworksJavaAppLayer(),
|
"aws_opsworks_java_app_layer": resourceAwsOpsworksJavaAppLayer(),
|
||||||
|
|
|
@ -50,6 +50,7 @@ func resourceAwsNetworkAcl() *schema.Resource {
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeSet,
|
||||||
Required: false,
|
Required: false,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
Computed: false,
|
||||||
Elem: &schema.Resource{
|
Elem: &schema.Resource{
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"from_port": &schema.Schema{
|
"from_port": &schema.Schema{
|
||||||
|
@ -92,6 +93,7 @@ func resourceAwsNetworkAcl() *schema.Resource {
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeSet,
|
||||||
Required: false,
|
Required: false,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
Computed: false,
|
||||||
Elem: &schema.Resource{
|
Elem: &schema.Resource{
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"from_port": &schema.Schema{
|
"from_port": &schema.Schema{
|
||||||
|
@ -316,87 +318,89 @@ func resourceAwsNetworkAclUpdate(d *schema.ResourceData, meta interface{}) error
|
||||||
|
|
||||||
func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2.EC2) error {
|
func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2.EC2) error {
|
||||||
|
|
||||||
o, n := d.GetChange(entryType)
|
if d.HasChange(entryType) {
|
||||||
|
o, n := d.GetChange(entryType)
|
||||||
|
|
||||||
if o == nil {
|
if o == nil {
|
||||||
o = new(schema.Set)
|
o = new(schema.Set)
|
||||||
}
|
}
|
||||||
if n == nil {
|
if n == nil {
|
||||||
n = new(schema.Set)
|
n = new(schema.Set)
|
||||||
}
|
|
||||||
|
|
||||||
os := o.(*schema.Set)
|
|
||||||
ns := n.(*schema.Set)
|
|
||||||
|
|
||||||
toBeDeleted, err := expandNetworkAclEntries(os.Difference(ns).List(), entryType)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, remove := range toBeDeleted {
|
|
||||||
|
|
||||||
// AWS includes default rules with all network ACLs that can be
|
|
||||||
// neither modified nor destroyed. They have a custom rule
|
|
||||||
// number that is out of bounds for any other rule. If we
|
|
||||||
// encounter it, just continue. There's no work to be done.
|
|
||||||
if *remove.RuleNumber == 32767 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete old Acl
|
os := o.(*schema.Set)
|
||||||
_, err := conn.DeleteNetworkAclEntry(&ec2.DeleteNetworkAclEntryInput{
|
ns := n.(*schema.Set)
|
||||||
NetworkAclId: aws.String(d.Id()),
|
|
||||||
RuleNumber: remove.RuleNumber,
|
toBeDeleted, err := expandNetworkAclEntries(os.Difference(ns).List(), entryType)
|
||||||
Egress: remove.Egress,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error deleting %s entry: %s", entryType, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeCreated, err := expandNetworkAclEntries(ns.Difference(os).List(), entryType)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, add := range toBeCreated {
|
|
||||||
// Protocol -1 rules don't store ports in AWS. Thus, they'll always
|
|
||||||
// hash differently when being read out of the API. Force the user
|
|
||||||
// to set from_port and to_port to 0 for these rules, to keep the
|
|
||||||
// hashing consistent.
|
|
||||||
if *add.Protocol == "-1" {
|
|
||||||
to := *add.PortRange.To
|
|
||||||
from := *add.PortRange.From
|
|
||||||
expected := &expectedPortPair{
|
|
||||||
to_port: 0,
|
|
||||||
from_port: 0,
|
|
||||||
}
|
|
||||||
if ok := validatePorts(to, from, *expected); !ok {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"to_port (%d) and from_port (%d) must both be 0 to use the the 'all' \"-1\" protocol!",
|
|
||||||
to, from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
for _, remove := range toBeDeleted {
|
||||||
|
|
||||||
// Add new Acl entry
|
// AWS includes default rules with all network ACLs that can be
|
||||||
_, connErr := conn.CreateNetworkAclEntry(&ec2.CreateNetworkAclEntryInput{
|
// neither modified nor destroyed. They have a custom rule
|
||||||
NetworkAclId: aws.String(d.Id()),
|
// number that is out of bounds for any other rule. If we
|
||||||
CidrBlock: add.CidrBlock,
|
// encounter it, just continue. There's no work to be done.
|
||||||
Egress: add.Egress,
|
if *remove.RuleNumber == 32767 {
|
||||||
PortRange: add.PortRange,
|
continue
|
||||||
Protocol: add.Protocol,
|
}
|
||||||
RuleAction: add.RuleAction,
|
|
||||||
RuleNumber: add.RuleNumber,
|
// Delete old Acl
|
||||||
IcmpTypeCode: add.IcmpTypeCode,
|
_, err := conn.DeleteNetworkAclEntry(&ec2.DeleteNetworkAclEntryInput{
|
||||||
})
|
NetworkAclId: aws.String(d.Id()),
|
||||||
if connErr != nil {
|
RuleNumber: remove.RuleNumber,
|
||||||
return fmt.Errorf("Error creating %s entry: %s", entryType, connErr)
|
Egress: remove.Egress,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting %s entry: %s", entryType, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toBeCreated, err := expandNetworkAclEntries(ns.Difference(os).List(), entryType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, add := range toBeCreated {
|
||||||
|
// Protocol -1 rules don't store ports in AWS. Thus, they'll always
|
||||||
|
// hash differently when being read out of the API. Force the user
|
||||||
|
// to set from_port and to_port to 0 for these rules, to keep the
|
||||||
|
// hashing consistent.
|
||||||
|
if *add.Protocol == "-1" {
|
||||||
|
to := *add.PortRange.To
|
||||||
|
from := *add.PortRange.From
|
||||||
|
expected := &expectedPortPair{
|
||||||
|
to_port: 0,
|
||||||
|
from_port: 0,
|
||||||
|
}
|
||||||
|
if ok := validatePorts(to, from, *expected); !ok {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"to_port (%d) and from_port (%d) must both be 0 to use the the 'all' \"-1\" protocol!",
|
||||||
|
to, from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
_, connErr := conn.CreateNetworkAclEntry(&ec2.CreateNetworkAclEntryInput{
|
||||||
|
NetworkAclId: aws.String(d.Id()),
|
||||||
|
CidrBlock: add.CidrBlock,
|
||||||
|
Egress: add.Egress,
|
||||||
|
PortRange: add.PortRange,
|
||||||
|
Protocol: add.Protocol,
|
||||||
|
RuleAction: add.RuleAction,
|
||||||
|
RuleNumber: add.RuleNumber,
|
||||||
|
IcmpTypeCode: add.IcmpTypeCode,
|
||||||
|
})
|
||||||
|
if connErr != nil {
|
||||||
|
return fmt.Errorf("Error creating %s entry: %s", entryType, connErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAwsNetworkAclRule() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsNetworkAclRuleCreate,
|
||||||
|
Read: resourceAwsNetworkAclRuleRead,
|
||||||
|
Delete: resourceAwsNetworkAclRuleDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"network_acl_id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"rule_number": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"egress": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
"protocol": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"rule_action": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"cidr_block": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"from_port": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"to_port": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"icmp_type": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"icmp_code": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsNetworkAclRuleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
|
||||||
|
protocol := d.Get("protocol").(string)
|
||||||
|
p, protocolErr := strconv.Atoi(protocol)
|
||||||
|
if protocolErr != nil {
|
||||||
|
var ok bool
|
||||||
|
p, ok = protocolIntegers()[protocol]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Invalid Protocol %s for rule %#v", protocol, d.Get("rule_number").(int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("[INFO] Transformed Protocol %s into %d", protocol, p)
|
||||||
|
|
||||||
|
params := &ec2.CreateNetworkAclEntryInput{
|
||||||
|
NetworkAclId: aws.String(d.Get("network_acl_id").(string)),
|
||||||
|
Egress: aws.Bool(d.Get("egress").(bool)),
|
||||||
|
RuleNumber: aws.Int64(int64(d.Get("rule_number").(int))),
|
||||||
|
Protocol: aws.String(strconv.Itoa(p)),
|
||||||
|
CidrBlock: aws.String(d.Get("cidr_block").(string)),
|
||||||
|
RuleAction: aws.String(d.Get("rule_action").(string)),
|
||||||
|
PortRange: &ec2.PortRange{
|
||||||
|
From: aws.Int64(int64(d.Get("from_port").(int))),
|
||||||
|
To: aws.Int64(int64(d.Get("to_port").(int))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify additional required fields for ICMP
|
||||||
|
if p == 1 {
|
||||||
|
params.IcmpTypeCode = &ec2.IcmpTypeCode{}
|
||||||
|
if v, ok := d.GetOk("icmp_code"); ok {
|
||||||
|
params.IcmpTypeCode.Code = aws.Int64(int64(v.(int)))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("icmp_type"); ok {
|
||||||
|
params.IcmpTypeCode.Type = aws.Int64(int64(v.(int)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Creating Network Acl Rule: %d (%t)", d.Get("rule_number").(int), d.Get("egress").(bool))
|
||||||
|
_, err := conn.CreateNetworkAclEntry(params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Creating Network Acl Rule: %s", err.Error())
|
||||||
|
}
|
||||||
|
d.SetId(networkAclIdRuleNumberEgressHash(d.Get("network_acl_id").(string), d.Get("rule_number").(int), d.Get("egress").(bool), d.Get("protocol").(string)))
|
||||||
|
return resourceAwsNetworkAclRuleRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsNetworkAclRuleRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
resp, err := findNetworkAclRule(d, meta)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("rule_number", resp.RuleNumber)
|
||||||
|
d.Set("cidr_block", resp.CidrBlock)
|
||||||
|
d.Set("egress", resp.Egress)
|
||||||
|
if resp.IcmpTypeCode != nil {
|
||||||
|
d.Set("icmp_code", resp.IcmpTypeCode.Code)
|
||||||
|
d.Set("icmp_type", resp.IcmpTypeCode.Type)
|
||||||
|
}
|
||||||
|
if resp.PortRange != nil {
|
||||||
|
d.Set("from_port", resp.PortRange.From)
|
||||||
|
d.Set("to_port", resp.PortRange.To)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("rule_action", resp.RuleAction)
|
||||||
|
|
||||||
|
p, protocolErr := strconv.Atoi(*resp.Protocol)
|
||||||
|
log.Printf("[INFO] Converting the protocol %v", p)
|
||||||
|
if protocolErr == nil {
|
||||||
|
var ok bool
|
||||||
|
protocol, ok := protocolStrings(protocolIntegers())[p]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Invalid Protocol %s for rule %#v", *resp.Protocol, d.Get("rule_number").(int))
|
||||||
|
}
|
||||||
|
log.Printf("[INFO] Transformed Protocol %s back into %s", *resp.Protocol, protocol)
|
||||||
|
d.Set("protocol", protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsNetworkAclRuleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
|
||||||
|
params := &ec2.DeleteNetworkAclEntryInput{
|
||||||
|
NetworkAclId: aws.String(d.Get("network_acl_id").(string)),
|
||||||
|
RuleNumber: aws.Int64(int64(d.Get("rule_number").(int))),
|
||||||
|
Egress: aws.Bool(d.Get("egress").(bool)),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Deleting Network Acl Rule: %s", d.Id())
|
||||||
|
_, err := conn.DeleteNetworkAclEntry(params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Deleting Network Acl Rule: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findNetworkAclRule(d *schema.ResourceData, meta interface{}) (*ec2.NetworkAclEntry, error) {
|
||||||
|
conn := meta.(*AWSClient).ec2conn
|
||||||
|
|
||||||
|
filters := make([]*ec2.Filter, 0, 2)
|
||||||
|
ruleNumberFilter := &ec2.Filter{
|
||||||
|
Name: aws.String("entry.rule-number"),
|
||||||
|
Values: []*string{aws.String(fmt.Sprintf("%v", d.Get("rule_number").(int)))},
|
||||||
|
}
|
||||||
|
filters = append(filters, ruleNumberFilter)
|
||||||
|
egressFilter := &ec2.Filter{
|
||||||
|
Name: aws.String("entry.egress"),
|
||||||
|
Values: []*string{aws.String(fmt.Sprintf("%v", d.Get("egress").(bool)))},
|
||||||
|
}
|
||||||
|
filters = append(filters, egressFilter)
|
||||||
|
params := &ec2.DescribeNetworkAclsInput{
|
||||||
|
NetworkAclIds: []*string{aws.String(d.Get("network_acl_id").(string))},
|
||||||
|
Filters: filters,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Describing Network Acl: %s", d.Get("network_acl_id").(string))
|
||||||
|
log.Printf("[INFO] Describing Network Acl with the Filters %#v", params)
|
||||||
|
resp, err := conn.DescribeNetworkAcls(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error Finding Network Acl Rule %d: %s", d.Get("rule_number").(int), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp == nil || len(resp.NetworkAcls) != 1 || resp.NetworkAcls[0] == nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Expected to find one Network ACL, got: %#v",
|
||||||
|
resp.NetworkAcls)
|
||||||
|
}
|
||||||
|
networkAcl := resp.NetworkAcls[0]
|
||||||
|
if networkAcl.Entries != nil {
|
||||||
|
for _, i := range networkAcl.Entries {
|
||||||
|
if *i.RuleNumber == int64(d.Get("rule_number").(int)) && *i.Egress == d.Get("egress").(bool) {
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Expected the Network ACL to have Entries, got: %#v",
|
||||||
|
networkAcl)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func networkAclIdRuleNumberEgressHash(networkAclId string, ruleNumber int, egress bool, protocol string) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", networkAclId))
|
||||||
|
buf.WriteString(fmt.Sprintf("%d-", ruleNumber))
|
||||||
|
buf.WriteString(fmt.Sprintf("%t-", egress))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", protocol))
|
||||||
|
return fmt.Sprintf("nacl-%d", hashcode.String(buf.String()))
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSNetworkAclRule_basic(t *testing.T) {
|
||||||
|
var networkAcl ec2.NetworkAcl
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSNetworkAclRuleDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSNetworkAclRuleBasicConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSNetworkAclRuleExists("aws_network_acl_rule.bar", &networkAcl),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSNetworkAclRuleDestroy(s *terraform.State) error {
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||||
|
if rs.Type != "aws_network_acl_rule" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &ec2.DescribeNetworkAclsInput{
|
||||||
|
NetworkAclIds: []*string{aws.String(rs.Primary.ID)},
|
||||||
|
}
|
||||||
|
resp, err := conn.DescribeNetworkAcls(req)
|
||||||
|
if err == nil {
|
||||||
|
if len(resp.NetworkAcls) > 0 && *resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID {
|
||||||
|
networkAcl := resp.NetworkAcls[0]
|
||||||
|
if networkAcl.Entries != nil {
|
||||||
|
return fmt.Errorf("Network ACL Entries still exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ec2err, ok := err.(awserr.Error)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ec2err.Code() != "InvalidNetworkAclEntry.NotFound" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSNetworkAclRuleExists(n string, networkAcl *ec2.NetworkAcl) resource.TestCheckFunc {
|
||||||
|
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No Network ACL Id is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &ec2.DescribeNetworkAclsInput{
|
||||||
|
NetworkAclIds: []*string{aws.String(rs.Primary.ID)},
|
||||||
|
}
|
||||||
|
resp, err := conn.DescribeNetworkAcls(req)
|
||||||
|
if err == nil {
|
||||||
|
if len(resp.NetworkAcls) > 0 && *resp.NetworkAcls[0].NetworkAclId == rs.Primary.ID {
|
||||||
|
networkAcl := resp.NetworkAcls[0]
|
||||||
|
if networkAcl.Entries == nil {
|
||||||
|
return fmt.Errorf("No Network ACL Entries exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ec2err, ok := err.(awserr.Error)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ec2err.Code() != "InvalidNetworkAclEntry.NotFound" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccAWSNetworkAclRuleBasicConfig = `
|
||||||
|
provider "aws" {
|
||||||
|
region = "us-east-1"
|
||||||
|
}
|
||||||
|
resource "aws_vpc" "foo" {
|
||||||
|
cidr_block = "10.3.0.0/16"
|
||||||
|
}
|
||||||
|
resource "aws_network_acl" "bar" {
|
||||||
|
vpc_id = "${aws_vpc.foo.id}"
|
||||||
|
}
|
||||||
|
resource "aws_network_acl_rule" "bar" {
|
||||||
|
network_acl_id = "${aws_network_acl.bar.id}"
|
||||||
|
rule_number = 200
|
||||||
|
egress = false
|
||||||
|
protocol = "tcp"
|
||||||
|
rule_action = "allow"
|
||||||
|
cidr_block = "0.0.0.0/0"
|
||||||
|
from_port = 22
|
||||||
|
to_port = 22
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_network_acl_rule"
|
||||||
|
sidebar_current: "docs-aws-resource-network-acl-rule"
|
||||||
|
description: |-
|
||||||
|
Provides an network ACL Rule resource.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_network\_acl\_rule
|
||||||
|
|
||||||
|
Creates an entry (a rule) in a network ACL with the specified rule number.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_network_acl" "bar" {
|
||||||
|
vpc_id = "${aws_vpc.foo.id}"
|
||||||
|
}
|
||||||
|
resource "aws_network_acl_rule" "bar" {
|
||||||
|
network_acl_id = "${aws_network_acl.bar.id}"
|
||||||
|
rule_number = 200
|
||||||
|
egress = false
|
||||||
|
protocol = "tcp"
|
||||||
|
rule_action = "allow"
|
||||||
|
cidr_block = "0.0.0.0/0"
|
||||||
|
from_port = 22
|
||||||
|
to_port = 22
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `network_acl_id` - (Required) The ID of the network ACL.
|
||||||
|
* `rule_number` - (Required) The rule number for the entry (for example, 100). ACL entries are processed in ascending order by rule number.
|
||||||
|
* `egress` - (Optional, bool) Indicates whether this is an egress rule (rule is applied to traffic leaving the subnet). Default `false`.
|
||||||
|
* `protocol` - (Required) The protocol. A value of -1 means all protocols.
|
||||||
|
* `rule_action` - (Required) Indicates whether to allow or deny the traffic that matches the rule. Accepted values: `allow` | `deny`
|
||||||
|
* `cidr_block` - (Required) The network range to allow or deny, in CIDR notation (for example 172.16.0.0/24 ).
|
||||||
|
* `from_port` - (Optional) The from port to match.
|
||||||
|
* `to_port` - (Optional) The to port to match.
|
||||||
|
* `icmp_type` - (Optional) ICMP protocol: The ICMP type. Required if specifying ICMP for the protocol. e.g. -1
|
||||||
|
* `icmp_code` - (Optional) ICMP protocol: The ICMP code. Required if specifying ICMP for the protocol. e.g. -1
|
||||||
|
|
||||||
|
~> Note: For more information on ICMP types and codes, see here: http://www.nthelp.com/icmp.html
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ID of the network ACL Rule
|
||||||
|
|
|
@ -538,6 +538,10 @@
|
||||||
<a href="/docs/providers/aws/r/network_acl.html">aws_network_acl</a>
|
<a href="/docs/providers/aws/r/network_acl.html">aws_network_acl</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-network-acl-rule") %>>
|
||||||
|
<a href="/docs/providers/aws/r/network_acl_rule.html">aws_network_acl_rule</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-network-interface") %>>
|
<li<%= sidebar_current("docs-aws-resource-network-interface") %>>
|
||||||
<a href="/docs/providers/aws/r/network_interface.html">aws_network_interface</a>
|
<a href="/docs/providers/aws/r/network_interface.html">aws_network_interface</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue