(远程)状态文件中的Terraform和明文密码

(远程)状态文件中的Terraform和明文密码,terraform,hashicorp-vault,Terraform,Hashicorp Vault,关于这个问题,Terraform repo上有很多Git问题,有很多有趣的评论,但到目前为止,我仍然看不到这个问题的解决方案 Terraform在tfstate文件中存储纯文本值,包括密码 大多数用户都需要远程存储状态文件,这样团队就可以在同一个基础设施上同时工作,而大多数用户将状态文件存储在S3中 那么如何隐藏密码呢 这里有人使用Terraform进行生产吗?你的密码是纯文本的吗? 您是否有特殊的工作流来删除或隐藏它们?然后运行terraformapply时会发生什么 我考虑过以下几种选择:

关于这个问题,Terraform repo上有很多Git问题,有很多有趣的评论,但到目前为止,我仍然看不到这个问题的解决方案

Terraform在tfstate文件中存储纯文本值,包括密码

大多数用户都需要远程存储状态文件,这样团队就可以在同一个基础设施上同时工作,而大多数用户将状态文件存储在S3中

那么如何隐藏密码呢

这里有人使用Terraform进行生产吗?你的密码是纯文本的吗? 您是否有特殊的工作流来删除或隐藏它们?然后运行
terraformapply
时会发生什么

我考虑过以下几种选择:

  • 把它们放在领事馆-我不用领事馆
  • 从状态文件中删除它们-这需要每次执行另一个进程,我不知道Terraform将如何使用空/不可读/不工作的密码处理资源
  • 存储一个随后更改的默认密码(以便Terraform在tfstate文件中有一个不工作的密码)-同上
  • 使用Vault资源-听起来这还不是一个完整的工作流
  • 使用Git repo crypt将它们存储在Git中-Git也不是一个选项
  • 全局加密S3存储桶-这不会阻止人们看到纯文本密码,如果他们作为“管理者”级别访问AWS,但这似乎是迄今为止最好的选择
在我看来,这是我想看到的:

  • 状态文件不包括密码
  • 状态文件是加密的
  • 状态文件中的密码是指向其他资源的“指针”,如“vault:后端类型:/path/to/password”
  • 每次Terraform运行都将从指定的提供程序收集所需的密码
这只是一个愿望


但回到问题上来——如何在生产中使用Terraform

整个远程州的事情应该是为整个州的文件和机密公开的

在此之前,我们只需使用多个AWS帐户,并将进入该帐户的内容的状态写入该帐户的S3存储桶中。在我们的例子中,我们并不太关心最终会出现在那里的秘密,因为如果你有权读取存储桶,那么你通常会在该帐户中拥有相当数量的访问权限。此外,我们在状态文件中保存的唯一真正秘密是RDS数据库密码,我们将安全组级别的访问限制为仅对构建所有内容的应用程序实例和Jenkins实例的访问,因此无论如何,人们的工作站上都无法从命令行直接访问

我还建议在S3存储桶上添加rest加密(因为它基本上是免费的)和版本控制,以便在必要时检索旧的状态文件

更进一步说,如果您担心有人对包含状态的S3存储桶具有读访问权限,您可以添加一个存储桶策略,该策略明确拒绝除某些白名单角色/用户之外的任何人的访问,这些角色/用户将在任何IAM访问之外被考虑。从一个示例扩展该示例,我们可能有一个类似以下内容的bucket策略:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyTFStateFileBucket",
        "arn:aws:s3:::MyTFStateFileBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*",
            "AIDAEXAMPLEID"
          ]
        }
      }
    }
  ]
}
其中,
AROAEXAMPLEID
表示示例角色ID,
AIDAEXAMPLEID
表示示例用户ID。可以通过运行以下命令找到:

aws iam get-role -–role-name ROLE-NAME

分别


如果您真的想完全加密状态文件,那么您需要编写一个包装器脚本,使Terraform在本地(而不是远程)与状态文件交互,然后让包装器脚本管理远程状态,在将其上传到S3之前对其进行加密,并在提取时对其进行解密。

我想知道如何处理最佳实践,但让我分享一下我的案例,尽管这对AWS来说是一种有限的方式。基本上,我不使用Terraform管理凭据

  • 为RDS设置初始密码,忽略与lifecycle hook的差异,稍后更改。忽略差异的方法如下:

     resource "aws_db_instance" "db_instance" {
       ...
       password = "hoge"
    
       lifecycle {
         ignore_changes = ["password"]
       }
     }
    
  • IAM用户由Terraform管理,但包括密码在内的IAM登录配置文件不受管理。我认为IAM密码应该由个人管理,而不是由管理员管理

  • 应用程序使用的API密钥也不由Terraform管理。它们使用AWS KMS(密钥管理服务)进行加密,加密数据保存在应用程序的git存储库或S3存储桶中。KMS加密的优点是解密权限可以由IAM角色控制。不需要管理解密密钥

  • 虽然我还没有尝试过,但最近我注意到,
    aws ssm put参数--key id
    可以用作支持KMS加密的简单键值存储,因此这可能也是一个不错的选择


我希望这能对您有所帮助。

Re:
aws ssm
,我正在从ssm中提取一个包装器脚本,在docker中运行应用程序,它非常出色。我一直讨厌在版本控制中加密机密。
 resource "aws_db_instance" "db_instance" {
   ...
   password = "hoge"

   lifecycle {
     ignore_changes = ["password"]
   }
 }