Terraform-provider-aws: Data sources with non-deterministic IDs show perpetual diff with Terraform 0.13 (R015, R016, R017 linters)

Created on 11 Aug 2020  路  22Comments  路  Source: hashicorp/terraform-provider-aws

Community Note

  • Please vote on this issue by adding a 馃憤 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform CLI and Terraform AWS Provider Version

Terraform v0.13.0
AWS Provider v3.1.0

Affected Resource(s)

$ grep 'd.SetId' aws/data_source*.go | grep Now
aws/data_source_aws_acm_certificate.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_autoscaling_group.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_autoscaling_groups.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_availability_zones.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_caller_identity.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_ebs_default_kms_key.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_ebs_encryption_by_default.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_ec2_coip_pools.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_ec2_local_gateway_route_tables.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_ec2_local_gateways.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_ecr_authorization_token.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_ecr_image.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_efs_access_points.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_eks_cluster_auth.go:    d.SetId(time.Now().UTC().String())
aws/data_source_aws_glue_script.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_iam_account_alias.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_inspector_rules_packages.go:    d.SetId(time.Now().UTC().String())
aws/data_source_aws_kms_alias.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_kms_ciphertext.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_kms_secrets.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_partition.go:   d.SetId(time.Now().UTC().String())
aws/data_source_aws_regions.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_route53_resolver_rules.go:  d.SetId(time.Now().UTC().String())
aws/data_source_aws_sns.go: d.SetId(time.Now().UTC().String())
aws/data_source_aws_vpcs.go:    d.SetId(time.Now().UTC().String())
$ grep 'd.SetId' aws/data_source*.go | grep Unique
aws/data_source_aws_db_event_categories.go: d.SetId(resource.UniqueId())
aws/data_source_aws_ebs_volumes.go: d.SetId(resource.UniqueId())
aws/data_source_aws_ec2_instance_type_offering.go:  d.SetId(resource.UniqueId())
aws/data_source_aws_ec2_instance_type_offerings.go: d.SetId(resource.UniqueId())
aws/data_source_aws_ec2_local_gateway_virtual_interface_groups.go:  d.SetId(resource.UniqueId())
aws/data_source_aws_ec2_spot_price.go:  d.SetId(resource.UniqueId())
aws/data_source_aws_instances.go:   d.SetId(resource.UniqueId())
aws/data_source_aws_network_acls.go:    d.SetId(resource.UniqueId())
aws/data_source_aws_network_interfaces.go:  d.SetId(resource.UniqueId())
aws/data_source_aws_organizations_organizational_units.go:  d.SetId(resource.UniqueId())
aws/data_source_aws_outposts_outposts.go:   d.SetId(resource.UniqueId())
aws/data_source_aws_outposts_sites.go:  d.SetId(resource.UniqueId())
aws/data_source_aws_route_tables.go:    d.SetId(resource.UniqueId())
aws/data_source_aws_s3_bucket_objects.go:   d.SetId(resource.UniqueId())
aws/data_source_aws_security_groups.go: d.SetId(resource.UniqueId())

Actual Behavior

