github.com/peterbale/terraform@v0.9.0-beta2.0.20170315142748-5723acd55547/builtin/providers/aws/resource_aws_security_group_rule_test.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"regexp"
     8  	"testing"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/awserr"
    12  	"github.com/aws/aws-sdk-go/service/ec2"
    13  	"github.com/hashicorp/terraform/helper/acctest"
    14  	"github.com/hashicorp/terraform/helper/resource"
    15  	"github.com/hashicorp/terraform/terraform"
    16  )
    17  
    18  func TestIpPermissionIDHash(t *testing.T) {
    19  	simple := &ec2.IpPermission{
    20  		IpProtocol: aws.String("tcp"),
    21  		FromPort:   aws.Int64(int64(80)),
    22  		ToPort:     aws.Int64(int64(8000)),
    23  		IpRanges: []*ec2.IpRange{
    24  			{
    25  				CidrIp: aws.String("10.0.0.0/8"),
    26  			},
    27  		},
    28  	}
    29  
    30  	egress := &ec2.IpPermission{
    31  		IpProtocol: aws.String("tcp"),
    32  		FromPort:   aws.Int64(int64(80)),
    33  		ToPort:     aws.Int64(int64(8000)),
    34  		IpRanges: []*ec2.IpRange{
    35  			{
    36  				CidrIp: aws.String("10.0.0.0/8"),
    37  			},
    38  		},
    39  	}
    40  
    41  	egress_all := &ec2.IpPermission{
    42  		IpProtocol: aws.String("-1"),
    43  		IpRanges: []*ec2.IpRange{
    44  			{
    45  				CidrIp: aws.String("10.0.0.0/8"),
    46  			},
    47  		},
    48  	}
    49  
    50  	vpc_security_group_source := &ec2.IpPermission{
    51  		IpProtocol: aws.String("tcp"),
    52  		FromPort:   aws.Int64(int64(80)),
    53  		ToPort:     aws.Int64(int64(8000)),
    54  		UserIdGroupPairs: []*ec2.UserIdGroupPair{
    55  			{
    56  				UserId:  aws.String("987654321"),
    57  				GroupId: aws.String("sg-12345678"),
    58  			},
    59  			{
    60  				UserId:  aws.String("123456789"),
    61  				GroupId: aws.String("sg-987654321"),
    62  			},
    63  			{
    64  				UserId:  aws.String("123456789"),
    65  				GroupId: aws.String("sg-12345678"),
    66  			},
    67  		},
    68  	}
    69  
    70  	security_group_source := &ec2.IpPermission{
    71  		IpProtocol: aws.String("tcp"),
    72  		FromPort:   aws.Int64(int64(80)),
    73  		ToPort:     aws.Int64(int64(8000)),
    74  		UserIdGroupPairs: []*ec2.UserIdGroupPair{
    75  			{
    76  				UserId:    aws.String("987654321"),
    77  				GroupName: aws.String("my-security-group"),
    78  			},
    79  			{
    80  				UserId:    aws.String("123456789"),
    81  				GroupName: aws.String("my-security-group"),
    82  			},
    83  			{
    84  				UserId:    aws.String("123456789"),
    85  				GroupName: aws.String("my-other-security-group"),
    86  			},
    87  		},
    88  	}
    89  
    90  	// hardcoded hashes, to detect future change
    91  	cases := []struct {
    92  		Input  *ec2.IpPermission
    93  		Type   string
    94  		Output string
    95  	}{
    96  		{simple, "ingress", "sgrule-3403497314"},
    97  		{egress, "egress", "sgrule-1173186295"},
    98  		{egress_all, "egress", "sgrule-766323498"},
    99  		{vpc_security_group_source, "egress", "sgrule-351225364"},
   100  		{security_group_source, "egress", "sgrule-2198807188"},
   101  	}
   102  
   103  	for _, tc := range cases {
   104  		actual := ipPermissionIDHash("sg-12345", tc.Type, tc.Input)
   105  		if actual != tc.Output {
   106  			t.Errorf("input: %s - %s\noutput: %s", tc.Type, tc.Input, actual)
   107  		}
   108  	}
   109  }
   110  
   111  func TestAccAWSSecurityGroupRule_Ingress_VPC(t *testing.T) {
   112  	var group ec2.SecurityGroup
   113  	rInt := acctest.RandInt()
   114  
   115  	testRuleCount := func(*terraform.State) error {
   116  		if len(group.IpPermissions) != 1 {
   117  			return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
   118  				1, len(group.IpPermissions))
   119  		}
   120  
   121  		rule := group.IpPermissions[0]
   122  		if *rule.FromPort != int64(80) {
   123  			return fmt.Errorf("Wrong Security Group port setting, expected %d, got %d",
   124  				80, int(*rule.FromPort))
   125  		}
   126  
   127  		return nil
   128  	}
   129  
   130  	resource.Test(t, resource.TestCase{
   131  		PreCheck:     func() { testAccPreCheck(t) },
   132  		Providers:    testAccProviders,
   133  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   134  		Steps: []resource.TestStep{
   135  			{
   136  				Config: testAccAWSSecurityGroupRuleIngressConfig(rInt),
   137  				Check: resource.ComposeTestCheckFunc(
   138  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   139  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.ingress_1", &group, nil, "ingress"),
   140  					resource.TestCheckResourceAttr(
   141  						"aws_security_group_rule.ingress_1", "from_port", "80"),
   142  					testRuleCount,
   143  				),
   144  			},
   145  		},
   146  	})
   147  }
   148  
   149  func TestAccAWSSecurityGroupRule_Ingress_Protocol(t *testing.T) {
   150  	var group ec2.SecurityGroup
   151  
   152  	testRuleCount := func(*terraform.State) error {
   153  		if len(group.IpPermissions) != 1 {
   154  			return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
   155  				1, len(group.IpPermissions))
   156  		}
   157  
   158  		rule := group.IpPermissions[0]
   159  		if *rule.FromPort != int64(80) {
   160  			return fmt.Errorf("Wrong Security Group port setting, expected %d, got %d",
   161  				80, int(*rule.FromPort))
   162  		}
   163  
   164  		return nil
   165  	}
   166  
   167  	resource.Test(t, resource.TestCase{
   168  		PreCheck:     func() { testAccPreCheck(t) },
   169  		Providers:    testAccProviders,
   170  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   171  		Steps: []resource.TestStep{
   172  			{
   173  				Config: testAccAWSSecurityGroupRuleIngress_protocolConfig,
   174  				Check: resource.ComposeTestCheckFunc(
   175  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   176  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.ingress_1", &group, nil, "ingress"),
   177  					resource.TestCheckResourceAttr(
   178  						"aws_security_group_rule.ingress_1", "from_port", "80"),
   179  					testRuleCount,
   180  				),
   181  			},
   182  		},
   183  	})
   184  }
   185  
   186  func TestAccAWSSecurityGroupRule_Ingress_Ipv6(t *testing.T) {
   187  	var group ec2.SecurityGroup
   188  
   189  	testRuleCount := func(*terraform.State) error {
   190  		if len(group.IpPermissions) != 1 {
   191  			return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
   192  				1, len(group.IpPermissions))
   193  		}
   194  
   195  		rule := group.IpPermissions[0]
   196  		if *rule.FromPort != int64(80) {
   197  			return fmt.Errorf("Wrong Security Group port setting, expected %d, got %d",
   198  				80, int(*rule.FromPort))
   199  		}
   200  
   201  		ipv6Address := rule.Ipv6Ranges[0]
   202  		if *ipv6Address.CidrIpv6 != "::/0" {
   203  			return fmt.Errorf("Wrong Security Group IPv6 address, expected %s, got %s",
   204  				"::/0", *ipv6Address.CidrIpv6)
   205  		}
   206  
   207  		return nil
   208  	}
   209  
   210  	resource.Test(t, resource.TestCase{
   211  		PreCheck:     func() { testAccPreCheck(t) },
   212  		Providers:    testAccProviders,
   213  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   214  		Steps: []resource.TestStep{
   215  			{
   216  				Config: testAccAWSSecurityGroupRuleIngress_ipv6Config,
   217  				Check: resource.ComposeTestCheckFunc(
   218  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   219  					testRuleCount,
   220  				),
   221  			},
   222  		},
   223  	})
   224  }
   225  
   226  func TestAccAWSSecurityGroupRule_Ingress_Classic(t *testing.T) {
   227  	var group ec2.SecurityGroup
   228  	rInt := acctest.RandInt()
   229  
   230  	testRuleCount := func(*terraform.State) error {
   231  		if len(group.IpPermissions) != 1 {
   232  			return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
   233  				1, len(group.IpPermissions))
   234  		}
   235  
   236  		rule := group.IpPermissions[0]
   237  		if *rule.FromPort != int64(80) {
   238  			return fmt.Errorf("Wrong Security Group port setting, expected %d, got %d",
   239  				80, int(*rule.FromPort))
   240  		}
   241  
   242  		return nil
   243  	}
   244  
   245  	resource.Test(t, resource.TestCase{
   246  		PreCheck:     func() { testAccPreCheck(t) },
   247  		Providers:    testAccProviders,
   248  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   249  		Steps: []resource.TestStep{
   250  			{
   251  				Config: testAccAWSSecurityGroupRuleIngressClassicConfig(rInt),
   252  				Check: resource.ComposeTestCheckFunc(
   253  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   254  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.ingress_1", &group, nil, "ingress"),
   255  					resource.TestCheckResourceAttr(
   256  						"aws_security_group_rule.ingress_1", "from_port", "80"),
   257  					testRuleCount,
   258  				),
   259  			},
   260  		},
   261  	})
   262  }
   263  
   264  func TestAccAWSSecurityGroupRule_MultiIngress(t *testing.T) {
   265  	var group ec2.SecurityGroup
   266  
   267  	testMultiRuleCount := func(*terraform.State) error {
   268  		if len(group.IpPermissions) != 2 {
   269  			return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
   270  				2, len(group.IpPermissions))
   271  		}
   272  
   273  		var rule *ec2.IpPermission
   274  		for _, r := range group.IpPermissions {
   275  			if *r.FromPort == int64(80) {
   276  				rule = r
   277  			}
   278  		}
   279  
   280  		if *rule.ToPort != int64(8000) {
   281  			return fmt.Errorf("Wrong Security Group port 2 setting, expected %d, got %d",
   282  				8000, int(*rule.ToPort))
   283  		}
   284  
   285  		return nil
   286  	}
   287  
   288  	resource.Test(t, resource.TestCase{
   289  		PreCheck:     func() { testAccPreCheck(t) },
   290  		Providers:    testAccProviders,
   291  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   292  		Steps: []resource.TestStep{
   293  			{
   294  				Config: testAccAWSSecurityGroupRuleConfigMultiIngress,
   295  				Check: resource.ComposeTestCheckFunc(
   296  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   297  					testMultiRuleCount,
   298  				),
   299  			},
   300  		},
   301  	})
   302  }
   303  
   304  func TestAccAWSSecurityGroupRule_Egress(t *testing.T) {
   305  	var group ec2.SecurityGroup
   306  	rInt := acctest.RandInt()
   307  
   308  	resource.Test(t, resource.TestCase{
   309  		PreCheck:     func() { testAccPreCheck(t) },
   310  		Providers:    testAccProviders,
   311  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   312  		Steps: []resource.TestStep{
   313  			{
   314  				Config: testAccAWSSecurityGroupRuleEgressConfig(rInt),
   315  				Check: resource.ComposeTestCheckFunc(
   316  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   317  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.egress_1", &group, nil, "egress"),
   318  				),
   319  			},
   320  		},
   321  	})
   322  }
   323  
   324  func TestAccAWSSecurityGroupRule_SelfReference(t *testing.T) {
   325  	var group ec2.SecurityGroup
   326  
   327  	resource.Test(t, resource.TestCase{
   328  		PreCheck:     func() { testAccPreCheck(t) },
   329  		Providers:    testAccProviders,
   330  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   331  		Steps: []resource.TestStep{
   332  			{
   333  				Config: testAccAWSSecurityGroupRuleConfigSelfReference,
   334  				Check: resource.ComposeTestCheckFunc(
   335  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   336  				),
   337  			},
   338  		},
   339  	})
   340  }
   341  
   342  func TestAccAWSSecurityGroupRule_ExpectInvalidTypeError(t *testing.T) {
   343  	rInt := acctest.RandInt()
   344  	resource.Test(t, resource.TestCase{
   345  		PreCheck:     func() { testAccPreCheck(t) },
   346  		Providers:    testAccProviders,
   347  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   348  		Steps: []resource.TestStep{
   349  			{
   350  				Config:      testAccAWSSecurityGroupRuleExpectInvalidType(rInt),
   351  				ExpectError: regexp.MustCompile(`\\"type\\" contains an invalid Security Group Rule type \\"foobar\\"`),
   352  			},
   353  		},
   354  	})
   355  }
   356  
   357  // testing partial match implementation
   358  func TestAccAWSSecurityGroupRule_PartialMatching_basic(t *testing.T) {
   359  	var group ec2.SecurityGroup
   360  	rInt := acctest.RandInt()
   361  
   362  	p := ec2.IpPermission{
   363  		FromPort:   aws.Int64(80),
   364  		ToPort:     aws.Int64(80),
   365  		IpProtocol: aws.String("tcp"),
   366  		IpRanges: []*ec2.IpRange{
   367  			{CidrIp: aws.String("10.0.2.0/24")},
   368  			{CidrIp: aws.String("10.0.3.0/24")},
   369  			{CidrIp: aws.String("10.0.4.0/24")},
   370  		},
   371  	}
   372  
   373  	o := ec2.IpPermission{
   374  		FromPort:   aws.Int64(80),
   375  		ToPort:     aws.Int64(80),
   376  		IpProtocol: aws.String("tcp"),
   377  		IpRanges: []*ec2.IpRange{
   378  			{CidrIp: aws.String("10.0.5.0/24")},
   379  		},
   380  	}
   381  
   382  	resource.Test(t, resource.TestCase{
   383  		PreCheck:     func() { testAccPreCheck(t) },
   384  		Providers:    testAccProviders,
   385  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   386  		Steps: []resource.TestStep{
   387  			{
   388  				Config: testAccAWSSecurityGroupRulePartialMatching(rInt),
   389  				Check: resource.ComposeTestCheckFunc(
   390  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   391  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.ingress", &group, &p, "ingress"),
   392  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.other", &group, &o, "ingress"),
   393  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.nat_ingress", &group, &o, "ingress"),
   394  				),
   395  			},
   396  		},
   397  	})
   398  }
   399  
   400  func TestAccAWSSecurityGroupRule_PartialMatching_Source(t *testing.T) {
   401  	var group ec2.SecurityGroup
   402  	var nat ec2.SecurityGroup
   403  	var p ec2.IpPermission
   404  	rInt := acctest.RandInt()
   405  
   406  	// This function creates the expected IPPermission with the group id from an
   407  	// external security group, needed because Security Group IDs are generated on
   408  	// AWS side and can't be known ahead of time.
   409  	setupSG := func(*terraform.State) error {
   410  		if nat.GroupId == nil {
   411  			return fmt.Errorf("Error: nat group has nil GroupID")
   412  		}
   413  
   414  		p = ec2.IpPermission{
   415  			FromPort:   aws.Int64(80),
   416  			ToPort:     aws.Int64(80),
   417  			IpProtocol: aws.String("tcp"),
   418  			UserIdGroupPairs: []*ec2.UserIdGroupPair{
   419  				{GroupId: nat.GroupId},
   420  			},
   421  		}
   422  
   423  		return nil
   424  	}
   425  
   426  	resource.Test(t, resource.TestCase{
   427  		PreCheck:     func() { testAccPreCheck(t) },
   428  		Providers:    testAccProviders,
   429  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   430  		Steps: []resource.TestStep{
   431  			{
   432  				Config: testAccAWSSecurityGroupRulePartialMatching_Source(rInt),
   433  				Check: resource.ComposeTestCheckFunc(
   434  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   435  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.nat", &nat),
   436  					setupSG,
   437  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.source_ingress", &group, &p, "ingress"),
   438  				),
   439  			},
   440  		},
   441  	})
   442  }
   443  
   444  func TestAccAWSSecurityGroupRule_Issue5310(t *testing.T) {
   445  	var group ec2.SecurityGroup
   446  
   447  	resource.Test(t, resource.TestCase{
   448  		PreCheck:     func() { testAccPreCheck(t) },
   449  		Providers:    testAccProviders,
   450  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   451  		Steps: []resource.TestStep{
   452  			{
   453  				Config: testAccAWSSecurityGroupRuleIssue5310,
   454  				Check: resource.ComposeTestCheckFunc(
   455  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.issue_5310", &group),
   456  				),
   457  			},
   458  		},
   459  	})
   460  }
   461  
   462  func TestAccAWSSecurityGroupRule_Race(t *testing.T) {
   463  	var group ec2.SecurityGroup
   464  
   465  	resource.Test(t, resource.TestCase{
   466  		PreCheck:     func() { testAccPreCheck(t) },
   467  		Providers:    testAccProviders,
   468  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   469  		Steps: []resource.TestStep{
   470  			{
   471  				Config: testAccAWSSecurityGroupRuleRace,
   472  				Check: resource.ComposeTestCheckFunc(
   473  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.race", &group),
   474  				),
   475  			},
   476  		},
   477  	})
   478  }
   479  
   480  func TestAccAWSSecurityGroupRule_SelfSource(t *testing.T) {
   481  	var group ec2.SecurityGroup
   482  	rInt := acctest.RandInt()
   483  
   484  	resource.Test(t, resource.TestCase{
   485  		PreCheck:     func() { testAccPreCheck(t) },
   486  		Providers:    testAccProviders,
   487  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   488  		Steps: []resource.TestStep{
   489  			{
   490  				Config: testAccAWSSecurityGroupRuleSelfInSource(rInt),
   491  				Check: resource.ComposeTestCheckFunc(
   492  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   493  				),
   494  			},
   495  		},
   496  	})
   497  }
   498  
   499  func TestAccAWSSecurityGroupRule_PrefixListEgress(t *testing.T) {
   500  	var group ec2.SecurityGroup
   501  	var endpoint ec2.VpcEndpoint
   502  	var p ec2.IpPermission
   503  
   504  	// This function creates the expected IPPermission with the prefix list ID from
   505  	// the VPC Endpoint created in the test
   506  	setupSG := func(*terraform.State) error {
   507  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   508  		prefixListInput := &ec2.DescribePrefixListsInput{
   509  			Filters: []*ec2.Filter{
   510  				{Name: aws.String("prefix-list-name"), Values: []*string{endpoint.ServiceName}},
   511  			},
   512  		}
   513  
   514  		log.Printf("[DEBUG] Reading VPC Endpoint prefix list: %s", prefixListInput)
   515  		prefixListsOutput, err := conn.DescribePrefixLists(prefixListInput)
   516  
   517  		if err != nil {
   518  			_, ok := err.(awserr.Error)
   519  			if !ok {
   520  				return fmt.Errorf("Error reading VPC Endpoint prefix list: %s", err.Error())
   521  			}
   522  		}
   523  
   524  		if len(prefixListsOutput.PrefixLists) != 1 {
   525  			return fmt.Errorf("There are multiple prefix lists associated with the service name '%s'. Unexpected", prefixListsOutput)
   526  		}
   527  
   528  		p = ec2.IpPermission{
   529  			IpProtocol: aws.String("-1"),
   530  			PrefixListIds: []*ec2.PrefixListId{
   531  				{PrefixListId: prefixListsOutput.PrefixLists[0].PrefixListId},
   532  			},
   533  		}
   534  
   535  		return nil
   536  	}
   537  
   538  	resource.Test(t, resource.TestCase{
   539  		PreCheck:     func() { testAccPreCheck(t) },
   540  		Providers:    testAccProviders,
   541  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   542  		Steps: []resource.TestStep{
   543  			{
   544  				Config: testAccAWSSecurityGroupRulePrefixListEgressConfig,
   545  				Check: resource.ComposeTestCheckFunc(
   546  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.egress", &group),
   547  					// lookup info on the VPC Endpoint created, to populate the expected
   548  					// IP Perm
   549  					testAccCheckVpcEndpointExists("aws_vpc_endpoint.s3-us-west-2", &endpoint),
   550  					setupSG,
   551  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.egress_1", &group, &p, "egress"),
   552  				),
   553  			},
   554  		},
   555  	})
   556  }
   557  
   558  func testAccCheckAWSSecurityGroupRuleDestroy(s *terraform.State) error {
   559  	conn := testAccProvider.Meta().(*AWSClient).ec2conn
   560  
   561  	for _, rs := range s.RootModule().Resources {
   562  		if rs.Type != "aws_security_group" {
   563  			continue
   564  		}
   565  
   566  		// Retrieve our group
   567  		req := &ec2.DescribeSecurityGroupsInput{
   568  			GroupIds: []*string{aws.String(rs.Primary.ID)},
   569  		}
   570  		resp, err := conn.DescribeSecurityGroups(req)
   571  		if err == nil {
   572  			if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID {
   573  				return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID)
   574  			}
   575  
   576  			return nil
   577  		}
   578  
   579  		ec2err, ok := err.(awserr.Error)
   580  		if !ok {
   581  			return err
   582  		}
   583  		// Confirm error code is what we want
   584  		if ec2err.Code() != "InvalidGroup.NotFound" {
   585  			return err
   586  		}
   587  	}
   588  
   589  	return nil
   590  }
   591  
   592  func testAccCheckAWSSecurityGroupRuleExists(n string, group *ec2.SecurityGroup) resource.TestCheckFunc {
   593  	return func(s *terraform.State) error {
   594  		rs, ok := s.RootModule().Resources[n]
   595  		if !ok {
   596  			return fmt.Errorf("Not found: %s", n)
   597  		}
   598  
   599  		if rs.Primary.ID == "" {
   600  			return fmt.Errorf("No Security Group is set")
   601  		}
   602  
   603  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   604  		req := &ec2.DescribeSecurityGroupsInput{
   605  			GroupIds: []*string{aws.String(rs.Primary.ID)},
   606  		}
   607  		resp, err := conn.DescribeSecurityGroups(req)
   608  		if err != nil {
   609  			return err
   610  		}
   611  
   612  		if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID {
   613  			*group = *resp.SecurityGroups[0]
   614  			return nil
   615  		}
   616  
   617  		return fmt.Errorf("Security Group not found")
   618  	}
   619  }
   620  
   621  func testAccCheckAWSSecurityGroupRuleAttributes(n string, group *ec2.SecurityGroup, p *ec2.IpPermission, ruleType string) resource.TestCheckFunc {
   622  	return func(s *terraform.State) error {
   623  		rs, ok := s.RootModule().Resources[n]
   624  		if !ok {
   625  			return fmt.Errorf("Security Group Rule Not found: %s", n)
   626  		}
   627  
   628  		if rs.Primary.ID == "" {
   629  			return fmt.Errorf("No Security Group Rule is set")
   630  		}
   631  
   632  		if p == nil {
   633  			p = &ec2.IpPermission{
   634  				FromPort:   aws.Int64(80),
   635  				ToPort:     aws.Int64(8000),
   636  				IpProtocol: aws.String("tcp"),
   637  				IpRanges:   []*ec2.IpRange{{CidrIp: aws.String("10.0.0.0/8")}},
   638  			}
   639  		}
   640  
   641  		var matchingRule *ec2.IpPermission
   642  		var rules []*ec2.IpPermission
   643  		if ruleType == "ingress" {
   644  			rules = group.IpPermissions
   645  		} else {
   646  			rules = group.IpPermissionsEgress
   647  		}
   648  
   649  		if len(rules) == 0 {
   650  			return fmt.Errorf("No IPPerms")
   651  		}
   652  
   653  		for _, r := range rules {
   654  			if r.ToPort != nil && *p.ToPort != *r.ToPort {
   655  				continue
   656  			}
   657  
   658  			if r.FromPort != nil && *p.FromPort != *r.FromPort {
   659  				continue
   660  			}
   661  
   662  			if r.IpProtocol != nil && *p.IpProtocol != *r.IpProtocol {
   663  				continue
   664  			}
   665  
   666  			remaining := len(p.IpRanges)
   667  			for _, ip := range p.IpRanges {
   668  				for _, rip := range r.IpRanges {
   669  					if *ip.CidrIp == *rip.CidrIp {
   670  						remaining--
   671  					}
   672  				}
   673  			}
   674  
   675  			if remaining > 0 {
   676  				continue
   677  			}
   678  
   679  			remaining = len(p.UserIdGroupPairs)
   680  			for _, ip := range p.UserIdGroupPairs {
   681  				for _, rip := range r.UserIdGroupPairs {
   682  					if *ip.GroupId == *rip.GroupId {
   683  						remaining--
   684  					}
   685  				}
   686  			}
   687  
   688  			if remaining > 0 {
   689  				continue
   690  			}
   691  
   692  			remaining = len(p.PrefixListIds)
   693  			for _, pip := range p.PrefixListIds {
   694  				for _, rpip := range r.PrefixListIds {
   695  					if *pip.PrefixListId == *rpip.PrefixListId {
   696  						remaining--
   697  					}
   698  				}
   699  			}
   700  
   701  			if remaining > 0 {
   702  				continue
   703  			}
   704  
   705  			matchingRule = r
   706  		}
   707  
   708  		if matchingRule != nil {
   709  			log.Printf("[DEBUG] Matching rule found : %s", matchingRule)
   710  			return nil
   711  		}
   712  
   713  		return fmt.Errorf("Error here\n\tlooking for %s, wasn't found in %s", p, rules)
   714  	}
   715  }
   716  
   717  func testAccAWSSecurityGroupRuleIngressConfig(rInt int) string {
   718  	return fmt.Sprintf(`
   719  	resource "aws_security_group" "web" {
   720  		name = "terraform_test_%d"
   721  		description = "Used in the terraform acceptance tests"
   722  
   723  					tags {
   724  									Name = "tf-acc-test"
   725  					}
   726  	}
   727  
   728  	resource "aws_security_group_rule" "ingress_1" {
   729  		type = "ingress"
   730  		protocol = "tcp"
   731  		from_port = 80
   732  		to_port = 8000
   733  		cidr_blocks = ["10.0.0.0/8"]
   734  
   735  		security_group_id = "${aws_security_group.web.id}"
   736  	}`, rInt)
   737  }
   738  
   739  const testAccAWSSecurityGroupRuleIngress_ipv6Config = `
   740  resource "aws_vpc" "tftest" {
   741    cidr_block = "10.0.0.0/16"
   742  
   743    tags {
   744      Name = "tf-testing"
   745    }
   746  }
   747  
   748  resource "aws_security_group" "web" {
   749    vpc_id = "${aws_vpc.tftest.id}"
   750  
   751    tags {
   752      Name = "tf-acc-test"
   753    }
   754  }
   755  
   756  resource "aws_security_group_rule" "ingress_1" {
   757    type        = "ingress"
   758    protocol    = "6"
   759    from_port   = 80
   760    to_port     = 8000
   761    ipv6_cidr_blocks = ["::/0"]
   762  
   763    security_group_id = "${aws_security_group.web.id}"
   764  }
   765  `
   766  
   767  const testAccAWSSecurityGroupRuleIngress_protocolConfig = `
   768  resource "aws_vpc" "tftest" {
   769    cidr_block = "10.0.0.0/16"
   770  
   771    tags {
   772      Name = "tf-testing"
   773    }
   774  }
   775  
   776  resource "aws_security_group" "web" {
   777    vpc_id = "${aws_vpc.tftest.id}"
   778  
   779    tags {
   780      Name = "tf-acc-test"
   781    }
   782  }
   783  
   784  resource "aws_security_group_rule" "ingress_1" {
   785    type        = "ingress"
   786    protocol    = "6"
   787    from_port   = 80
   788    to_port     = 8000
   789    cidr_blocks = ["10.0.0.0/8"]
   790  
   791    security_group_id = "${aws_security_group.web.id}"
   792  }
   793  
   794  `
   795  
   796  const testAccAWSSecurityGroupRuleIssue5310 = `
   797  provider "aws" {
   798          region = "us-east-1"
   799  }
   800  
   801  resource "aws_security_group" "issue_5310" {
   802      name = "terraform-test-issue_5310"
   803      description = "SG for test of issue 5310"
   804  }
   805  
   806  resource "aws_security_group_rule" "issue_5310" {
   807      type = "ingress"
   808      from_port = 0
   809      to_port = 65535
   810      protocol = "tcp"
   811      security_group_id = "${aws_security_group.issue_5310.id}"
   812      self = true
   813  }
   814  `
   815  
   816  func testAccAWSSecurityGroupRuleIngressClassicConfig(rInt int) string {
   817  	return fmt.Sprintf(`
   818  	provider "aws" {
   819  					region = "us-east-1"
   820  	}
   821  
   822  	resource "aws_security_group" "web" {
   823  		name = "terraform_test_%d"
   824  		description = "Used in the terraform acceptance tests"
   825  
   826  					tags {
   827  									Name = "tf-acc-test"
   828  					}
   829  	}
   830  
   831  	resource "aws_security_group_rule" "ingress_1" {
   832  		type = "ingress"
   833  		protocol = "tcp"
   834  		from_port = 80
   835  		to_port = 8000
   836  		cidr_blocks = ["10.0.0.0/8"]
   837  
   838  		security_group_id = "${aws_security_group.web.id}"
   839  	}`, rInt)
   840  }
   841  
   842  func testAccAWSSecurityGroupRuleEgressConfig(rInt int) string {
   843  	return fmt.Sprintf(`
   844  	resource "aws_security_group" "web" {
   845  		name = "terraform_test_%d"
   846  		description = "Used in the terraform acceptance tests"
   847  
   848  					tags {
   849  									Name = "tf-acc-test"
   850  					}
   851  	}
   852  
   853  	resource "aws_security_group_rule" "egress_1" {
   854  		type = "egress"
   855  		protocol = "tcp"
   856  		from_port = 80
   857  		to_port = 8000
   858  		cidr_blocks = ["10.0.0.0/8"]
   859  
   860  		security_group_id = "${aws_security_group.web.id}"
   861  	}`, rInt)
   862  }
   863  
   864  const testAccAWSSecurityGroupRuleConfigMultiIngress = `
   865  resource "aws_security_group" "web" {
   866    name = "terraform_acceptance_test_example_2"
   867    description = "Used in the terraform acceptance tests"
   868  }
   869  
   870  resource "aws_security_group" "worker" {
   871    name = "terraform_acceptance_test_example_worker"
   872    description = "Used in the terraform acceptance tests"
   873  }
   874  
   875  
   876  resource "aws_security_group_rule" "ingress_1" {
   877    type = "ingress"
   878    protocol = "tcp"
   879    from_port = 22
   880    to_port = 22
   881    cidr_blocks = ["10.0.0.0/8"]
   882  
   883    security_group_id = "${aws_security_group.web.id}"
   884  }
   885  
   886  resource "aws_security_group_rule" "ingress_2" {
   887    type = "ingress"
   888    protocol = "tcp"
   889    from_port = 80
   890    to_port = 8000
   891          self = true
   892  
   893    security_group_id = "${aws_security_group.web.id}"
   894  }
   895  `
   896  
   897  // check for GH-1985 regression
   898  const testAccAWSSecurityGroupRuleConfigSelfReference = `
   899  provider "aws" {
   900    region = "us-west-2"
   901  }
   902  
   903  resource "aws_vpc" "main" {
   904    cidr_block = "10.0.0.0/16"
   905    tags {
   906      Name = "sg-self-test"
   907    }
   908  }
   909  
   910  resource "aws_security_group" "web" {
   911    name = "main"
   912    vpc_id = "${aws_vpc.main.id}"
   913    tags {
   914      Name = "sg-self-test"
   915    }
   916  }
   917  
   918  resource "aws_security_group_rule" "self" {
   919    type = "ingress"
   920    protocol = "-1"
   921    from_port = 0
   922    to_port = 0
   923    self = true
   924    security_group_id = "${aws_security_group.web.id}"
   925  }
   926  `
   927  
   928  func testAccAWSSecurityGroupRulePartialMatching(rInt int) string {
   929  	return fmt.Sprintf(`
   930  	resource "aws_vpc" "default" {
   931  		cidr_block = "10.0.0.0/16"
   932  		tags {
   933  			Name = "tf-sg-rule-bug"
   934  		}
   935  	}
   936  
   937  	resource "aws_security_group" "web" {
   938  			name = "tf-other-%d"
   939  			vpc_id = "${aws_vpc.default.id}"
   940  			tags {
   941  					Name        = "tf-other-sg"
   942  			}
   943  	}
   944  
   945  	resource "aws_security_group" "nat" {
   946  			name = "tf-nat-%d"
   947  			vpc_id = "${aws_vpc.default.id}"
   948  			tags {
   949  					Name        = "tf-nat-sg"
   950  			}
   951  	}
   952  
   953  	resource "aws_security_group_rule" "ingress" {
   954  			type        = "ingress"
   955  			from_port   = 80
   956  			to_port     = 80
   957  			protocol    = "tcp"
   958  			cidr_blocks = ["10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
   959  
   960  		 security_group_id = "${aws_security_group.web.id}"
   961  	}
   962  
   963  	resource "aws_security_group_rule" "other" {
   964  			type        = "ingress"
   965  			from_port   = 80
   966  			to_port     = 80
   967  			protocol    = "tcp"
   968  			cidr_blocks = ["10.0.5.0/24"]
   969  
   970  		 security_group_id = "${aws_security_group.web.id}"
   971  	}
   972  
   973  	// same a above, but different group, to guard against bad hashing
   974  	resource "aws_security_group_rule" "nat_ingress" {
   975  			type        = "ingress"
   976  			from_port   = 80
   977  			to_port     = 80
   978  			protocol    = "tcp"
   979  			cidr_blocks = ["10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
   980  
   981  		 security_group_id = "${aws_security_group.nat.id}"
   982  	}`, rInt, rInt)
   983  }
   984  
   985  func testAccAWSSecurityGroupRulePartialMatching_Source(rInt int) string {
   986  	return fmt.Sprintf(`
   987  	resource "aws_vpc" "default" {
   988  		cidr_block = "10.0.0.0/16"
   989  		tags {
   990  			Name = "tf-sg-rule-bug"
   991  		}
   992  	}
   993  
   994  	resource "aws_security_group" "web" {
   995  			name = "tf-other-%d"
   996  			vpc_id = "${aws_vpc.default.id}"
   997  			tags {
   998  					Name        = "tf-other-sg"
   999  			}
  1000  	}
  1001  
  1002  	resource "aws_security_group" "nat" {
  1003  			name = "tf-nat-%d"
  1004  			vpc_id = "${aws_vpc.default.id}"
  1005  			tags {
  1006  					Name        = "tf-nat-sg"
  1007  			}
  1008  	}
  1009  
  1010  	resource "aws_security_group_rule" "source_ingress" {
  1011  			type        = "ingress"
  1012  			from_port   = 80
  1013  			to_port     = 80
  1014  			protocol    = "tcp"
  1015  
  1016  									source_security_group_id = "${aws_security_group.nat.id}"
  1017  		 security_group_id = "${aws_security_group.web.id}"
  1018  	}
  1019  
  1020  	resource "aws_security_group_rule" "other_ingress" {
  1021  			type        = "ingress"
  1022  			from_port   = 80
  1023  			to_port     = 80
  1024  			protocol    = "tcp"
  1025  			cidr_blocks = ["10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
  1026  
  1027  		 security_group_id = "${aws_security_group.web.id}"
  1028  	}`, rInt, rInt)
  1029  }
  1030  
  1031  var testAccAWSSecurityGroupRuleRace = func() string {
  1032  	var b bytes.Buffer
  1033  	iterations := 50
  1034  	b.WriteString(fmt.Sprintf(`
  1035  		resource "aws_vpc" "default" {
  1036  			cidr_block = "10.0.0.0/16"
  1037  			tags { Name = "tf-sg-rule-race" }
  1038  		}
  1039  
  1040  		resource "aws_security_group" "race" {
  1041  			name   = "tf-sg-rule-race-group-%d"
  1042  			vpc_id = "${aws_vpc.default.id}"
  1043  		}
  1044  	`, acctest.RandInt()))
  1045  	for i := 1; i < iterations; i++ {
  1046  		b.WriteString(fmt.Sprintf(`
  1047  			resource "aws_security_group_rule" "ingress%d" {
  1048  				security_group_id = "${aws_security_group.race.id}"
  1049  				type              = "ingress"
  1050  				from_port         = %d
  1051  				to_port           = %d
  1052  				protocol          = "tcp"
  1053  				cidr_blocks       = ["10.0.0.%d/32"]
  1054  			}
  1055  
  1056  			resource "aws_security_group_rule" "egress%d" {
  1057  				security_group_id = "${aws_security_group.race.id}"
  1058  				type              = "egress"
  1059  				from_port         = %d
  1060  				to_port           = %d
  1061  				protocol          = "tcp"
  1062  				cidr_blocks       = ["10.0.0.%d/32"]
  1063  			}
  1064  		`, i, i, i, i, i, i, i, i))
  1065  	}
  1066  	return b.String()
  1067  }()
  1068  
  1069  const testAccAWSSecurityGroupRulePrefixListEgressConfig = `
  1070  
  1071  resource "aws_vpc" "tf_sg_prefix_list_egress_test" {
  1072      cidr_block = "10.0.0.0/16"
  1073      tags {
  1074              Name = "tf_sg_prefix_list_egress_test"
  1075      }
  1076  }
  1077  
  1078  resource "aws_route_table" "default" {
  1079      vpc_id = "${aws_vpc.tf_sg_prefix_list_egress_test.id}"
  1080  }
  1081  
  1082  resource "aws_vpc_endpoint" "s3-us-west-2" {
  1083    	vpc_id = "${aws_vpc.tf_sg_prefix_list_egress_test.id}"
  1084    	service_name = "com.amazonaws.us-west-2.s3"
  1085    	route_table_ids = ["${aws_route_table.default.id}"]
  1086    	policy = <<POLICY
  1087  {
  1088  	"Version": "2012-10-17",
  1089  	"Statement": [
  1090  		{
  1091  			"Sid":"AllowAll",
  1092  			"Effect":"Allow",
  1093  			"Principal":"*",
  1094  			"Action":"*",
  1095  			"Resource":"*"
  1096  		}
  1097  	]
  1098  }
  1099  POLICY
  1100  }
  1101  
  1102  resource "aws_security_group" "egress" {
  1103      name = "terraform_acceptance_test_prefix_list_egress"
  1104      description = "Used in the terraform acceptance tests"
  1105      vpc_id = "${aws_vpc.tf_sg_prefix_list_egress_test.id}"
  1106  }
  1107  
  1108  resource "aws_security_group_rule" "egress_1" {
  1109    type = "egress"
  1110    protocol = "-1"
  1111    from_port = 0
  1112    to_port = 0
  1113    prefix_list_ids = ["${aws_vpc_endpoint.s3-us-west-2.prefix_list_id}"]
  1114  	security_group_id = "${aws_security_group.egress.id}"
  1115  }
  1116  `
  1117  
  1118  func testAccAWSSecurityGroupRuleSelfInSource(rInt int) string {
  1119  	return fmt.Sprintf(`
  1120  	resource "aws_vpc" "foo" {
  1121  		cidr_block = "10.1.0.0/16"
  1122  
  1123  		tags {
  1124  			Name = "tf_sg_rule_self_group"
  1125  		}
  1126  	}
  1127  
  1128  	resource "aws_security_group" "web" {
  1129  		name        = "allow_all-%d"
  1130  		description = "Allow all inbound traffic"
  1131  		vpc_id      = "${aws_vpc.foo.id}"
  1132  	}
  1133  
  1134  	resource "aws_security_group_rule" "allow_self" {
  1135  		type                     = "ingress"
  1136  		from_port                = 0
  1137  		to_port                  = 0
  1138  		protocol                 = "-1"
  1139  		security_group_id        = "${aws_security_group.web.id}"
  1140  		source_security_group_id = "${aws_security_group.web.id}"
  1141  	}`, rInt)
  1142  }
  1143  
  1144  func testAccAWSSecurityGroupRuleExpectInvalidType(rInt int) string {
  1145  	return fmt.Sprintf(`
  1146  	resource "aws_vpc" "foo" {
  1147  		cidr_block = "10.1.0.0/16"
  1148  
  1149  		tags {
  1150  			Name = "tf_sg_rule_self_group"
  1151  		}
  1152  	}
  1153  
  1154  	resource "aws_security_group" "web" {
  1155  		name        = "allow_all-%d"
  1156  		description = "Allow all inbound traffic"
  1157  		vpc_id      = "${aws_vpc.foo.id}"
  1158  	}
  1159  
  1160  	resource "aws_security_group_rule" "allow_self" {
  1161  		type                     = "foobar"
  1162  		from_port                = 0
  1163  		to_port                  = 0
  1164  		protocol                 = "-1"
  1165  		security_group_id        = "${aws_security_group.web.id}"
  1166  		source_security_group_id = "${aws_security_group.web.id}"
  1167  	}`, rInt)
  1168  }