关于这个问题,Terraform repo上有很多Git问题,有很多有趣的评论,但到目前为止,我仍然没有看到这个问题的解决方案。
Terraform将包括密码在内的纯文本值存储在tfstate文件中。
大多数用户都需要远程存储它们,这样团队就可以在同一基础设施上同时工作,其中大多数用户将状态文件存储在S3中。
那么你如何隐藏你的密码呢?
这里有人使用Terraform进行生产吗?你的密码是纯文本的吗?您有特殊的工作流程来删除或隐藏它们吗?那么,当您运行terraform apply
时会发生什么?
我考虑了以下选项:
- 将它们存储在Consul中-我不使用Consul
- 从状态文件中删除它们-这需要每次执行另一个进程,我不知道Terraform将如何处理空/不可读/不工作的密码的资源
- 存储一个默认密码,然后更改该密码(因此Terraform将在tfstate文件中有一个不起作用的密码)-与上面相同
- 使用Vault资源-听起来这还不是一个完整的工作流
- 使用Git-reo-crypt将它们存储在Git中-Git也不是一个选项
- 全局加密S3存储桶-如果人们以"管理员"级别访问AWS,这不会阻止他们看到纯文本密码,但这似乎是迄今为止最好的选择
从我的角度来看,这就是我希望看到的:
- 状态文件不包括密码
- 状态文件已加密
- 状态文件中的密码是指向其他资源的"指针",如"vault:后端类型:/path/to/password">
- 每个Terraform运行都会从指定的提供程序收集所需的密码
这只是一个愿望。
但回到问题上来——你如何在生产中使用Terraform?
我想知道如何处理最佳实践,但让我分享一下我的案例,尽管这是AWS的一种有限方式。基本上,我不使用Terraform管理凭据。
-
为RDS设置初始密码,忽略与生命周期挂钩的差异,稍后更改。忽略差异的方法如下:
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-parameter --key-id
可以用作支持KMS加密的简单键值存储,所以这可能也是一个很好的选择。
我希望这对你有所帮助。
整个远程状态的内容正在被重新设计为0.9,这将为锁定远程状态和可能加密整个状态文件/只是机密打开大门。
在此之前,我们只需使用多个AWS帐户,并将进入该帐户的内容的状态写入该帐户中的S3存储桶。在我们的情况下,我们真的不太关心最终出现在那里的秘密,因为如果你有权读取bucket,那么你通常在该账户中有相当多的访问权限。此外,我们在状态文件中保存的唯一真正秘密是RDS数据库密码,我们在安全组级别上仅将访问权限限制为构建所有内容的应用程序实例和Jenkins实例,因此无论如何都无法从人们工作站上的命令行直接访问。
我还建议在S3存储桶上添加静态加密(因为它基本上是免费的)和版本控制,以便在必要时检索旧的状态文件。
更进一步地说,如果你担心有人对包含状态的S3存储桶进行读取访问,你可以添加一个存储桶策略,明确拒绝某些白名单角色/用户以外的任何人的访问,然后在任何IAM访问之外都会考虑这些访问。从相关的AWS博客文章中扩展这个例子,我们可能有一个类似于以下内容的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
和
aws iam get-user -–user-name USER-NAME
分别。
如果你真的想完全加密状态文件,那么你需要编写一个包装脚本,让Terraform在本地(而不是远程)与状态文件交互,然后让你的包装脚本管理远程状态,在上传到S3之前对其进行加密,并在提取时对其进行解密。