Data sources whose ID is set to a non-deterministic value (e.g. the current timestamp or a unique ID) that changes every time a refresh (the data source's Read method) runs show a perpetual diff starting with Terraform 0.13.0.

For example

provider "aws" {
  region = "us-west-2"
}

data "aws_availability_zones" "a" {}
Terraform 0.12
$ terraform apply
data.aws_availability_zones.a: Refreshing state...

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.aws_availability_zones.a: Refreshing state...

------------------------------------------------------------------------

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
Terraform 0.13
$ terraform apply
data.aws_availability_zones.a: Refreshing state...

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 <= read (data resources)

Terraform will perform the following actions:

  # data.aws_availability_zones.a will be read during apply
  # (config refers to values not yet known)
 <= data "aws_availability_zones" "a"  {
        group_names = [
            "us-west-2",
            "us-west-2-lax-1",
        ]
      ~ id          = "2020-08-11 20:23:08.230813894 +0000 UTC" -> "2020-08-11 20:23:09.61125009 +0000 UTC"
        names       = [
            "us-west-2-lax-1a",
            "us-west-2a",
            "us-west-2b",
            "us-west-2c",
            "us-west-2d",
        ]
        zone_ids    = [
            "usw2-lax1-az1",
            "usw2-az1",
            "usw2-az2",
            "usw2-az3",
            "usw2-az4",
        ]
    }

Plan: 0 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

data.aws_availability_zones.a: Reading... [id=2020-08-11 20:23:08.230813894 +0000 UTC]
data.aws_availability_zones.a: Read complete after 0s [id=2020-08-11 20:23:09.61125009 +0000 UTC]

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.aws_availability_zones.a: Refreshing state... [id=2020-08-11 20:23:09.61125009 +0000 UTC]

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 <= read (data resources)

Terraform will perform the following actions:

  # data.aws_availability_zones.a will be read during apply
  # (config refers to values not yet known)
 <= data "aws_availability_zones" "a"  {
        group_names = [
            "us-west-2",
            "us-west-2-lax-1",
        ]
      ~ id          = "2020-08-11 20:23:19.963587604 +0000 UTC" -> "2020-08-11 20:23:21.360002629 +0000 UTC"
        names       = [
            "us-west-2-lax-1a",
            "us-west-2a",
            "us-west-2b",
            "us-west-2c",
            "us-west-2d",
        ]
        zone_ids    = [
            "usw2-lax1-az1",
            "usw2-az1",
            "usw2-az2",
            "usw2-az3",
            "usw2-az4",
        ]
    }

Plan: 0 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

References

Related:

bug linter provider upstream-terraform

Most helpful comment

I still experience this issue with terraform 0.13.3 and aws provider 3.8.0

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 <= read (data resources)

Terraform will perform the following actions:

  # module.ingress_apiserver.data.aws_acm_certificate.private_ingress will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "private_ingress"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:34.614684996 +0000 UTC" -> "2020-09-25 16:31:58.10270239 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.data.aws_acm_certificate.private_ingress will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "private_ingress"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:40.318109288 +0000 UTC" -> "2020-09-25 16:31:58.333672281 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.data.aws_acm_certificate.cloud will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "cloud"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:38.512641469 +0000 UTC" -> "2020-09-25 16:31:58.337586459 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.module.traefik_public.data.aws_acm_certificate.cloud will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "cloud"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:36.56696734 +0000 UTC" -> "2020-09-25 16:31:58.350688577 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.module.traefik_waf.data.aws_acm_certificate.cloud will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "cloud"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:34.648220862 +0000 UTC" -> "2020-09-25 16:31:57.940237258 +0000 UTC"
        most_recent = false
        tags        = {}
    }

Plan: 0 to add, 0 to change, 0 to destroy.

All 22 comments

In our case, we use terraform plan as part of a CI Pipeline, and this means there are a lot of data blocks with will be read during apply messages in the terraform plan output.

This makes pull requests/reviews quite difficult as some of our Terraform repositories are quite large, and make use of a lot of data resources.

A few notes since this change was unexpected for Terraform Providers.

There may be some additional work the Terraform core team can do to prevent this unexpected plan output issue from occurring in later Terraform 0.13 releases, but it is unknown if/what that might entail at the moment, so unable to provide any estimates on timelines. For example: https://github.com/hashicorp/terraform/issues/25812

We just migrated this provider to the newly released version 2 of the Terraform Plugin SDK which should allow us to run the acceptance testing against Terraform 0.13.0 directly (currently running against 0.12.26). Bumping our testing to that version would potentially make this class of issue more visible. However, I just submitted a bunch of issues here and in the SDK to cover the 30 or so new consistent test failures caused by the SDK version 2 upgrade. Ideally we need to get through those before potentially adding more uncertainty about the causes for test failures since the SDK v2 framework may not fully be compatible with Terraform 0.13 yet.

New tfproviderlint/awsproviderlint checks are now available for this specific issue (not enabled in our CI yet, fresh off the press):

Longterm this is certainly something we will need to address more holistically as this behavior change will be the default in Terraform core, but we should come up with a game plan before jumping to code changes.

