Merge pull request #1765 from hashicorp/f-aws-security-group-remove-default-egress

provider/aws: Remove default egress rule from Security Group on creation
This commit is contained in:
Clint 2015-05-05 16:47:23 -05:00
commit a4000941c2
4 changed files with 210 additions and 3 deletions

View File

@ -181,6 +181,13 @@ resource "aws_security_group" "foo" {
vpc_id = "${aws_vpc.foo.id}" vpc_id = "${aws_vpc.foo.id}"
description = "foo" description = "foo"
name = "foo" name = "foo"
egress {
from_port = 0
to_port = 0
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"]
}
} }
resource "aws_network_interface" "bar" { resource "aws_network_interface" "bar" {

View File

@ -185,12 +185,44 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er
Refresh: SGStateRefreshFunc(conn, d.Id()), Refresh: SGStateRefreshFunc(conn, d.Id()),
Timeout: 1 * time.Minute, Timeout: 1 * time.Minute,
} }
if _, err := stateConf.WaitForState(); err != nil {
resp, err := stateConf.WaitForState()
if err != nil {
return fmt.Errorf( return fmt.Errorf(
"Error waiting for Security Group (%s) to become available: %s", "Error waiting for Security Group (%s) to become available: %s",
d.Id(), err) d.Id(), err)
} }
// AWS defaults all Security Groups to have an ALLOW ALL egress rule. Here we
// revoke that rule, so users don't unknowningly have/use it.
group := resp.(*ec2.SecurityGroup)
if group.VPCID != nil && *group.VPCID != "" {
log.Printf("[DEBUG] Revoking default egress rule for Security Group for %s", d.Id())
req := &ec2.RevokeSecurityGroupEgressInput{
GroupID: createResp.GroupID,
IPPermissions: []*ec2.IPPermission{
&ec2.IPPermission{
FromPort: aws.Long(int64(0)),
ToPort: aws.Long(int64(0)),
IPRanges: []*ec2.IPRange{
&ec2.IPRange{
CIDRIP: aws.String("0.0.0.0/0"),
},
},
IPProtocol: aws.String("-1"),
},
},
}
if _, err = conn.RevokeSecurityGroupEgress(req); err != nil {
return fmt.Errorf(
"Error revoking default egress rule for Security Group (%s): %s",
d.Id(), err)
}
}
return resourceAwsSecurityGroupUpdate(d, meta) return resourceAwsSecurityGroupUpdate(d, meta)
} }

View File

