移除AWS安全组规则,完成上传数据库转储后。

huangapple go评论65阅读模式
英文:

Terraform - Remove AWS security_group_rule from a PostgreSQL DB after upload of dump has been completed

问题

以下是您要求的翻译内容:

我有一个Terraform脚本,在其中我在AWS中设置了一个PostgreSQL数据库。

我的想法是:

  • 使用一个安全组设置数据库,该安全组关闭了端口5432
  • 向安全组添加规则,以打开端口5432以供互联网访问
  • 从Linux机器上载数据库架构和一些初始数据
  • 稍后关闭端口5432 - 我想要将其更改为仅可从Lambda函数访问...

因此,我在一个脚本中有这个Terraform代码,我使用"terraform apply"执行它:

// 使用一个安全组设置数据库,该安全组关闭了端口5432 1/2
resource "aws_security_group" "PostgreSQL-SecGrp" {
  vpc_id      = "${data.aws_vpc.default.id}"
  name        = "PostgreSQL-sec-group"
  description = "从外部锁定流量"
}

// 使用一个安全组设置数据库,该安全组关闭了端口5432 2/2
resource "aws_db_instance" "app_rds" {
  identifier             = "mypostgresqldb"
  db_name                = "PostgreSQLDB"
  instance_class         = "db.t2.micro"
  allocated_storage      = 5
  engine                 = "postgres"
  engine_version         = "12.7"
  skip_final_snapshot    = true
  publicly_accessible    = true
  vpc_security_group_ids = [aws_security_group.PostgreSQL-SecGrp.id]
  username               = "user"
  password               = "<secretPassword>"
}

// 向安全组添加规则,以打开端口5432供互联网访问
resource "aws_security_group_rule" "open_port5432" {
  security_group_id = aws_security_group.PostgreSQL-SecGrp.id
  
  type = "ingress"
  from_port   = 5432
  to_port     = 5432
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
  
}
    
// 从Linux机器上传数据库架构和一些初始数据(1/2)
terraform {
  required_version = ">= 1.1.6"
 required_providers {
   ssh = {
      source = "loafoe/ssh"
    }
  }
}

// 从Linux机器上传数据库架构和一些初始数据(2/2)
resource "ssh_resource" "init" {

  host         = "<linuxMachine>"
  user         = "..."
  password     = "..."
  
  commands = [
  <上传psql转储到postgresql的命令>
  ]
}

// 再次关闭端口5432
resource "aws_security_group_rule" "close_port5432" {
  security_group_id = aws_security_group.PostgreSQL-SecGrp.id 
  <????>
}

除了最后一点之外,一切都正常工作,最后一点的目的是再次从互联网中删除可访问性 - 因为它没有删除或更改安全组。我的假设是,也许我需要重新导入创建的安全组,然后以某种方式修改其资源,但在那里我也没有找到任何有用的信息。

是否有人有关于如何做到这一点的想法?或者,由于这看起来也有点像一个标准问题(设置数据库,注入一些初始数据,然后从互联网中锁定它),也许有人可以指向一个文档,描述了如何设置类似的东西?

英文:

I got a Terraform script in which I setup a PostgreSQL DB in AWS.

There my idea was to:

  • Setup the DB with a security group which got port 5432 closed
  • Add a rule to the security group which opens port 5432 to the internet
  • Upload the DB schema and some initial data from a linux machine
  • Close the port 5432 again - later I want to change this to be only reachable from a Lambda function...

So I got this Terraform code in one script which I execute with "terraform apply":

// Setup the DB with a security group which got port 5432 closed 1/2
resource &quot;aws_security_group&quot; &quot;PostgreSQL-SecGrp&quot; {
  vpc_id      = &quot;${data.aws_vpc.default.id}&quot;
  name        = &quot;PostgreSQL-sec-group&quot;
  description = &quot;Lock traffic from outside&quot;
}

// Setup the DB with a security group which got port 5432 closed 2/2
resource &quot;aws_db_instance&quot; &quot;app_rds&quot; {
  identifier             = &quot;mypostgresqldb&quot;
  db_name                = &quot;PostgreSQLDB&quot;
  instance_class         = &quot;db.t2.micro&quot;
  allocated_storage      = 5
  engine                 = &quot;postgres&quot;
  engine_version         = &quot;12.7&quot;
  skip_final_snapshot    = true
  publicly_accessible    = true
  vpc_security_group_ids = [aws_security_group.PostgreSQL-SecGrp.id]
  username               = &quot;user&quot;
  password               = &quot;&lt;secretPassword&gt;&quot;
}

// Add a rule to the security group which opens port 5432 to the internet
resource &quot;aws_security_group_rule&quot; &quot;open_port5432&quot; {
  security_group_id = aws_security_group.PostgreSQL-SecGrp.id
  
  type = &quot;ingress&quot;
  from_port   = 5432
  to_port     = 5432
  protocol    = &quot;tcp&quot;
  cidr_blocks = [&quot;0.0.0.0/0&quot;]
  
}
    
