【问题标题】:Terraform RDS database credentialsTerraform RDS 数据库凭据
【发布时间】:2021-04-12 16:20:15
【问题描述】:

我正在尝试使用 AWS Secrets Manager 来声明 RDS 管理员凭据。

  1. 在变量 RdsAdminCred 中的 rds.tf 中将凭据声明为键/值对
  2. 在同一个 tf 文件中也声明了机密
variable "RdsAminCred" {
    default = {
        username = "dbadmin"
        password = "dbadmin#02avia"
    }
    type = map(string)
}

resource "aws_secretsmanager_secret" "RdsAminCred" {
  name = "RdsAminCred"
}
resource "aws_secretsmanager_secret_version" "RdsAminCred" {
  secret_id     = aws_secretsmanager_secret.RdsAminCred.id
  secret_string = jsonencode(var.RdsAminCred)
}
  1. 我不确定如何使用下面声明中的秘密字符串来替换用户名和密码的硬编码值。
resource "aws_db_instance" "default" {
  identifier            = "testdb"
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t2.medium"
  name                 = "mydb"
 
  username             = "dbadmin"
  password             = "dbadmin#01avia"

任何帮助表示赞赏..

【问题讨论】:

  • 你能说明你想要达到什么目标吗?如果你在RdsAminCred 中硬编码你的密码,那么secret_manager 没有多大意义,因为密码最终会出现在你的源代码中,更糟糕的是,在github 或gitlab 上的公共仓库中。
  • 这将是下一步,我也不知道如何完成。在上面的代码中,我首先尝试使用 Secrets Manager。最终,密码不应在 tf.所以我认为他的最终方法是使用 env 变量(在 tf 之外)或其他更好的方法并使用 AWS Secrets manager

标签: amazon-web-services terraform secret-manager


【解决方案1】:

在您的 Terraform 代码中,您可以使用 aws_secretsmanager_secret_version 数据源来读取此密钥:

data "aws_secretsmanager_secret_version" "creds" {
  # write your secret name here
  secret_id = "your_secret"
}

使用 jsondecode 从 JSON 中解析秘密:

locals {
  your_secret = jsondecode(
    data.aws_secretsmanager_secret_version.creds.secret_string
  )
}

现在将密钥传递给 RDS:

resource "aws_db_instance" "example" {
  engine               = "engine"
  engine_version       = "version"
  instance_class       = "instance"
  name                 = "example"
  # Set the secrets from AWS Secrets Manager
  username = local.your_secret.username
  password = local.your_secret.password
}

【讨论】:

  • 我尝试包含上面的代码(声明 locals )并重新运行,但出现错误 A data source "aws_secretsmanager_secret_manager" "RdsAdminCred" has not been declared in the root module
  • 我认为使用 terraform 创建您的秘密不是一个好主意,因为它包含一个敏感数据,它不应该包含在您的代码中,或者先使用秘密管理器创建秘密,然后参考这个来自 terraform 的秘密。
  • 您建议使用 AWS 控制台中的 Secrets Manager 来创建密钥,对吗?
  • 是的,正确,然后使用 terraform 阅读此机密
  • @AsriBadlah,即使您引用手动创建的秘密,您的秘密也会以纯文本形式存储在 terraform 状态文件中。这有点烦人,但我看不到任何设置此密码的方法,并且在状态文件中没有它的值。
【解决方案2】:

我建议改用random_password 资源。然后您可以在集群配置和机密管理器中引用它。

例子:

resource "random_password" "master_password" {
  length  = 16
  special = false
}

resource "aws_rds_cluster" "default" {
  cluster_identifier = "my-cluster"
  
  master_username = "admin"
  master_password = random_password.default_master_password.result

  # other configurations
  # .
  # .
  # .
}

resource "aws_secretsmanager_secret" "rds_credentials" {
  name = "credentials"
}

resource "aws_secretsmanager_secret_version" "rds_credentials" {
  secret_id     = aws_secretsmanager_secret.rds_credentials.id
  secret_string = <<EOF
{
  "username": "${aws_rds_cluster.default.master_username}",
  "password": "${random_password.master_password.result}",
  "engine": "mysql",
  "host": "${aws_rds_cluster.default.endpoint}",
  "port": ${aws_rds_cluster.default.port},
  "dbClusterIdentifier": "${aws_rds_cluster.default.cluster_identifier}"
}
EOF
}

【讨论】:

  • 这是最好的答案,因为secret_string 中的关联数组正是通过让 SSM 生成“RDS 凭据”而生成的输出(尽管它确实将其存储为“键值” " secret 而不是控制台本身的字符串)。
【解决方案3】:

我会有一个 TF 配置来设置您的密钥并将其存储在 AWS Secrets Manager 中,就像这样。

resource "random_password" "master"{
  length           = 16
  special          = true
  override_special = "_!%^"
}

resource "aws_secretsmanager_secret" "password" {
  name = "test-db-password"
}

resource "aws_secretsmanager_secret_version" "password" {
  secret_id = aws_secretsmanager_secret.password.id
  secret_string = random_password.master.result
}

然后在您的数据库的单独 TF 配置中,您可以使用来自 AWS Secrets Manager 的密钥。

data "aws_secretsmanager_secret" "password" {
  name = "test-db-password"

}

data "aws_secretsmanager_secret_version" "password" {
  secret_id = data.aws_secretsmanager_secret.password
}

resource "aws_db_instance" "default" {
  identifier            = "testdb"
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t2.medium"
  name                 = "mydb"
 
  username             = "dbadmin"
  password             = data.aws_secretsmanager_secret_version.password

在上面的 cmets 中,Asri Badlah 建议在控制台中手动输入密码。我想你可以做到这一点。然而,这种方法确实开始偏离 IaC 的基本原则 - 将所有内容置于源代码控制中。当然,您不想将密码、私钥等检查到源代码控制中。但是在这里,你可以看到我们没有这样做。我们用一个配置填充一个秘密,并用另一个配置来使用它。这样可以确保代码可以签入源代码管理,但不能签入密码。

在状态方面,密码确实会在TF状态下存储和破译。但是,如果您使用适当的状态管理,这应该不是问题。理想情况下,您会希望使用远程状态、加密且访问受限。

最后一点,我不会像 Evan Closson 建议的那样只使用 random_password。这种方法意味着您的数据库密码 100% 由 Terraform 管理。通过使用 Secrets Manager,您的密码由服务管理,这意味着您可以执行其他操作,例如轮换密码(未显示)和检索密码,而无需依赖 Terraform(例如 terraform 输出或破解打开状态文件) .

【讨论】:

  • 这应该是公认的答案。
  • 在向数据库配置提供值时,为什么我们需要使用数据资源来指定它?改用aws_secretsmanager.secret_version.password.secret_string(即使用非数据资源中的值)是否不能正常工作?
【解决方案4】:
variable "RdsAdminCred" {
  default = {
    username = "dbadmin"
    password = "dbadmin#02avia"
  }
  type = map(string)
}

resource "aws_secretsmanager_secret" "RdsAdminCred" {
  name = "RdsAdminCred"
}
resource "aws_secretsmanager_secret_version" "RdsAdminCred" {
  secret_id     = aws_secretsmanager_secret.RdsAdminCred.id
  secret_string = jsonencode(var.RdsAdminCred)
}

创建密钥后,您需要从那里获取数据

data "aws_secretsmanager_secret" "env_secrets" {
  name = "RdsAdminCred"
  depends_on = [
    aws_secretsmanager_secret.RdsAdminCred
  ]
}
data "aws_secretsmanager_secret_version" "current_secrets" {
  secret_id = data.aws_secretsmanager_secret.env_secrets.id
}
resource "aws_db_instance" "default" {
  identifier        = "testdb"
  allocated_storage = 20
  storage_type      = "gp2"
  engine            = "mysql"
  engine_version    = "5.7"
  instance_class    = "db.t2.medium"
  name              = "mydb"

  username = jsondecode(data.aws_secretsmanager_secret_version.current_secrets.secret_string)["username"]
  password = jsondecode(data.aws_secretsmanager_secret_version.current_secrets.secret_string)["password"]
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-13
    • 2021-05-20
    • 1970-01-01
    • 2021-10-24
    • 2016-09-25
    • 1970-01-01
    • 2014-10-17
    • 2012-12-15
    相关资源
    最近更新 更多