@ -214,6 +214,40 @@ func TestAccAWSSecurityGroup_generatedName(t *testing.T) {
}) })
} }
func TestAccAWSSecurityGroup_DefaultEgress(t *testing.T) {
// VPC
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSecurityGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSSecurityGroupConfigDefaultEgress,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSecurityGroupExistsWithoutDefault("aws_security_group.worker"),
),
},
},
})
// Classic
var group ec2.SecurityGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSecurityGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSSecurityGroupConfigClassic,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSSecurityGroupExists("aws_security_group.web", &group),
),
},
},
})
}
func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error { func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ec2conn conn := testAccProvider.Meta().(*AWSClient).ec2conn
@ -394,6 +428,38 @@ func testAccCheckAWSSecurityGroupAttributesChanged(group *ec2.SecurityGroup) res
} }
} }
func testAccCheckAWSSecurityGroupExistsWithoutDefault(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Security Group is set")
}
conn := testAccProvider.Meta().(*AWSClient).ec2conn
req := &ec2.DescribeSecurityGroupsInput{
GroupIDs: []*string{aws.String(rs.Primary.ID)},
}
resp, err := conn.DescribeSecurityGroups(req)
if err != nil {
return err
}
if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupID == rs.Primary.ID {
group := *resp.SecurityGroups[0]
if len(group.IPPermissionsEgress) != 1 {
return fmt.Errorf("Security Group should have only 1 egress rule, got %d", len(group.IPPermissionsEgress))
}
}
return nil
}
}
const testAccAWSSecurityGroupConfig = ` const testAccAWSSecurityGroupConfig = `
resource "aws_security_group" "web" { resource "aws_security_group" "web" {
name = "terraform_acceptance_test_example" name = "terraform_acceptance_test_example"
@ -406,6 +472,13 @@ resource "aws_security_group" "web" {
cidr_blocks = ["10.0.0.0/8"] cidr_blocks = ["10.0.0.0/8"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
tags { tags {
Name = "tf-acc-test" Name = "tf-acc-test"
} }
@ -430,6 +503,13 @@ resource "aws_security_group" "web" {
to_port = 8000 to_port = 8000
cidr_blocks = ["0.0.0.0/0", "10.0.0.0/8"] cidr_blocks = ["0.0.0.0/0", "10.0.0.0/8"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
} }
` `
@ -444,6 +524,13 @@ resource "aws_security_group" "web" {
to_port = 8000 to_port = 8000
self = true self = true
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
} }
` `
@ -484,6 +571,13 @@ resource "aws_security_group" "worker" {
to_port = 8000 to_port = 8000
cidr_blocks = ["10.0.0.0/8"] cidr_blocks = ["10.0.0.0/8"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
} }
resource "aws_security_group" "web" { resource "aws_security_group" "web" {
@ -510,6 +604,13 @@ resource "aws_security_group" "web" {
to_port = 8000 to_port = 8000
security_groups = ["${aws_security_group.worker.id}"] security_groups = ["${aws_security_group.worker.id}"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
} }
` `
@ -525,6 +626,13 @@ resource "aws_security_group" "foo" {
cidr_blocks = ["10.0.0.0/8"] cidr_blocks = ["10.0.0.0/8"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
tags { tags {
foo = "bar" foo = "bar"
} }
@ -543,6 +651,13 @@ resource "aws_security_group" "foo" {
cidr_blocks = ["10.0.0.0/8"] cidr_blocks = ["10.0.0.0/8"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
tags { tags {
bar = "baz" bar = "baz"
} }
@ -558,8 +673,48 @@ resource "aws_security_group" "web" {
cidr_blocks = ["10.0.0.0/8"] cidr_blocks = ["10.0.0.0/8"]
} }
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
tags { tags {
Name = "tf-acc-test" Name = "tf-acc-test"
} }
} }
` `
const testAccAWSSecurityGroupConfigDefaultEgress = `
resource "aws_vpc" "tf_sg_egress_test" {
cidr_block = "10.0.0.0/16"
tags {
Name = "tf_sg_egress_test"
}
}
resource "aws_security_group" "worker" {
name = "terraform_acceptance_test_example_1"
description = "Used in the terraform acceptance tests"
vpc_id = "${aws_vpc.tf_sg_egress_test.id}"
egress {
protocol = "tcp"
from_port = 80
to_port = 8000
cidr_blocks = ["10.0.0.0/8"]
}
}
`
const testAccAWSSecurityGroupConfigClassic = `
provider "aws" {
region = "us-east-1"
}
resource "aws_security_group" "web" {
name = "terraform_acceptance_test_example_1"
description = "Used in the terraform acceptance tests"
}
`

View File

@ -63,9 +63,8 @@ The following arguments are supported:
* `description` - (Required) The security group description. * `description` - (Required) The security group description.
* `ingress` - (Optional) Can be specified multiple times for each * `ingress` - (Optional) Can be specified multiple times for each
ingress rule. Each ingress block supports fields documented below. ingress rule. Each ingress block supports fields documented below.
* `egress` - (Optional) Can be specified multiple times for each * `egress` - (Optional, VPC only) Can be specified multiple times for each
egress rule. Each egress block supports fields documented below. egress rule. Each egress block supports fields documented below.
VPC only.
* `vpc_id` - (Optional) The VPC ID. * `vpc_id` - (Optional) The VPC ID.
* `tags` - (Optional) A mapping of tags to assign to the resource. * `tags` - (Optional) A mapping of tags to assign to the resource.
@ -93,6 +92,20 @@ The `egress` block supports:
a source to this egress rule. a source to this egress rule.
* `to_port` - (Required) The end range port. * `to_port` - (Required) The end range port.
~> **NOTE on Egress rules:** By default, AWS creates an `ALLOW ALL` egress rule when creating a
new Security Group inside of a VPC. When creating a new Security
Group inside a VPC, **Terraform will remove this default rule**, and require you
specifically re-create it if you desire that rule. We feel this leads to fewer
surprises in terms of controlling your egress rules. If you desire this rule to
be in place, you can use this `egress` block:
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_block = "0.0.0.0/0"
}
## Attributes Reference ## Attributes Reference
The following attributes are exported: The following attributes are exported: