Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Terraform v1.10 #2178

Merged
merged 14 commits into from
Jan 11, 2025
Merged

Add support for Terraform v1.10 #2178

merged 14 commits into from
Jan 11, 2025

Conversation

wata727
Copy link
Member

@wata727 wata727 commented Dec 8, 2024

Fixes #2172

This PR adds support for the following features added in Terraform v1.10:

Besides the above, updating the Terraform fork to v1.10 also brings several other fixes.

Ephemeral Values

Terraform v1.10 introduced ephemeral values. This is treated internally as a cty value marked in the same way as sensitive. In order to send marked values ​​to the plugin, we need to extend the serialization process, so updating the SDK version. See terraform-linters/tflint-plugin-sdk#358 for details.

Plugins built with older SDKs cannot interpret the new ephemeral mark, so host server will return ErrSensitive instead of returning a marked cty value. Strictly speaking, ephemeral values ​​are not sensitive values, but they are similar in that they contain secrets, so we have adopted the policy of returning this error that older SDKs can interpret to prevent unintended disclosure. Developers of plugins built with SDK v0.16+ should be aware that if they directly evaluate expr to a cty value, ErrSensitive may be returned. This will not affect you if you use the recommended function callback approach.

An expression like ephemeral.* will always resolve to unknown, just like a resource reference, but it differs in that it is marked as ephemeral. This is mostly no different from any other unsupported named value, but it has implications when passed as an argument to a function, such as ephemeralasnull.

Values ​​marked as ephemeral are treated the same as Terraform in most cases, but there is a slight difference when they are passed as meta-arguments. Terraform does not allow passing an ephemeral value as count, but TFLint does not throw an error. It is possible to match the same behavior, but since it is not necessary to exactly match the behavior that causes an error in Terraform, nothing is done here. The behavior regarding meta-arguments is summarized in below:

Are the marked values ​​available in meta-arguments?

Terraform

sensitive ephemeral
count Yes No
for_each No No

TFLint

sensitive ephemeral
count Yes Yes
for_each No No

The terraform.applying symbol, which returns an ephemeral value, always resolves to false.

Marked dynamic blocks

Terraform v1.10 now accepts marked for_each values in dynamic blocks. See hashicorp/hcl#679 for details.

TFLint now also supports expanding dynamic blocks when sensitive or ephemeral values ​​are included in for_each, but note that there is a slight difference in whether the mark propagates to children. Terraform propagates marks to all attributes included in a dynamic block, but TFLint does not. Instead, expressions containing the marked value resolve to unknown.

resource "aws_s3_bucket" "main" {
  dynamic "lifecycle_rule" {
    for_each = sensitive(toset([true]))

    content {
      # Terraform: cty.StringVal("static").Marks(marks.Sensitive)
      # TFLint:    cty.StringVal("static")
      id = "static"

      # Terraform: cty.True.Marks(marks.Sensitive)
      # TFLint:    cty.UnknownVal(cty.Bool)
      enabled = lifecycle_rule.value
    }
  }
}

In most cases this behavior is not likely to be an issue, but be aware that there are situations where it is less safe than Terraform in that static values ​​may become unmarked.

This is because older SDKs cannot support the marked values. TFLint supports dynamic blocks in the tfhcl package, a fork of hcl/ext/dynblock. It evaluates a wrapped expr on the fly and binds the cty value to the expr to send over the wire protocol. At this time, TFLint does not bind marked values ​​because not all plugins can handle all marked values. As a result, marked values ​​are resolved to unknown (iterators are treated as resource references) and static values ​​can be evaluated as is, without the mark. This behavior will be improved if all marks are supported in available SDK versions.

Side note: hashicorp/hcl#679 explains that if you use a sensitive value in the dynamic block for_each, Terraform will reject the value. However, in fact it will accept the value.

variable "attempts" {
  sensitive = true
  default = [1]
}

data "http" "example" {
  url = "https://checkpoint-api.hashicorp.com/v1/check/terraform"

  request_headers = {
    Accept = "application/json"
  }

  dynamic "retry" {
    for_each = var.attempts
    content {
      attempts = retry.value
    }
  }
}
$ ./terraform19 plan

Planning failed. Terraform encountered an error while generating this plan.


│ Error: Invalid dynamic for_each value

│   on main.tf line 14, in data "http" "example":
│   14:     for_each = var.attempts

│ Cannot use a tuple value in for_each. An iterable collection is required.

$ ./terraform110 plan
data.http.example: Reading...
data.http.example: Read complete after 0s [id=https://checkpoint-api.hashicorp.com/v1/check/terraform]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

I'm not sure if this was intended, but TFLint follows this behavior.

@wata727 wata727 force-pushed the terraform_1_10 branch 5 times, most recently from 274d532 to ccab0bf Compare January 4, 2025 18:18
Follow up of hashicorp/terraform#35273
Follow up of hashicorp/terraform#35985

Terraform throws an error if you use ephemeral values for the count meta-argument,
but TFLint does not. This is because the reason for throwing an error is that
plan cannot have ephemeral values, which is not an issue in the context of static analysis.
In the future, we can throw an error if we need to match this behavior.
Follow up of hashicorp/terraform#35727
Follow up of hashicorp/terraform#35728

Ephemeral resource addresses are like resources in that they always
resolve to unknown values, but they differ in that they are marked
as ephemeral, which can have a subtle effect on the return value of
the ephemeralasnull function.
Follow up of hashicorp/hcl#679

Previously, for_each in dynamic blocks did not allow marked values
such as sensitive. However, hashicorp/hcl#679
now supports this by propagating the marks to expanded children.

The reason behind this is to add a new mark called "ephemeral",
so we'll pull the changes to support Terraform 1.10.

Note that tfhcl's dynamic block support has incomplete mark propagation
since marked values resolve to unknown values. This is because in the past
the marked values could not be sent over the wire protocol,
and may be fixed in the near future.
Because ephemeral values are likely to contain secrets,
return ErrSensitive for plugins that do not support it
to prevent unintended disclosure.
@wata727 wata727 marked this pull request as ready for review January 11, 2025 14:25
@wata727 wata727 merged commit b638d2f into master Jan 11, 2025
14 checks passed
@wata727 wata727 deleted the terraform_1_10 branch January 11, 2025 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Add support for Terraform v1.10
1 participant