// Upload the DB schema and some initial data from a linux machine (1/2)
terraform {
  required_version = &quot;&gt;= 1.1.6&quot;
 required_providers {
   ssh = {
      source = &quot;loafoe/ssh&quot;
    }
  }
}

// Upload the DB schema and some initial data from a linux machine (2/2)
resource &quot;ssh_resource&quot; &quot;init&quot; {

  host         = &quot;&lt;linuxMachine&gt;&quot;
  user         = &quot;...&quot;
  password     = &quot;...&quot;
  
  commands = [
  &lt; command to upload a psql dump into postgresql &gt;
  ]
}

// Close the port 5432 again
resource &quot;aws_security_group_rule&quot; &quot;close_port5432&quot; {
  security_group_id = aws_security_group.PostgreSQL-SecGrp.id 
  &lt;????&gt;
}

Everything works apart from the last point which shall remove the acessibility from the internet again - because it did not remove/change the security group again. My supposition was that I have maybe to import the created security group again and then modify its resource anyhow, but also there I didn't find anything usefull.

Does anybody got an idea how to do this? Or, since this also looks a bit like a standard problem to me (setup a DB, inject some initial data and then locking it from the internet), maybe someone could point me to a documentation, in which it is described to setup something like this?

答案1

得分: 2

以下是翻译好的内容:

有一种方法可以做到这一点,那就是将一个变量传递给Terraform,并在Terraform模板中使用该变量的值来确定应该部署什么。例如,如果你有一个像这样定义的输入变量

variable "public_db" {
  type    = bool
  default = false

  description = "Expose the database to the public Internet"
}

然后在你的模板中可以这样写:

