terraform是否基于外部数据有条件地创建资源?

terraform是否基于外部数据有条件地创建资源?,terraform,Terraform,作为设置的一部分,我创建TLS证书并将其存储在S3中。通过运行生成证书命令的外部数据源创建证书。然后,我使用这些输出来创建S3 bucket对象resources 这在我第一次运行terraformapply时非常有效。但是,如果我更改任何其他(非证书)变量、资源等并重新运行,它将重新运行external命令,该命令将生成一个新的密钥/证书对,将它们上载到S3,并中断所有已经工作的操作 有没有办法有条件地创建资源?如果证书不存在,我可以使用什么模式创建证书 我确实考虑过在本地存储生成的密钥/证书

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

这在我第一次运行
terraformapply
时非常有效。但是,如果我更改任何其他(非证书)变量、资源等并重新运行,它将重新运行
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}"
}

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

这种行为的原因是
外部
是一个数据源,因此Terraform希望它是只读的,没有副作用。它为每个计划重新运行数据源

为了通过外部脚本实现这一点,有必要使用资源供应器来运行脚本并将其上载到S3,因为目前没有
external
等效资源,这些资源允许有副作用,而供应器只是副作用(也就是说,它们无法生成可在配置中的其他位置使用的结果。)

不过,另一种方法是使用Terraform,它允许在Terraform本身内创建证书。在这种情况下,您似乎正在尝试创建新的CA证书和密钥,可以通过以下方式完成:

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}"
}
生成的私钥将包含在状态中,以便在将来的运行中使用,因此确保安全地存储状态非常重要。请注意,使用
外部
数据源时也是如此,因为数据源结果也存储在状态中。因此,从机密所在的角度来看,这种方法是等效的让我们储存起来


我在中写了更多关于使用Terraform进行TLS证书管理的详细信息。它的范围比您在这里的要求更广,但可能会引起一些兴趣。

谢谢Martin。在这种情况下,这正是我最终要做的。我记不起为什么我们没有从TLS provisioner开始,而是在编写本文档时就切换到了它不管怎样,我猜答案是,“不,你不能有一个有条件的外部数据源。”:-)我想我应该说“你不能(安全地)使用外部数据源来创建东西”;您可以根据数据源的结果做出决策,但让您感到困惑的是,您的“数据源”并不是Terraform认为的真正的数据源。在某种程度上,可能有一个“外部”资源可以做你想做的事情,但这会有点复杂,到目前为止,还没有感觉到有足够强烈的需求来超越这一复杂性。“你可以根据数据源的结果来做决定……并不是terraform认为的真正的数据源。”不管怎样,它必须给出一致的结果才能重复,不是吗?对。。。这样说有点重复,但是您的数据源应该返回一个一致的值,直到需要返回一个新值为止。提供特定用例所需的一致性是数据源本身的责任,在
外部
的情况下,是数据源运行的脚本的责任。如果您的脚本本身能够以某种方式记住在以前的运行中返回的内容,那么这也会起作用。