Skip to content

Commit

Permalink
provider/aws: Add support for IPv6 to aws_security_group_rule (#12645)
Browse files Browse the repository at this point in the history
```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSSecurityGroupRule_'         ✹ ✭
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/03/13 15:40:39 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSSecurityGroupRule_ -timeout 120m
=== RUN   TestAccAWSSecurityGroupRule_Ingress_VPC
--- PASS: TestAccAWSSecurityGroupRule_Ingress_VPC (53.36s)
=== RUN   TestAccAWSSecurityGroupRule_Ingress_Protocol
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Protocol (85.22s)
=== RUN   TestAccAWSSecurityGroupRule_Ingress_Ipv6
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Ipv6 (87.55s)
=== RUN   TestAccAWSSecurityGroupRule_Ingress_Classic
--- PASS: TestAccAWSSecurityGroupRule_Ingress_Classic (50.58s)
=== RUN   TestAccAWSSecurityGroupRule_MultiIngress
--- PASS: TestAccAWSSecurityGroupRule_MultiIngress (47.98s)
=== RUN   TestAccAWSSecurityGroupRule_Egress
--- PASS: TestAccAWSSecurityGroupRule_Egress (50.48s)
=== RUN   TestAccAWSSecurityGroupRule_SelfReference
--- PASS: TestAccAWSSecurityGroupRule_SelfReference (82.45s)
=== RUN   TestAccAWSSecurityGroupRule_ExpectInvalidTypeError
--- PASS: TestAccAWSSecurityGroupRule_ExpectInvalidTypeError (0.01s)
=== RUN   TestAccAWSSecurityGroupRule_PartialMatching_basic
--- PASS: TestAccAWSSecurityGroupRule_PartialMatching_basic (95.55s)
=== RUN   TestAccAWSSecurityGroupRule_PartialMatching_Source
--- PASS: TestAccAWSSecurityGroupRule_PartialMatching_Source (95.65s)
=== RUN   TestAccAWSSecurityGroupRule_Issue5310
--- PASS: TestAccAWSSecurityGroupRule_Issue5310 (45.91s)
=== RUN   TestAccAWSSecurityGroupRule_Race
--- PASS: TestAccAWSSecurityGroupRule_Race (697.79s)
=== RUN   TestAccAWSSecurityGroupRule_SelfSource
--- PASS: TestAccAWSSecurityGroupRule_SelfSource (96.19s)
=== RUN   TestAccAWSSecurityGroupRule_PrefixListEgress
--- PASS: TestAccAWSSecurityGroupRule_PrefixListEgress (97.51s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	1586.248s
```
  • Loading branch information
stack72 authored Mar 14, 2017
1 parent 9fe61d0 commit d87cc07
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 10 deletions.
57 changes: 54 additions & 3 deletions builtin/providers/aws/resource_aws_security_group_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ func resourceAwsSecurityGroupRule() *schema.Resource {
Elem: &schema.Schema{Type: schema.TypeString},
},

"ipv6_cidr_blocks": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"prefix_list_ids": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -400,6 +407,19 @@ func findRuleMatch(p *ec2.IpPermission, rules []*ec2.IpPermission, isVPC bool) *
continue
}

remaining = len(p.Ipv6Ranges)
for _, ipv6 := range p.Ipv6Ranges {
for _, ipv6ip := range r.Ipv6Ranges {
if *ipv6.CidrIpv6 == *ipv6ip.CidrIpv6 {
remaining--
}
}
}

if remaining > 0 {
continue
}