resource "aws_security_group_rule" "open_port5432" {
  # 如果public_db为true,我们希望有1个此规则的实例。
  # 否则,我们希望有0个此规则的实例。
  count = var.public_db ? 1 : 0

  security_group_id = aws_security_group.PostgreSQL-SecGrp.id
  
  type        = "ingress"
  from_port   = 5432
  to_port     = 5432
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

现在,当你运行 terraform apply -var="public_db=true" 时,Terraform将创建安全组规则(如果它尚不存在)。如果你运行 terraform apply -var="public_db=false" 或只是 terraform apply 时,安全组规则将被删除(如果存在)。

英文:

One way to do this is to pass a variable to Terraform and use the value of that variable in your Terraform templates to determine what should be deployed. For example if you have an input variable defined like this:

variable &quot;public_db&quot; {
  type    = bool
  default = false

  description = &quot;Expose the database to the public Internet&quot;
}

Then in your template you could have:

resource &quot;aws_security_group_rule&quot; &quot;open_port5432&quot; {
  # We want 1 instance of this rule if public_db is true. 
  # Otherwise we want 0 instances of this rule.
  count = var.public_db ? 1 : 0

  security_group_id = aws_security_group.PostgreSQL-SecGrp.id
  
  type        = &quot;ingress&quot;
  from_port   = 5432
  to_port     = 5432
  protocol    = &quot;tcp&quot;
  cidr_blocks = [&quot;0.0.0.0/0&quot;]
}

Now when you run terraform apply -var=&quot;public_db=true&quot; Terraform will create the security group rule, if it doesn't already exist. And if you run terraform apply -var=&quot;public_db=false&quot; or just terraform apply&quot; the security group rule will be deleted (if it exists).

答案2

得分: 1

只需删除初始的安全组规则 open_port5432,然后执行 terraform plan 和 apply。

您还可以使用计数作为功能标志来启用/禁用所需的安全组。

count = local.enable_external_access ? 1 : 0

注意:将实例暴露给 0.0.0.0/0 是一个不好的主意,如果可能的话,建议使用特定的外部 IP(/32)来引导数据库。或者使用 Lambda 来执行此操作,这样您只会将数据库暴露在私有网络中。

英文:

You just need to remove the initial security group rule open_port5432, and perform a terraform plan and apply.

You could also use count as a feature flag to enable/disable the needed security groups.

count = local.enable_external_access ? 1 : 0

NB: it's a bad idea to expose your instance to 0.0.0.0/0 I would like to suggest if possible to use the specific external IP using /32 which will bootstrap the DB. Or use a lambda to do so, this way you only expose your DB in the private network.

答案3

得分: 0

Ok, based on the feedback of Mark and v-rosa, I want to come up with a solution which seems to work.

At first the overall security group of my code snippet (see the top of this thread):

resource "aws_security_group" "PostgreSQL-SecGrp" {
  vpc_id      = "${data.aws_vpc.default.id}"
  name        = "PostgreSQL-sec-group"
  description = "Lock traffic from outside"
}

stays in the top-level main.tf file.

Then I use the hints from Mark and v-rosa and shift the security group rule into its own tf file, in its own folder:

resource "aws_security_group_rule" "everything_around_port_5432" {
  security_group_id = ...
  count = var.public_db ? 1 : 0
  type = "ingress"
  from_port   = 5432
  to_port     = 5432
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

Then back in the "top level" main.tf, I added two null_resources:

resource "null_resource" "create_rule_with_open_port" {
  provisioner "local-exec" {
    working_dir = "./postgres_db"
    command     = "terraform init"
    interpreter = ["cmd", "/C"]
  }
  provisioner "local-exec" {
    working_dir = "./postgres_db"
    command     = "terraform apply -auto-approve -var=public_db=true"
    interpreter = ["cmd", "/C"]
  }
}

/*
At this point, the database is running and the port is open.
Do the dump upload with:
*/

resource "ssh_resource" "init" {

  host         = "<linuxMachine>"
  user         = "..."
  password     = "..."
  
  commands = [
  <command to upload a psql dump into PostgreSQL>
  ]
}

# ... and then proceed with the removal of the port again.

resource "null_resource" "remove_rule_again" {
    provisioner "local-exec" {
    working_dir = "./postgres_db"
    command     = "terraform apply -auto-approve -var=public_db=false"
    interpreter = ["cmd", "/C"]
  }
  depends_on = [null_resource.create_rule_with_open_port, ssh_resource.init]
}

When I now run "terraform apply" on the top-level file, it calls this new tf file, which is in charge of the security_group_rule and sets the port - and removes it again.

Probably the script can be tuned to not always do the "terraform init" in the first place.

And a small side note: This new tf file also gets its own state file, and I was a bit wondering if this can get messed up when I call "terraform destroy" on the top-level script. However, when I call "terraform apply" on the top-level script, in the specific state file, one resource is added - and removed again. So this state is "empty" - that's my theory.

英文:

Ok, based on the feedback of Mark and v-rosa, I want to come up with a solution which seems to work.

At first the overall security group of my code snipped (see the top of this thread):

resource &quot;aws_security_group&quot; &quot;PostgreSQL-SecGrp&quot; {
  vpc_id      = &quot;${data.aws_vpc.default.id}&quot;
  name        = &quot;PostgreSQL-sec-group&quot;
  description = &quot;Lock traffic from outside&quot;
}

stays in the top level main.tf file.

Then I use the hints from Mark and v-rosa and shift the security group rule into an own tf file, in an own folder:

resource &quot;aws_security_group_rule&quot; &quot;everything_around_port_5432&quot; {
  security_group_id = ...
  count = var.public_db ? 1 : 0
  type = &quot;ingress&quot;
  from_port   = 5432
  to_port     = 5432
  protocol    = &quot;tcp&quot;
  cidr_blocks = [&quot;0.0.0.0/0&quot;]
  
}

Then back in the "top level" main.tf I added two null_ressources:

resource &quot;null_resource&quot; &quot;create_rule_with_open_port&quot; {
  provisioner &quot;local-exec&quot; {
    working_dir = &quot;./postgres_db&quot;
    command     = &quot;terraform init&quot;
    interpreter = [&quot;cmd&quot;, &quot;/C&quot;]
  }
  provisioner &quot;local-exec&quot; {
    working_dir = &quot;./postgres_db&quot;
    command     = &quot;terraform apply -auto-approve -var=public_db=true&quot;
    interpreter = [&quot;cmd&quot;, &quot;/C&quot;]
  }
}

/*
At this point the database is running and the port is open. 
Do the dump upload with:
*/

resource &quot;ssh_resource&quot; &quot;init&quot; {

  host         = &quot;&lt;linuxMachine&gt;&quot;
  user         = &quot;...&quot;
  password     = &quot;...&quot;
  
  commands = [
  &lt; command to upload a psql dump into postgresql &gt;
  ]
}

# ... and then proceed with the removal of the port again.

resource &quot;null_resource&quot; &quot;remove_rule_again&quot; {
    provisioner &quot;local-exec&quot; {
    working_dir = &quot;./postgres_db&quot;
    command     = &quot;terraform apply -auto-approve -var=public_db=false&quot;
    interpreter = [&quot;cmd&quot;, &quot;/C&quot;]
  }
  depends_on = [ null_resource.create_rule_with_open_port, ssh_resource.init ]
}

When I now run "terraform apply" on the top level file it calls this new tf file which is in charge for the security_group_rule and sets the port - and removes it again.

Probably the script can be tuned to e. g. not always do the "terraform init" in the first place.

And a small side note: This new tf file also gets an own state file and I was a bit wondering if this can get messed up when I call "terraform destroy" on the top level script. However when I call "terraform apply" on the top level script, in the specific state file is one resource added - and removed again. So this state is "empty" - that's my theory.

huangapple
  • 本文由 发表于 2023年5月21日 18:01:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76299306.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定