使用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更安全。