To clarify the issue here, since this is being referenced from many places, the apparent diffs from a non-deterministic ID is only the symptom, and not the underlying problem. While it may be better in the long run to have deterministic attributes when possible (remember that core attributes to special meaning to id, it is simply another attribute), unnecessarily changing an attribute is not technically incorrect.

The problems here are mostly stemming from 2 places; either the schema is incorrectly defined with data being written to a non-computed field; or the SDK is altering a zero value for a schema block. The former problem is usually a simple change in the resource definition, while the latter should be remedied with with a patch in core for 0.13.1.

Just adding in another data source affected is aws_kms_secrets. It's leaking a password encrypted with KMS to the console.

image

I'm running 0.13.2

I was experiencing the same issue, and found that upgrading my version of Terraform fixed my issue.

Using latest version of the AWS provider (3.7.0 at the time of comment) and version 0.13.1+ (tested 0.13.1, 0.13.2, 0.13.3), this does not seem to be an issue. I tested with the aws_availability_zones data source.

Just a note here, I did test with Terraform version 0.13.0 with AWS provider version 3.7.0, and the issue persisted when doing that.

can also confirm @ktmorgan 's account

@avvi00, IMO the KMS Secrets one is a huge issue.

@jurgenweber #15169 to fix the display of sensitive data from the aws_kms_secrets data source has been released in version 3.7.0 of the Terraform AWS provider.

@ewbankkit Then the fix did not entirely work, as we still have an issue. Now I just see the unencrypted payloads and we still have the problem as discussed in this thread. I have been aggressively following it to see a resolution.

