Terraform: 1Password Data Source Implicit Provider Inference Doesn't Work

Created on 10 Nov 2020  ·  6Comments  ·  Source: hashicorp/terraform

Terraform Version

$ terraform version
Terraform v0.13.5
+ provider registry.terraform.io/hashicorp/aws v3.12.0
+ provider registry.terraform.io/milosbackonja/1password v1.1.0

Terraform Configuration Files

https://github.com/Tensho/terraform-issue-1password-provider

Debug Output

$ /script.sh
...
Error: Invalid resource type

  on main.tf line 25, in output "check":
  25:   value = data.onepassword_item_login.abc.password

A data resource type "onepassword_item_login" is not supported by provider
"registry.terraform.io/hashicorp/1password".

Expected Behavior

Terrraform should infer the correct provider from the data source prefix name implicitly.

Actual Behavior

Terraform raises Error: Invalid resource type error.

Steps to Reproduce

  1. Read and satisfy prerequisites in the README file.
  2. Run:

    $ ./script.sh
    

Additional Context

As you may note data source reference requires hashicorp/onepassword instead of milosbackonja/1password one. When I explicitly specify provider attribute on data source everything works fine.

bug explained

Most helpful comment

I'm able to confirm this bug with 0.13.5 and 0.14 using the reproduction in the issue, so thanks again for that information. My analysis of the bug is below.

When loading the configuration with a resource which has no explicit provider argument, we determine which provider should be bound to the resource using the implied provider. This is derived from the resource type and the set of local provider names defined in required_providers:

https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/configs/module.go#L324-L327
https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/configs/module.go#L526-L534

In this case, this works: the onepassword_item_login data source is bound to the milosbackonja/1password provider, because you've specified the local provider name as onepassword.

Later, we statically validate resources against provider schemas. To look up the schema we do this:

https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/terraform/evaluate_valid.go#L215-L216
https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/configs/resource.go#L67-L72

This incorrectly returns the provider _type_ as a local name, which is normally correct. But not in this instance! Instead, it should be returning onepassword.

My first attempt to fix this would be to change the implementation of ProviderConfigAddr to defer to r.Addr().ImpliedProvider() for the case where there's no ProviderConfigRef. I'm not sure what knock-on effects that would have, but it would seem to make the method do what its documentation says it should.

All 6 comments

I believe that the issue here is that the onepassword provider has been published by someone incorrectly to the registry as 1password. Terraform then is unable to automatically map resources or data sources with the onepassword_ prefix to this provider, even if given that local name.

Here's a similar diagnosis in the upstream provider repository. The only workarounds I can suggest are locally installing the provider, publishing the provider to the registry yourself under the correct onepassword name, or asking the upstream maintainer to do the same.

This doesn't appear to be a Terraform core bug, so I'm marking it "working as designed" and closing for now. Hopefully my explanation makes sense! Please let me know if anything is unclear.

@alisdair Thank you for the quick reply. But I wonder explicit version block doesn't mitigate this. I'd expect this mapping should make a deal:

terraform {
  required_providers {
    onepassword = {
      source  = "milosbackonja/1password"
      version = "1.1.0"
    }
  }
}

It's odd to me Terraform relies on source attribute value (1password) over the key in required_providers (onepassword). Is it documented somewhere?

That's a good question! The intended behaviour is documented here:

Users of a provider can choose any local name for it. However, nearly every provider has a _preferred local name_, which it uses as a prefix for all of its resource types. (For example, resources from hashicorp/aws all begin with aws, like aws_instance or aws_security_group.)

Whenever possible, you should use a provider's preferred local name. This makes your configurations easier to understand, and lets you omit the provider meta-argument from most of your resources. (If a resource doesn't specify which provider configuration to use, Terraform interprets the first word of the resource type as a local provider name.)

The last sentence contradicts my understanding of what was happening here, and so I'm going to reopen this issue and investigate further. Thanks!

I'm able to confirm this bug with 0.13.5 and 0.14 using the reproduction in the issue, so thanks again for that information. My analysis of the bug is below.

When loading the configuration with a resource which has no explicit provider argument, we determine which provider should be bound to the resource using the implied provider. This is derived from the resource type and the set of local provider names defined in required_providers:

https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/configs/module.go#L324-L327
https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/configs/module.go#L526-L534

In this case, this works: the onepassword_item_login data source is bound to the milosbackonja/1password provider, because you've specified the local provider name as onepassword.

Later, we statically validate resources against provider schemas. To look up the schema we do this:

https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/terraform/evaluate_valid.go#L215-L216
https://github.com/hashicorp/terraform/blob/7c98be92c2423a3d2f777d0fac5359e7b11364f3/configs/resource.go#L67-L72

This incorrectly returns the provider _type_ as a local name, which is normally correct. But not in this instance! Instead, it should be returning onepassword.

My first attempt to fix this would be to change the implementation of ProviderConfigAddr to defer to r.Addr().ImpliedProvider() for the case where there's no ProviderConfigRef. I'm not sure what knock-on effects that would have, but it would seem to make the method do what its documentation says it should.

Got it. I'm glad the current behavior doesn't seem odd to only me, TBH 🙂 Thanks again for the code walkthrough 🙇

I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pawelsawicz picture pawelsawicz  ·  3Comments

rkulagowski picture rkulagowski  ·  3Comments

zeninfinity picture zeninfinity  ·  3Comments

shanmugakarna picture shanmugakarna  ·  3Comments

rjinski picture rjinski  ·  3Comments