使用Terraform安全地更新AWS安全组

不好的模式

请将以下内容用中文本地化,仅需要一个选项:
这个东西

resource "aws_security_group" "test" {
    name        = "test"
    vpc_id      = "${aws_vpc.test.id}"
    ingress {
        from_port       = 22
        to_port         = 22
        protocol        = "tcp"
        cidr_blocks     = ["x.x.x.x/32"]
    }
}

如果这样改变的话

 resource "aws_security_group" "test" {
     name        = "test"
     vpc_id      = "${aws_vpc.test.id}"
     ingress {
         from_port       = 22
         to_port         = 22
         protocol        = "tcp"
-        cidr_blocks     = ["x.x.x.x/32"]
+        cidr_blocks     = ["x.x.x.x/32","y.y.y.y/32"]
     }
 }

日志显示了以下情况,差异有些可疑。看起来好像将所有的进入流量删除,然后再次创建了全部的流量。

aws_security_group.test: Modifying...
  ingress.2293169953.cidr_blocks.#:     "1" => "0"
2016/10/27 18:33:14 [DEBUG] apply: aws_security_group.test: executing Apply
  ingress.2293169953.cidr_blocks.0:     "x.x.x.x/32" => ""
  ingress.2293169953.from_port:         "22" => "0"
  ingress.2293169953.protocol:          "tcp" => ""
  ingress.2293169953.security_groups.#: "0" => "0"
  ingress.2293169953.self:              "0" => "0"
  ingress.2293169953.to_port:           "22" => "0"
  ingress.3838495408.cidr_blocks.#:     "0" => "2"
  ingress.3838495408.cidr_blocks.0:     "" => "x.x.x.x/32"
  ingress.3838495408.cidr_blocks.1:     "" => "y.y.y.y/32"
  ingress.3838495408.from_port:         "" => "22"
  ingress.3838495408.protocol:          "" => "tcp"
  ingress.3838495408.security_groups.#: "0" => "0"
  ingress.3838495408.self:              "" => "0"
  ingress.3838495408.to_port:           "" => "22"

如果设置了TF_LOG=DEBUG并运行,日志将如下所示,并且会感到正在执行“Revoke & Authorize”。

2016/10/27 18:33:15 [DEBUG] terraform-provider-aws: 2016/10/27 18:33:15 [DEBUG] Revoking security group {
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   Description: "Managed by Terraform",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   GroupName: "test",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   IpPermissions: [{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       FromPort: 22,
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       IpProtocol: "tcp",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       IpRanges: [{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:           CidrIp: "x.x.x.x/32"
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:         }],
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       ToPort: 22
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:     }],
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws: } ingress rule: []*ec2.IpPermission{{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   FromPort: 22,
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   IpProtocol: "tcp",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   IpRanges: [{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       CidrIp: "x.x.x.x/32"
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:     }],
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   ToPort: 22
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws: }}
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws: 2016/10/27 18:33:15 [DEBUG] Authorizing security group {
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   Description: "Managed by Terraform",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   GroupName: "test",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   IpPermissions: [{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       FromPort: 22,
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       IpProtocol: "tcp",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       IpRanges: [{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:           CidrIp: "x.x.x.x/32"
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:         }],
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       ToPort: 22
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:     }],
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws: } ingress rule: []*ec2.IpPermission{{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   FromPort: 22,
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   IpProtocol: "tcp",
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   IpRanges: [{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       CidrIp: "x.x.x.x/32"
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:     },{
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:       CidrIp: "y.y.y.y/32"
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:     }],
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws:   ToPort: 22
2016/10/27 18:33:15 [DEBUG] terraform-provider-aws: }}

阅读源代码 https://github.com/hashicorp/terraform/blob/11b3b7cf29fa4120974d293458beac47e1eedd32/builtin/providers/aws/resource_aws_security_group.go#L552-L559

        // TODO: We need to handle partial state better in the in-between
        // in this update.

        // TODO: It'd be nicer to authorize before removing, but then we have
        // to deal with complicated unrolling to get individual CIDR blocks
        // to avoid authorizing already authorized sources. Removing before
        // adding is easier here, and Terraform should be fast enough to
        // not have service issues.

据说,TODO 仅仅是暂时未完成的项目。由于Terraform的速度非常快,可能不会发生任何服务问题(根据我的理解)。

具有安全感和放心的模式

使用aws_security_group_rule

 resource "aws_security_group" "test" {
     name        = "test"
     vpc_id      = "${aws_vpc.test.id}"
 }

 resource "aws_security_group_rule" "test_rule_1" {
     security_group_id = "${aws_security_group.test.id}"
     type = "ingress"
     from_port = 22
     to_port = 22
     protocol = "tcp"
     cidr_blocks = ["x.x.x.x/32"]
 }

+resource "aws_security_group_rule" "test_rule_2" {
+    security_group_id = "${aws_security_group.test.id}"
+    type = "ingress"
+    from_port = 22
+    to_port = 22
+    protocol = "tcp"
+    cidr_blocks = ["y.y.y.y/32"]
+}

这样的话只需要添加。日志如下。

2016/10/27 18:40:29 [DEBUG] apply: aws_security_group_rule.test_rule2: executing Apply
aws_security_group_rule.test: Creating...
  cidr_blocks.#:            "" => "1"
  cidr_blocks.0:            "" => "y.y.y.y/32"
  from_port:                "" => "22"
  protocol:                 "" => "tcp"
  self:                     "" => "0"

2016/10/27 18:40:30 [DEBUG] terraform-provider-aws: 2016/10/27 18:40:30 [DEBUG] Authorizing security group sg-66d6231b Ingress rule: {
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   FromPort: 22,
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   IpProtocol: "tcp",
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   IpRanges: [{
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:       CidrIp: "y.y.y.y/32"
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:     }],
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   ToPort: 22
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws: }
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws: 2016/10/27 18:40:30 [DEBUG] Found rule for Security Group Rule (sgrule-3952629376): {
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   FromPort: 22,
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   IpProtocol: "tcp",
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   IpRanges: [{
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:       CidrIp: "x.x.x.x/32"
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:     },{
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:       CidrIp: "y.y.y.y/32"
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:     }],
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws:   ToPort: 22
2016/10/27 18:40:30 [DEBUG] terraform-provider-aws: }

需要注意的是,如果尝试将 from_port 和 to_port 相同的情况下添加到 cidr_blocks 数组元素中,会导致销毁和添加的情况发生。换句话说,以下方式是不可行的,应该另外准备一个 aws_security_group_rule。

 resource "aws_security_group" "test" {
     name        = "test"
     vpc_id      = "${aws_vpc.test.id}"
 }

 resource "aws_security_group_rule" "test_rule_1" {
     security_group_id = "${aws_security_group.test.id}"
     type = "ingress"
     from_port = 22
     to_port = 22
     protocol = "tcp"
-    cidr_blocks = ["x.x.x.x/32"]
+    cidr_blocks = ["x.x.x.x/32","y.y.y.y/32"]
 }

对于安全组的短暂中断进行思考(补充)

确认删除安全组的入口或出口条目会阻止新的连接,但不会断开已经建立的连接。

所以,只有在执行了”拒绝访问”之后立即执行”授权访问”的短时间内出现新的连接或操作时才会出现问题。如果是TCP协议,可以等待一下(在Linux下默认为1秒)再重新连接,这样可以容忍这段短暂时间;而关键问题则是能否容忍UDP的数据发送失败。

嗯,毫无疑问,使用aws_security_group_rule更安全。

广告
将在 10 秒后关闭
bannerAds