$ tf version
Terraform v0.13.3
+ provider instaclustr/instaclustr/instaclustr v1.4.1
+ provider registry.terraform.io/hashicorp/aws v3.7.0
+ provider registry.terraform.io/hashicorp/helm v1.3.0
+ provider registry.terraform.io/hashicorp/kubernetes v1.13.2
+ provider registry.terraform.io/hashicorp/local v1.4.0
+ provider registry.terraform.io/hashicorp/null v2.1.2
+ provider registry.terraform.io/hashicorp/random v2.3.0
+ provider registry.terraform.io/hashicorp/template v2.1.2
+ provider registry.terraform.io/hashicorp/tfe v0.21.0
  # data.aws_kms_secrets.data will be read during apply
  # (config refers to values not yet known)
 <= data "aws_kms_secrets" "data"  {
      ~ id        = "2020-09-22 06:45:36.536118222 +0000 UTC" -> "2020-09-22 06:46:10.369496051 +0000 UTC"
        plaintext = (sensitive value)

        secret {
            context      = {
                "foo" = "bar"
            }
            grant_tokens = []
            name         = "dockercfg"
            payload      = "AQ

but I don't see a fix in 3.7.0 rls notes?

3.7.0 (September 17, 2020)
FEATURES

New Resource: aws_config_remediation_configuration (#13884)
ENHANCEMENTS

resource/aws_db_cluster_snapshot: Add plan-time validation for db_cluster_snapshot_identifier argument (#15132)
resource/aws_kinesis_firehose_delivery_stream: Add server_side_encryption key_arn and key_type arguments (support KMS Customer Managed Key encryption) (#11954)
BUG FIXES

resource/aws_acm_certificate: Prevent tagging is not permitted on re-import error (#15060)
resource/aws_cognito_identity_pool: Prevent ordering differences for openid_connect_provider_arns argument (#15178)

@jurgenweber I think CHANGELOG must have been corrected after the v3.7.0 tag.
Here's the link in the head CHANGELOG: https://github.com/terraform-providers/terraform-provider-aws/blob/master/CHANGELOG.md#370-september-17-2020.

ok, cool. So now it's just the original problem you reported. ID's showing constant change.

I still experience this issue with terraform 0.13.3 and aws provider 3.8.0

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 <= read (data resources)

Terraform will perform the following actions:

  # module.ingress_apiserver.data.aws_acm_certificate.private_ingress will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "private_ingress"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:34.614684996 +0000 UTC" -> "2020-09-25 16:31:58.10270239 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.data.aws_acm_certificate.private_ingress will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "private_ingress"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:40.318109288 +0000 UTC" -> "2020-09-25 16:31:58.333672281 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.data.aws_acm_certificate.cloud will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "cloud"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:38.512641469 +0000 UTC" -> "2020-09-25 16:31:58.337586459 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.module.traefik_public.data.aws_acm_certificate.cloud will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "cloud"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:36.56696734 +0000 UTC" -> "2020-09-25 16:31:58.350688577 +0000 UTC"
        most_recent = false
        tags        = {}
    }

  # module.ingress_traefik.module.traefik_waf.data.aws_acm_certificate.cloud will be read during apply
  # (config refers to values not yet known)
 <= data "aws_acm_certificate" "cloud"  {
        arn         = ""
        domain      = ""
      ~ id          = "2020-09-25 16:30:34.648220862 +0000 UTC" -> "2020-09-25 16:31:57.940237258 +0000 UTC"
        most_recent = false
        tags        = {}
    }

Plan: 0 to add, 0 to change, 0 to destroy.

Same issue for me with latest Terraform 0.13.3, and 3.8.0 AWS provider.
This keeps happening with every plan/apply for all our TF repos.

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 <= read (data resources)

Terraform will perform the following actions:

  # data.aws_availability_zones.available will be read during apply
  # (config refers to values not yet known)
 <= data "aws_availability_zones" "available"  {
        group_names = [
            "us-east-1",
        ]
      ~ id          = "2020-09-29 16:55:42.830182 +0000 UTC" -> "2020-09-29 16:55:50.433126 +0000 UTC"
        names       = [
            "us-east-1a",
            "us-east-1b",
            "us-east-1c",
            "us-east-1d",
            "us-east-1e",
            "us-east-1f",
        ]
        state       = "available"
        zone_ids    = [
            "use1-az1",
            "use1-az2",
            "use1-az4",
            "use1-az6",
            "use1-az3",
            "use1-az5",
        ]
    }

Plan: 0 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Releasing state lock. This may take a few moments...

Any estimates for the fix?

AWS provider v3.10.0 fixed this as the changelog suggested; updating from v2.70.0, I had to manually modify my state to remove some blacklisted_* properties. Nothing too difficult, though!

it has not fixed everything. For example aws_kms_secrets still has the issue.

I'm seeing this with aws_route_tables on provider v3.10.0. This is in a brand-new Terraform project that has never used an older provider version.

Terraform will perform the following actions:

  # module.internal_peering.data.aws_route_tables.requestor[0] will be read during apply
  # (config refers to values not yet known)
 <= data "aws_route_tables" "requestor"  {
      ~ id     = "terraform-20201015222743753200000002" -> "terraform-20201015222746318200000001"
        ids    = [
            ...
        ]
        vpc_id = "vpc-XXX"
    }

Plan: 0 to add, 0 to change, 0 to destroy.

Is there something we can do about this if we're on 2.x version of the provider? We upgraded TF to 0.13 and all seemed fine until this hit. Upgrading the provider's major version was not something we expected the TF upgrade to depend on.

EDIT: It appears I was mistaken, it was another bug that looked like this and confused me. We eventually upgraded everything successfully though. Sorry for this.

not sure how to get my PR looked at, could use some +1's on it and we solve another resource with this problem!

Hi folks 馃憢 The remaining data sources with clear id attributes issues have been adjusted and will release with version 3.13.0 of the Terraform AWS Provider, likely later today. Please see the CHANGELOG for specifics on how they were updated.

If you are still having problems with perpetual differences in data sources after that release, please file a separate GitHub issue for each data source as each cause may be different. Thanks!

This has been released in version 3.13.0 of the Terraform AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template for triage. Thanks!

If you are still having problems with perpetual differences in data sources after that release

Just filed https://github.com/hashicorp/terraform-provider-aws/issues/16239. Seeing a similar issue with aws_iam_policy_document and aws_kms_key.

I am using 'aws_iam_policy_document' currently without issue, I had some problems here https://github.com/hashicorp/terraform/issues/26899 with v14 though.

Was this page helpful?
0 / 5 - 0 ratings