首页 文章

terraform有条件地根据外部数据创建资源?

提问于
浏览
3

作为设置的一部分,我创建了TLS证书并将其存储在S3中 . 创建证书是通过 external 数据源完成的,该数据源运行命令以生成证书 . 然后我使用这些输出来创建S3存储桶对象 resource s .

这在第一次运行 terraform apply 时非常有效 . 但是,如果我更改任何其他(非证书)变量,资源等并重新运行,它将重新运行 external 命令,该命令生成新的密钥/证书对,将它们上载到S3,并中断已经运行的所有内容 .

有条件地创建资源有什么方法吗?我可以使用什么模式来创建仅在不存在的情况下创建证书?

我确实在本地存储生成的密钥/证书,但这是敏感的密钥材料;我不希望它存储在本地磁盘中(每个环境都有密钥) .

密钥/证书生成和存储:

data "external" "ca" {
  program = ["sh","-c","jq '.root|fromjson' | cfssl gencert -initca -"]
  #
  query = {root = "${ data.template_file.etcd-ca-csr.rendered }"}
  # the result will be saved in
  # data.external.etcd-ca.result.key
  # data.external.etcd-ca.result.csr
  # data.external.etcd-ca.result.cert
}

resource "aws_s3_bucket_object" "ca_cert" {
  bucket = "${aws_s3_bucket.my_bucket.id}"
  key = "ca.pem"
  content = "${data.external.ca.result.cert}"
}
resource "aws_s3_bucket_object" "ca_key" {
  bucket = "${aws_s3_bucket.my_bucket.id}"
  key = "ca-key.pem"
  content = "${data.external.ca.result.key}"
}

很高兴看到使用某种形式的条件或完全不同的生成模式 .

1 回答

  • 2

    这种行为的原因是 external 是一个数据源,因此Terraform期望它是只读的和无副作用的 . 它为每个计划重新运行数据源 .

    为了通过外部脚本执行此操作,有必要使用资源调配器来运行脚本并将其上载到S3,因为当前没有资源的 external 等效项,允许有副作用,以及供应商是副作用的(也就是说,它们不能产生在配置中的其他地方使用的结果 . )

    不过,另一种方法是使用Terraform的built-in TLS provider,它允许在Terraform中创建证书 . 在这种情况下,您似乎正在尝试创建新的CA证书和密钥,可以使用tls_self_signed_cert来完成,如下所示:

    resource "tls_private_key" "ca" {
      algorithm = "RSA"
      rsa_bits = 2048
    }
    
    resource "tls_self_signed_cert" "ca" {
      key_algorithm   = "RSA"
      private_key_pem = "${tls_private_key.ca.private_key_pem}"
    
      # ... subject and validity settings, as appropriate
    
      is_ca_certificate = true
    
      allowed_uses = ["cert_signing"]      
    }
    
    resource "aws_s3_bucket_object" "ca_cert" {
      bucket  = "${aws_s3_bucket.my_bucket.id}"
      key     = "ca.pem"
      content = "${resource.tls_self_signed_cert.ca.cert_pem}"
    }
    
    resource "aws_s3_bucket_object" "ca_key" {
      bucket  = "${aws_s3_bucket.my_bucket.id}"
      key     = "ca-key.pem"
      content = "${resource.tls_self_signed_cert.ca.private_key_pem}"
    }
    

    生成的私钥将包含在状态中以供将来运行使用,因此确保安全地存储状态非常重要 . 请注意,使用 external 数据源也是如此,因为数据源结果也存储在状态中 . 因此,从存储秘密的角度来看,这种方法是等同的 .

    我在an article on my website中写了更多关于使用Terraform进行TLS证书管理的细节 . 它的范围比您的要求更广泛,但可能有一些兴趣 .

相关问题