remaining = len(p.PrefixListIds)
for _, pl := range p.PrefixListIds {
for _, rpl := range r.PrefixListIds {
Expand Down Expand Up @@ -463,6 +483,18 @@ func ipPermissionIDHash(sg_id, ruleType string, ip *ec2.IpPermission) string {
}
}

if len(ip.Ipv6Ranges) > 0 {
s := make([]string, len(ip.Ipv6Ranges))
for i, r := range ip.Ipv6Ranges {
s[i] = *r.CidrIpv6
}
sort.Strings(s)

for _, v := range s {
buf.WriteString(fmt.Sprintf("%s-", v))
}
}

if len(ip.PrefixListIds) > 0 {
s := make([]string, len(ip.PrefixListIds))
for i, pl := range ip.PrefixListIds {
Expand Down Expand Up @@ -555,6 +587,18 @@ func expandIPPerm(d *schema.ResourceData, sg *ec2.SecurityGroup) (*ec2.IpPermiss
}
}

if raw, ok := d.GetOk("ipv6_cidr_blocks"); ok {
list := raw.([]interface{})
perm.Ipv6Ranges = make([]*ec2.Ipv6Range, len(list))
for i, v := range list {
cidrIP, ok := v.(string)
if !ok {
return nil, fmt.Errorf("empty element found in ipv6_cidr_blocks - consider using the compact function")
}
perm.Ipv6Ranges[i] = &ec2.Ipv6Range{CidrIpv6: aws.String(cidrIP)}
}
}

if raw, ok := d.GetOk("prefix_list_ids"); ok {
list := raw.([]interface{})
perm.PrefixListIds = make([]*ec2.PrefixListId, len(list))
Expand Down Expand Up @@ -584,6 +628,12 @@ func setFromIPPerm(d *schema.ResourceData, sg *ec2.SecurityGroup, rule *ec2.IpPe

d.Set("cidr_blocks", cb)

var ipv6 []string
for _, ip := range rule.Ipv6Ranges {
ipv6 = append(ipv6, *ip.CidrIpv6)
}
d.Set("ipv6_cidr_blocks", ipv6)

var pl []string
for _, p := range rule.PrefixListIds {
pl = append(pl, *p.PrefixListId)
Expand All @@ -603,15 +653,16 @@ func setFromIPPerm(d *schema.ResourceData, sg *ec2.SecurityGroup, rule *ec2.IpPe
return nil
}

// Validates that either 'cidr_blocks', 'self', or 'source_security_group_id' is set
// Validates that either 'cidr_blocks', 'ipv6_cidr_blocks', 'self', or 'source_security_group_id' is set
func validateAwsSecurityGroupRule(d *schema.ResourceData) error {
_, blocksOk := d.GetOk("cidr_blocks")
_, ipv6Ok := d.GetOk("ipv6_cidr_blocks")
_, sourceOk := d.GetOk("source_security_group_id")
_, selfOk := d.GetOk("self")
_, prefixOk := d.GetOk("prefix_list_ids")
if !blocksOk && !sourceOk && !selfOk && !prefixOk {
if !blocksOk && !sourceOk && !selfOk && !prefixOk && !ipv6Ok {
return fmt.Errorf(
"One of ['cidr_blocks', 'self', 'source_security_group_id', 'prefix_list_ids'] must be set to create an AWS Security Group Rule")
"One of ['cidr_blocks', 'ipv6_cidr_blocks', 'self', 'source_security_group_id', 'prefix_list_ids'] must be set to create an AWS Security Group Rule")
}
return nil
}
82 changes: 75 additions & 7 deletions builtin/providers/aws/resource_aws_security_group_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ func TestIpPermissionIDHash(t *testing.T) {
FromPort: aws.Int64(int64(80)),
ToPort: aws.Int64(int64(8000)),
UserIdGroupPairs: []*ec2.UserIdGroupPair{
&ec2.UserIdGroupPair{
{
UserId: aws.String("987654321"),
GroupId: aws.String("sg-12345678"),
},
&ec2.UserIdGroupPair{
{
UserId: aws.String("123456789"),
GroupId: aws.String("sg-987654321"),
},
&ec2.UserIdGroupPair{
{
UserId: aws.String("123456789"),
GroupId: aws.String("sg-12345678"),
},
Expand All @@ -72,15 +72,15 @@ func TestIpPermissionIDHash(t *testing.T) {
FromPort: aws.Int64(int64(80)),
ToPort: aws.Int64(int64(8000)),
UserIdGroupPairs: []*ec2.UserIdGroupPair{
&ec2.UserIdGroupPair{
{
UserId: aws.String("987654321"),
GroupName: aws.String("my-security-group"),
},
&ec2.UserIdGroupPair{
{
UserId: aws.String("123456789"),
GroupName: aws.String("my-security-group"),
},
&ec2.UserIdGroupPair{
{
UserId: aws.String("123456789"),
GroupName: aws.String("my-other-security-group"),
},
Expand Down Expand Up @@ -183,6 +183,46 @@ func TestAccAWSSecurityGroupRule_Ingress_Protocol(t *testing.T) {
})
}

func TestAccAWSSecurityGroupRule_Ingress_Ipv6(t *testing.T) {
var group ec2.SecurityGroup

testRuleCount := func(*terraform.State) error {
if len(group.IpPermissions) != 1 {
return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
1, len(group.IpPermissions))
}

rule := group.IpPermissions[0]
if *rule.FromPort != int64(80) {
return fmt.Errorf("Wrong Security Group port setting, expected %d, got %d",
80, int(*rule.FromPort))
}

ipv6Address := rule.Ipv6Ranges[0]
if *ipv6Address.CidrIpv6 != "::/0" {
return fmt.Errorf("Wrong Security Group IPv6 address, expected %s, got %s",
"::/0", *ipv6Address.CidrIpv6)
}

return nil
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSSecurityGroupRuleIngress_ipv6Config,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
testRuleCount,
),
},
},
})
}

func TestAccAWSSecurityGroupRule_Ingress_Classic(t *testing.T) {
var group ec2.SecurityGroup
rInt := acctest.RandInt()
Expand Down Expand Up @@ -376,7 +416,7 @@ func TestAccAWSSecurityGroupRule_PartialMatching_Source(t *testing.T) {
ToPort: aws.Int64(80),
IpProtocol: aws.String("tcp"),
UserIdGroupPairs: []*ec2.UserIdGroupPair{
&ec2.UserIdGroupPair{GroupId: nat.GroupId},
{GroupId: nat.GroupId},
},
}

Expand Down Expand Up @@ -696,6 +736,34 @@ func testAccAWSSecurityGroupRuleIngressConfig(rInt int) string {
}`, rInt)
}

const testAccAWSSecurityGroupRuleIngress_ipv6Config = `
resource "aws_vpc" "tftest" {
cidr_block = "10.0.0.0/16"
tags {
Name = "tf-testing"
}
}
resource "aws_security_group" "web" {
vpc_id = "${aws_vpc.tftest.id}"
tags {
Name = "tf-acc-test"
}
}
resource "aws_security_group_rule" "ingress_1" {
type = "ingress"
protocol = "6"
from_port = 80
to_port = 8000
ipv6_cidr_blocks = ["::/0"]
security_group_id = "${aws_security_group.web.id}"
}
`

const testAccAWSSecurityGroupRuleIngress_protocolConfig = `
resource "aws_vpc" "tftest" {
cidr_block = "10.0.0.0/16"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The following arguments are supported:
* `type` - (Required) The type of rule being created. Valid options are `ingress` (inbound)
or `egress` (outbound).
* `cidr_blocks` - (Optional) List of CIDR blocks. Cannot be specified with `source_security_group_id`.
* `ipv6_cidr_blocks` - (Optional) List of IPv6 CIDR blocks.
* `prefix_list_ids` - (Optional) List of prefix list IDs (for allowing access to VPC endpoints).
Only valid with `egress`.
* `from_port` - (Required) The start port (or ICMP type number if protocol is "icmp").
Expand Down

0 comments on commit d87cc07

Please sign in to comment.