github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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  func TestAccAWSSecurityGroupRule_ExpectInvalidCIDR(t *testing.T) {
   358  	rInt := acctest.RandInt()
   359  	resource.Test(t, resource.TestCase{
   360  		PreCheck:     func() { testAccPreCheck(t) },
   361  		Providers:    testAccProviders,
   362  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   363  		Steps: []resource.TestStep{
   364  			{
   365  				Config:      testAccAWSSecurityGroupRuleInvalidIPv4CIDR(rInt),
   366  				ExpectError: regexp.MustCompile("invalid CIDR address: 1.2.3.4/33"),
   367  			},
   368  			{
   369  				Config:      testAccAWSSecurityGroupRuleInvalidIPv6CIDR(rInt),
   370  				ExpectError: regexp.MustCompile("invalid CIDR address: ::/244"),
   371  			},
   372  		},
   373  	})
   374  }
   375  
   376  // testing partial match implementation
   377  func TestAccAWSSecurityGroupRule_PartialMatching_basic(t *testing.T) {
   378  	var group ec2.SecurityGroup
   379  	rInt := acctest.RandInt()
   380  
   381  	p := ec2.IpPermission{
   382  		FromPort:   aws.Int64(80),
   383  		ToPort:     aws.Int64(80),
   384  		IpProtocol: aws.String("tcp"),
   385  		IpRanges: []*ec2.IpRange{
   386  			{CidrIp: aws.String("10.0.2.0/24")},
   387  			{CidrIp: aws.String("10.0.3.0/24")},
   388  			{CidrIp: aws.String("10.0.4.0/24")},
   389  		},
   390  	}
   391  
   392  	o := ec2.IpPermission{
   393  		FromPort:   aws.Int64(80),
   394  		ToPort:     aws.Int64(80),
   395  		IpProtocol: aws.String("tcp"),
   396  		IpRanges: []*ec2.IpRange{
   397  			{CidrIp: aws.String("10.0.5.0/24")},
   398  		},
   399  	}
   400  
   401  	resource.Test(t, resource.TestCase{
   402  		PreCheck:     func() { testAccPreCheck(t) },
   403  		Providers:    testAccProviders,
   404  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   405  		Steps: []resource.TestStep{
   406  			{
   407  				Config: testAccAWSSecurityGroupRulePartialMatching(rInt),
   408  				Check: resource.ComposeTestCheckFunc(
   409  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   410  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.ingress", &group, &p, "ingress"),
   411  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.other", &group, &o, "ingress"),
   412  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.nat_ingress", &group, &o, "ingress"),
   413  				),
   414  			},
   415  		},
   416  	})
   417  }
   418  
   419  func TestAccAWSSecurityGroupRule_PartialMatching_Source(t *testing.T) {
   420  	var group ec2.SecurityGroup
   421  	var nat ec2.SecurityGroup
   422  	var p ec2.IpPermission
   423  	rInt := acctest.RandInt()
   424  
   425  	// This function creates the expected IPPermission with the group id from an
   426  	// external security group, needed because Security Group IDs are generated on
   427  	// AWS side and can't be known ahead of time.
   428  	setupSG := func(*terraform.State) error {
   429  		if nat.GroupId == nil {
   430  			return fmt.Errorf("Error: nat group has nil GroupID")
   431  		}
   432  
   433  		p = ec2.IpPermission{
   434  			FromPort:   aws.Int64(80),
   435  			ToPort:     aws.Int64(80),
   436  			IpProtocol: aws.String("tcp"),
   437  			UserIdGroupPairs: []*ec2.UserIdGroupPair{
   438  				{GroupId: nat.GroupId},
   439  			},
   440  		}
   441  
   442  		return nil
   443  	}
   444  
   445  	resource.Test(t, resource.TestCase{
   446  		PreCheck:     func() { testAccPreCheck(t) },
   447  		Providers:    testAccProviders,
   448  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   449  		Steps: []resource.TestStep{
   450  			{
   451  				Config: testAccAWSSecurityGroupRulePartialMatching_Source(rInt),
   452  				Check: resource.ComposeTestCheckFunc(
   453  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   454  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.nat", &nat),
   455  					setupSG,
   456  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.source_ingress", &group, &p, "ingress"),
   457  				),
   458  			},
   459  		},
   460  	})
   461  }
   462  
   463  func TestAccAWSSecurityGroupRule_Issue5310(t *testing.T) {
   464  	var group ec2.SecurityGroup
   465  
   466  	resource.Test(t, resource.TestCase{
   467  		PreCheck:     func() { testAccPreCheck(t) },
   468  		Providers:    testAccProviders,
   469  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   470  		Steps: []resource.TestStep{
   471  			{
   472  				Config: testAccAWSSecurityGroupRuleIssue5310,
   473  				Check: resource.ComposeTestCheckFunc(
   474  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.issue_5310", &group),
   475  				),
   476  			},
   477  		},
   478  	})
   479  }
   480  
   481  func TestAccAWSSecurityGroupRule_Race(t *testing.T) {
   482  	var group ec2.SecurityGroup
   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: testAccAWSSecurityGroupRuleRace,
   491  				Check: resource.ComposeTestCheckFunc(
   492  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.race", &group),
   493  				),
   494  			},
   495  		},
   496  	})
   497  }
   498  
   499  func TestAccAWSSecurityGroupRule_SelfSource(t *testing.T) {
   500  	var group ec2.SecurityGroup
   501  	rInt := acctest.RandInt()
   502  
   503  	resource.Test(t, resource.TestCase{
   504  		PreCheck:     func() { testAccPreCheck(t) },
   505  		Providers:    testAccProviders,
   506  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   507  		Steps: []resource.TestStep{
   508  			{
   509  				Config: testAccAWSSecurityGroupRuleSelfInSource(rInt),
   510  				Check: resource.ComposeTestCheckFunc(
   511  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.web", &group),
   512  				),
   513  			},
   514  		},
   515  	})
   516  }
   517  
   518  func TestAccAWSSecurityGroupRule_PrefixListEgress(t *testing.T) {
   519  	var group ec2.SecurityGroup
   520  	var endpoint ec2.VpcEndpoint
   521  	var p ec2.IpPermission
   522  
   523  	// This function creates the expected IPPermission with the prefix list ID from
   524  	// the VPC Endpoint created in the test
   525  	setupSG := func(*terraform.State) error {
   526  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   527  		prefixListInput := &ec2.DescribePrefixListsInput{
   528  			Filters: []*ec2.Filter{
   529  				{Name: aws.String("prefix-list-name"), Values: []*string{endpoint.ServiceName}},
   530  			},
   531  		}
   532  
   533  		log.Printf("[DEBUG] Reading VPC Endpoint prefix list: %s", prefixListInput)
   534  		prefixListsOutput, err := conn.DescribePrefixLists(prefixListInput)
   535  
   536  		if err != nil {
   537  			_, ok := err.(awserr.Error)
   538  			if !ok {
   539  				return fmt.Errorf("Error reading VPC Endpoint prefix list: %s", err.Error())
   540  			}
   541  		}
   542  
   543  		if len(prefixListsOutput.PrefixLists) != 1 {
   544  			return fmt.Errorf("There are multiple prefix lists associated with the service name '%s'. Unexpected", prefixListsOutput)
   545  		}
   546  
   547  		p = ec2.IpPermission{
   548  			IpProtocol: aws.String("-1"),
   549  			PrefixListIds: []*ec2.PrefixListId{
   550  				{PrefixListId: prefixListsOutput.PrefixLists[0].PrefixListId},
   551  			},
   552  		}
   553  
   554  		return nil
   555  	}
   556  
   557  	resource.Test(t, resource.TestCase{
   558  		PreCheck:     func() { testAccPreCheck(t) },
   559  		Providers:    testAccProviders,
   560  		CheckDestroy: testAccCheckAWSSecurityGroupRuleDestroy,
   561  		Steps: []resource.TestStep{
   562  			{
   563  				Config: testAccAWSSecurityGroupRulePrefixListEgressConfig,
   564  				Check: resource.ComposeTestCheckFunc(
   565  					testAccCheckAWSSecurityGroupRuleExists("aws_security_group.egress", &group),
   566  					// lookup info on the VPC Endpoint created, to populate the expected
   567  					// IP Perm
   568  					testAccCheckVpcEndpointExists("aws_vpc_endpoint.s3-us-west-2", &endpoint),
   569  					setupSG,
   570  					testAccCheckAWSSecurityGroupRuleAttributes("aws_security_group_rule.egress_1", &group, &p, "egress"),
   571  				),
   572  			},
   573  		},
   574  	})
   575  }
   576  
   577  func testAccCheckAWSSecurityGroupRuleDestroy(s *terraform.State) error {
   578  	conn := testAccProvider.Meta().(*AWSClient).ec2conn
   579  
   580  	for _, rs := range s.RootModule().Resources {
   581  		if rs.Type != "aws_security_group" {
   582  			continue
   583  		}
   584  
   585  		// Retrieve our group
   586  		req := &ec2.DescribeSecurityGroupsInput{
   587  			GroupIds: []*string{aws.String(rs.Primary.ID)},
   588  		}
   589  		resp, err := conn.DescribeSecurityGroups(req)
   590  		if err == nil {
   591  			if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID {
   592  				return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID)
   593  			}
   594  
   595  			return nil
   596  		}
   597  
   598  		ec2err, ok := err.(awserr.Error)
   599  		if !ok {
   600  			return err
   601  		}
   602  		// Confirm error code is what we want
   603  		if ec2err.Code() != "InvalidGroup.NotFound" {
   604  			return err
   605  		}
   606  	}
   607  
   608  	return nil
   609  }
   610  
   611  func testAccCheckAWSSecurityGroupRuleExists(n string, group *ec2.SecurityGroup) resource.TestCheckFunc {
   612  	return func(s *terraform.State) error {
   613  		rs, ok := s.RootModule().Resources[n]
   614  		if !ok {
   615  			return fmt.Errorf("Not found: %s", n)
   616  		}
   617  
   618  		if rs.Primary.ID == "" {
   619  			return fmt.Errorf("No Security Group is set")
   620  		}
   621  
   622  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   623  		req := &ec2.DescribeSecurityGroupsInput{
   624  			GroupIds: []*string{aws.String(rs.Primary.ID)},
   625  		}
   626  		resp, err := conn.DescribeSecurityGroups(req)
   627  		if err != nil {
   628  			return err
   629  		}
   630  
   631  		if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID {
   632  			*group = *resp.SecurityGroups[0]
   633  			return nil
   634  		}
   635  
   636  		return fmt.Errorf("Security Group not found")
   637  	}
   638  }
   639  
   640  func testAccCheckAWSSecurityGroupRuleAttributes(n string, group *ec2.SecurityGroup, p *ec2.IpPermission, ruleType string) resource.TestCheckFunc {
   641  	return func(s *terraform.State) error {
   642  		rs, ok := s.RootModule().Resources[n]
   643  		if !ok {
   644  			return fmt.Errorf("Security Group Rule Not found: %s", n)
   645  		}
   646  
   647  		if rs.Primary.ID == "" {
   648  			return fmt.Errorf("No Security Group Rule is set")
   649  		}
   650  
   651  		if p == nil {
   652  			p = &ec2.IpPermission{
   653  				FromPort:   aws.Int64(80),
   654  				ToPort:     aws.Int64(8000),
   655  				IpProtocol: aws.String("tcp"),
   656  				IpRanges:   []*ec2.IpRange{{CidrIp: aws.String("10.0.0.0/8")}},
   657  			}
   658  		}
   659  
   660  		var matchingRule *ec2.IpPermission
   661  		var rules []*ec2.IpPermission
   662  		if ruleType == "ingress" {
   663  			rules = group.IpPermissions
   664  		} else {
   665  			rules = group.IpPermissionsEgress
   666  		}
   667  
   668  		if len(rules) == 0 {
   669  			return fmt.Errorf("No IPPerms")
   670  		}
   671  
   672  		for _, r := range rules {
   673  			if r.ToPort != nil && *p.ToPort != *r.ToPort {
   674  				continue
   675  			}
   676  
   677  			if r.FromPort != nil && *p.FromPort != *r.FromPort {
   678  				continue
   679  			}
   680  
   681  			if r.IpProtocol != nil && *p.IpProtocol != *r.IpProtocol {
   682  				continue
   683  			}
   684  
   685  			remaining := len(p.IpRanges)
   686  			for _, ip := range p.IpRanges {
   687  				for _, rip := range r.IpRanges {
   688  					if *ip.CidrIp == *rip.CidrIp {
   689  						remaining--
   690  					}
   691  				}
   692  			}
   693  
   694  			if remaining > 0 {
   695  				continue
   696  			}
   697  
   698  			remaining = len(p.UserIdGroupPairs)
   699  			for _, ip := range p.UserIdGroupPairs {
   700  				for _, rip := range r.UserIdGroupPairs {
   701  					if *ip.GroupId == *rip.GroupId {
   702  						remaining--
   703  					}
   704  				}
   705  			}
   706  
   707  			if remaining > 0 {
   708  				continue
   709  			}
   710  
   711  			remaining = len(p.PrefixListIds)
   712  			for _, pip := range p.PrefixListIds {
   713  				for _, rpip := range r.PrefixListIds {
   714  					if *pip.PrefixListId == *rpip.PrefixListId {
   715  						remaining--
   716  					}
   717  				}
   718  			}
   719  
   720  			if remaining > 0 {
   721  				continue
   722  			}
   723  
   724  			matchingRule = r
   725  		}
   726  
   727  		if matchingRule != nil {
   728  			log.Printf("[DEBUG] Matching rule found : %s", matchingRule)
   729  			return nil
   730  		}
   731  
   732  		return fmt.Errorf("Error here\n\tlooking for %s, wasn't found in %s", p, rules)
   733  	}
   734  }
   735  
   736  func testAccAWSSecurityGroupRuleIngressConfig(rInt int) string {
   737  	return fmt.Sprintf(`
   738  	resource "aws_security_group" "web" {
   739  		name = "terraform_test_%d"
   740  		description = "Used in the terraform acceptance tests"
   741  
   742  					tags {
   743  									Name = "tf-acc-test"
   744  					}
   745  	}
   746  
   747  	resource "aws_security_group_rule" "ingress_1" {
   748  		type = "ingress"
   749  		protocol = "tcp"
   750  		from_port = 80
   751  		to_port = 8000
   752  		cidr_blocks = ["10.0.0.0/8"]
   753  
   754  		security_group_id = "${aws_security_group.web.id}"
   755  	}`, rInt)
   756  }
   757  
   758  const testAccAWSSecurityGroupRuleIngress_ipv6Config = `
   759  resource "aws_vpc" "tftest" {
   760    cidr_block = "10.0.0.0/16"
   761  
   762    tags {
   763      Name = "tf-testing"
   764    }
   765  }
   766  
   767  resource "aws_security_group" "web" {
   768    vpc_id = "${aws_vpc.tftest.id}"
   769  
   770    tags {
   771      Name = "tf-acc-test"
   772    }
   773  }
   774  
   775  resource "aws_security_group_rule" "ingress_1" {
   776    type        = "ingress"
   777    protocol    = "6"
   778    from_port   = 80
   779    to_port     = 8000
   780    ipv6_cidr_blocks = ["::/0"]
   781  
   782    security_group_id = "${aws_security_group.web.id}"
   783  }
   784  `
   785  
   786  const testAccAWSSecurityGroupRuleIngress_protocolConfig = `
   787  resource "aws_vpc" "tftest" {
   788    cidr_block = "10.0.0.0/16"
   789  
   790    tags {
   791      Name = "tf-testing"
   792    }
   793  }
   794  
   795  resource "aws_security_group" "web" {
   796    vpc_id = "${aws_vpc.tftest.id}"
   797  
   798    tags {
   799      Name = "tf-acc-test"
   800    }
   801  }
   802  
   803  resource "aws_security_group_rule" "ingress_1" {
   804    type        = "ingress"
   805    protocol    = "6"
   806    from_port   = 80
   807    to_port     = 8000
   808    cidr_blocks = ["10.0.0.0/8"]
   809  
   810    security_group_id = "${aws_security_group.web.id}"
   811  }
   812  
   813  `
   814  
   815  const testAccAWSSecurityGroupRuleIssue5310 = `
   816  provider "aws" {
   817          region = "us-east-1"
   818  }
   819  
   820  resource "aws_security_group" "issue_5310" {
   821      name = "terraform-test-issue_5310"
   822      description = "SG for test of issue 5310"
   823  }
   824  
   825  resource "aws_security_group_rule" "issue_5310" {
   826      type = "ingress"
   827      from_port = 0
   828      to_port = 65535
   829      protocol = "tcp"
   830      security_group_id = "${aws_security_group.issue_5310.id}"
   831      self = true
   832  }
   833  `
   834  
   835  func testAccAWSSecurityGroupRuleIngressClassicConfig(rInt int) string {
   836  	return fmt.Sprintf(`
   837  	provider "aws" {
   838  					region = "us-east-1"
   839  	}
   840  
   841  	resource "aws_security_group" "web" {
   842  		name = "terraform_test_%d"
   843  		description = "Used in the terraform acceptance tests"
   844  
   845  					tags {
   846  									Name = "tf-acc-test"
   847  					}
   848  	}
   849  
   850  	resource "aws_security_group_rule" "ingress_1" {
   851  		type = "ingress"
   852  		protocol = "tcp"
   853  		from_port = 80
   854  		to_port = 8000
   855  		cidr_blocks = ["10.0.0.0/8"]
   856  
   857  		security_group_id = "${aws_security_group.web.id}"
   858  	}`, rInt)
   859  }
   860  
   861  func testAccAWSSecurityGroupRuleEgressConfig(rInt int) string {
   862  	return fmt.Sprintf(`
   863  	resource "aws_security_group" "web" {
   864  		name = "terraform_test_%d"
   865  		description = "Used in the terraform acceptance tests"
   866  
   867  					tags {
   868  									Name = "tf-acc-test"
   869  					}
   870  	}
   871  
   872  	resource "aws_security_group_rule" "egress_1" {
   873  		type = "egress"
   874  		protocol = "tcp"
   875  		from_port = 80
   876  		to_port = 8000
   877  		cidr_blocks = ["10.0.0.0/8"]
   878  
   879  		security_group_id = "${aws_security_group.web.id}"
   880  	}`, rInt)
   881  }
   882  
   883  const testAccAWSSecurityGroupRuleConfigMultiIngress = `
   884  resource "aws_security_group" "web" {
   885    name = "terraform_acceptance_test_example_2"
   886    description = "Used in the terraform acceptance tests"
   887  }
   888  
   889  resource "aws_security_group" "worker" {
   890    name = "terraform_acceptance_test_example_worker"
   891    description = "Used in the terraform acceptance tests"
   892  }
   893  
   894  
   895  resource "aws_security_group_rule" "ingress_1" {
   896    type = "ingress"
   897    protocol = "tcp"
   898    from_port = 22
   899    to_port = 22
   900    cidr_blocks = ["10.0.0.0/8"]
   901  
   902    security_group_id = "${aws_security_group.web.id}"
   903  }
   904  
   905  resource "aws_security_group_rule" "ingress_2" {
   906    type = "ingress"
   907    protocol = "tcp"
   908    from_port = 80
   909    to_port = 8000
   910          self = true
   911  
   912    security_group_id = "${aws_security_group.web.id}"
   913  }
   914  `
   915  
   916  // check for GH-1985 regression
   917  const testAccAWSSecurityGroupRuleConfigSelfReference = `
   918  provider "aws" {
   919    region = "us-west-2"
   920  }
   921  
   922  resource "aws_vpc" "main" {
   923    cidr_block = "10.0.0.0/16"
   924    tags {
   925      Name = "sg-self-test"
   926    }
   927  }
   928  
   929  resource "aws_security_group" "web" {
   930    name = "main"
   931    vpc_id = "${aws_vpc.main.id}"
   932    tags {
   933      Name = "sg-self-test"
   934    }
   935  }
   936  
   937  resource "aws_security_group_rule" "self" {
   938    type = "ingress"
   939    protocol = "-1"
   940    from_port = 0
   941    to_port = 0
   942    self = true
   943    security_group_id = "${aws_security_group.web.id}"
   944  }
   945  `
   946  
   947  func testAccAWSSecurityGroupRulePartialMatching(rInt int) string {
   948  	return fmt.Sprintf(`
   949  	resource "aws_vpc" "default" {
   950  		cidr_block = "10.0.0.0/16"
   951  		tags {
   952  			Name = "tf-sg-rule-bug"
   953  		}
   954  	}
   955  
   956  	resource "aws_security_group" "web" {
   957  			name = "tf-other-%d"
   958  			vpc_id = "${aws_vpc.default.id}"
   959  			tags {
   960  					Name        = "tf-other-sg"
   961  			}
   962  	}
   963  
   964  	resource "aws_security_group" "nat" {
   965  			name = "tf-nat-%d"
   966  			vpc_id = "${aws_vpc.default.id}"
   967  			tags {
   968  					Name        = "tf-nat-sg"
   969  			}
   970  	}
   971  
   972  	resource "aws_security_group_rule" "ingress" {
   973  			type        = "ingress"
   974  			from_port   = 80
   975  			to_port     = 80
   976  			protocol    = "tcp"
   977  			cidr_blocks = ["10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
   978  
   979  		 security_group_id = "${aws_security_group.web.id}"
   980  	}
   981  
   982  	resource "aws_security_group_rule" "other" {
   983  			type        = "ingress"
   984  			from_port   = 80
   985  			to_port     = 80
   986  			protocol    = "tcp"
   987  			cidr_blocks = ["10.0.5.0/24"]
   988  
   989  		 security_group_id = "${aws_security_group.web.id}"
   990  	}
   991  
   992  	// same a above, but different group, to guard against bad hashing
   993  	resource "aws_security_group_rule" "nat_ingress" {
   994  			type        = "ingress"
   995  			from_port   = 80
   996  			to_port     = 80
   997  			protocol    = "tcp"
   998  			cidr_blocks = ["10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
   999  
  1000  		 security_group_id = "${aws_security_group.nat.id}"
  1001  	}`, rInt, rInt)
  1002  }
  1003  
  1004  func testAccAWSSecurityGroupRulePartialMatching_Source(rInt int) string {
  1005  	return fmt.Sprintf(`
  1006  	resource "aws_vpc" "default" {
  1007  		cidr_block = "10.0.0.0/16"
  1008  		tags {
  1009  			Name = "tf-sg-rule-bug"
  1010  		}
  1011  	}
  1012  
  1013  	resource "aws_security_group" "web" {
  1014  			name = "tf-other-%d"
  1015  			vpc_id = "${aws_vpc.default.id}"
  1016  			tags {
  1017  					Name        = "tf-other-sg"
  1018  			}
  1019  	}
  1020  
  1021  	resource "aws_security_group" "nat" {
  1022  			name = "tf-nat-%d"
  1023  			vpc_id = "${aws_vpc.default.id}"
  1024  			tags {
  1025  					Name        = "tf-nat-sg"
  1026  			}
  1027  	}
  1028  
  1029  	resource "aws_security_group_rule" "source_ingress" {
  1030  			type        = "ingress"
  1031  			from_port   = 80
  1032  			to_port     = 80
  1033  			protocol    = "tcp"
  1034  
  1035  									source_security_group_id = "${aws_security_group.nat.id}"
  1036  		 security_group_id = "${aws_security_group.web.id}"
  1037  	}
  1038  
  1039  	resource "aws_security_group_rule" "other_ingress" {
  1040  			type        = "ingress"
  1041  			from_port   = 80
  1042  			to_port     = 80
  1043  			protocol    = "tcp"
  1044  			cidr_blocks = ["10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"]
  1045  
  1046  		 security_group_id = "${aws_security_group.web.id}"
  1047  	}`, rInt, rInt)
  1048  }
  1049  
  1050  var testAccAWSSecurityGroupRuleRace = func() string {
  1051  	var b bytes.Buffer
  1052  	iterations := 50
  1053  	b.WriteString(fmt.Sprintf(`
  1054  		resource "aws_vpc" "default" {
  1055  			cidr_block = "10.0.0.0/16"
  1056  			tags { Name = "tf-sg-rule-race" }
  1057  		}
  1058  
  1059  		resource "aws_security_group" "race" {
  1060  			name   = "tf-sg-rule-race-group-%d"
  1061  			vpc_id = "${aws_vpc.default.id}"
  1062  		}
  1063  	`, acctest.RandInt()))
  1064  	for i := 1; i < iterations; i++ {
  1065  		b.WriteString(fmt.Sprintf(`
  1066  			resource "aws_security_group_rule" "ingress%d" {
  1067  				security_group_id = "${aws_security_group.race.id}"
  1068  				type              = "ingress"
  1069  				from_port         = %d
  1070  				to_port           = %d
  1071  				protocol          = "tcp"
  1072  				cidr_blocks       = ["10.0.0.%d/32"]
  1073  			}
  1074  
  1075  			resource "aws_security_group_rule" "egress%d" {
  1076  				security_group_id = "${aws_security_group.race.id}"
  1077  				type              = "egress"
  1078  				from_port         = %d
  1079  				to_port           = %d
  1080  				protocol          = "tcp"
  1081  				cidr_blocks       = ["10.0.0.%d/32"]
  1082  			}
  1083  		`, i, i, i, i, i, i, i, i))
  1084  	}
  1085  	return b.String()
  1086  }()
  1087  
  1088  const testAccAWSSecurityGroupRulePrefixListEgressConfig = `
  1089  
  1090  resource "aws_vpc" "tf_sg_prefix_list_egress_test" {
  1091      cidr_block = "10.0.0.0/16"
  1092      tags {
  1093              Name = "tf_sg_prefix_list_egress_test"
  1094      }
  1095  }
  1096  
  1097  resource "aws_route_table" "default" {
  1098      vpc_id = "${aws_vpc.tf_sg_prefix_list_egress_test.id}"
  1099  }
  1100  
  1101  resource "aws_vpc_endpoint" "s3-us-west-2" {
  1102    	vpc_id = "${aws_vpc.tf_sg_prefix_list_egress_test.id}"
  1103    	service_name = "com.amazonaws.us-west-2.s3"
  1104    	route_table_ids = ["${aws_route_table.default.id}"]
  1105    	policy = <<POLICY
  1106  {
  1107  	"Version": "2012-10-17",
  1108  	"Statement": [
  1109  		{
  1110  			"Sid":"AllowAll",
  1111  			"Effect":"Allow",
  1112  			"Principal":"*",
  1113  			"Action":"*",
  1114  			"Resource":"*"
  1115  		}
  1116  	]
  1117  }
  1118  POLICY
  1119  }
  1120  
  1121  resource "aws_security_group" "egress" {
  1122      name = "terraform_acceptance_test_prefix_list_egress"
  1123      description = "Used in the terraform acceptance tests"
  1124      vpc_id = "${aws_vpc.tf_sg_prefix_list_egress_test.id}"
  1125  }
  1126  
  1127  resource "aws_security_group_rule" "egress_1" {
  1128    type = "egress"
  1129    protocol = "-1"
  1130    from_port = 0
  1131    to_port = 0
  1132    prefix_list_ids = ["${aws_vpc_endpoint.s3-us-west-2.prefix_list_id}"]
  1133  	security_group_id = "${aws_security_group.egress.id}"
  1134  }
  1135  `
  1136  
  1137  func testAccAWSSecurityGroupRuleSelfInSource(rInt int) string {
  1138  	return fmt.Sprintf(`
  1139  	resource "aws_vpc" "foo" {
  1140  		cidr_block = "10.1.0.0/16"
  1141  
  1142  		tags {
  1143  			Name = "tf_sg_rule_self_group"
  1144  		}
  1145  	}
  1146  
  1147  	resource "aws_security_group" "web" {
  1148  		name        = "allow_all-%d"
  1149  		description = "Allow all inbound traffic"
  1150  		vpc_id      = "${aws_vpc.foo.id}"
  1151  	}
  1152  
  1153  	resource "aws_security_group_rule" "allow_self" {
  1154  		type                     = "ingress"
  1155  		from_port                = 0
  1156  		to_port                  = 0
  1157  		protocol                 = "-1"
  1158  		security_group_id        = "${aws_security_group.web.id}"
  1159  		source_security_group_id = "${aws_security_group.web.id}"
  1160  	}`, rInt)
  1161  }
  1162  
  1163  func testAccAWSSecurityGroupRuleExpectInvalidType(rInt int) string {
  1164  	return fmt.Sprintf(`
  1165  	resource "aws_vpc" "foo" {
  1166  		cidr_block = "10.1.0.0/16"
  1167  
  1168  		tags {
  1169  			Name = "tf_sg_rule_self_group"
  1170  		}
  1171  	}
  1172  
  1173  	resource "aws_security_group" "web" {
  1174  		name        = "allow_all-%d"
  1175  		description = "Allow all inbound traffic"
  1176  		vpc_id      = "${aws_vpc.foo.id}"
  1177  	}
  1178  
  1179  	resource "aws_security_group_rule" "allow_self" {
  1180  		type                     = "foobar"
  1181  		from_port                = 0
  1182  		to_port                  = 0
  1183  		protocol                 = "-1"
  1184  		security_group_id        = "${aws_security_group.web.id}"
  1185  		source_security_group_id = "${aws_security_group.web.id}"
  1186  	}`, rInt)
  1187  }
  1188  
  1189  func testAccAWSSecurityGroupRuleInvalidIPv4CIDR(rInt int) string {
  1190  	return fmt.Sprintf(`
  1191  resource "aws_security_group" "foo" {
  1192    name = "testing-failure-%d"
  1193  }
  1194  
  1195  resource "aws_security_group_rule" "ing" {
  1196    type = "ingress"
  1197    from_port = 0
  1198    to_port = 0
  1199    protocol = "-1"
  1200    cidr_blocks = ["1.2.3.4/33"]
  1201    security_group_id = "${aws_security_group.foo.id}"
  1202  }`, rInt)
  1203  }
  1204  
  1205  func testAccAWSSecurityGroupRuleInvalidIPv6CIDR(rInt int) string {
  1206  	return fmt.Sprintf(`
  1207  resource "aws_security_group" "foo" {
  1208    name = "testing-failure-%d"
  1209  }
  1210  
  1211  resource "aws_security_group_rule" "ing" {
  1212    type = "egress"
  1213    from_port = 0
  1214    to_port = 0
  1215    protocol = "-1"
  1216    ipv6_cidr_blocks = ["::/244"]
  1217    security_group_id = "${aws_security_group.foo.id}"
  1218  }`, rInt)
  1219  }