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

Providers can no longer be configured using a mix of environment variables and explicit configuration. #1074

Closed
6 tasks done
dylanCz opened this issue Nov 11, 2024 · 7 comments
Assignees
Labels
🪲 bug Something isn't working

Comments

@dylanCz
Copy link

dylanCz commented Nov 11, 2024

Checklist

  • I have looked into the README and have not found a suitable solution or answer.
  • I have looked into the documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have upgraded to the latest version of this provider and the issue still persists.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Description

Since 1.7.3 where this commit added a check on provider's configuration for required env vars, this prevents providers from using a mix of env vars and explicit configuration.
We set our auth0_domain as an environment variable, and then create multiple auth0 providers in our terraform code, supplying the client_id and client_secret as part of the provider block. In provider version 1.7.1, this works fine, where it used the client_id and secret supplied to the provider and resolved the domain from the environment variable.

Expectation

If a provider block does not have all the required configuration explicitly defined, it should check env vars for any missing configuration.

Reproduction

  1. Set the auth0 domain environment variable
    export AUTH0_DOMAIN=fake_domain

  2. Create a provider with version 1.7.3, without explicitly passing a domain

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    auth0 = {
      source  = "auth0/auth0"
      version = "1.7.3"
    }
  }
}

provider "auth0" {
  alias         = "additional-provider"
  client_id     = "fake_id"
  client_secret = "fake_secret"
}

resource "auth0_role" "my_role" {
  provider    = auth0.additional-provider
  name        = "Test Role"
  description = "Test Role"
}
  1. Run terraform plan, see that it errors (because the domain has not been set in the provider block)

    │ Error: Missing environment variables

    │ with provider["registry.terraform.io/auth0/auth0"].additional-provider,
    │ on auth0.tf line 12, in provider "auth0":
    │ 12: provider "auth0" {

    │ Either AUTH0_API_TOKEN or AUTH0_DOMAIN:AUTH0_CLIENT_ID:AUTH0_CLIENT_SECRET must be configured. Ref: https://registry.terraform.io/providers/auth0/auth0/latest/docs

  2. The issue can be resolved by adding an explicit domain to the provider

 provider "auth0" {
  alias         = "additional-provider"
  client_id     = "fake_id"
  client_secret = "fake_secret"
++  domain        = "fake_domain" ++
}

Auth0 Terraform Provider version

1.7.3

Terraform version

1.9.8

@dylanCz dylanCz added the 🪲 bug Something isn't working label Nov 11, 2024
@duedares-rvj
Copy link
Contributor

@dylanCz Hello!
Sorry to hear that you are facing this issue.

I tried reproducing this but it is working as expected on our end.
I have used the exact same code provider by you in the description.

Please find the logs below:

rajat.bajaj@M7V9YL36HJ manual_testing % echo $AUTH0_DOMAIN
fake_domain
rajat.bajaj@M7V9YL36HJ manual_testing % echo $AUTH0_CLIENT_ID

rajat.bajaj@M7V9YL36HJ manual_testing % echo $AUTH0_CLIENT_SECRET

rajat.bajaj@M7V9YL36HJ manual_testing % terraform init
Initializing the backend...
Initializing provider plugins...
- Finding auth0/auth0 versions matching "1.7.3"...
- Installing auth0/auth0 v1.7.3...
- Installed auth0/auth0 v1.7.3 (unauthenticated)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

╷
│ Warning: Incomplete lock file information for providers
│ 
│ Due to your customized provider installation methods, Terraform was forced to calculate lock file checksums locally for the following providers:
│   - auth0/auth0
│ 
│ The current .terraform.lock.hcl file only includes checksums for darwin_arm64, so Terraform running on another platform will fail to install these providers.
│ 
│ To calculate additional checksums for another platform, run:
│   terraform providers lock -platform=linux_amd64
│ (where linux_amd64 is the platform to generate)
╵
Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
rajat.bajaj@M7V9YL36HJ manual_testing % terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # auth0_role.my_role will be created
  + resource "auth0_role" "my_role" {
      + description = "Test Role"
      + id          = (known after apply)
      + name        = "Test Role"
    }

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

──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
rajat.bajaj@M7V9YL36HJ manual_testing % terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # auth0_role.my_role will be created
  + resource "auth0_role" "my_role" {
      + description = "Test Role"
      + id          = (known after apply)
      + name        = "Test Role"
    }

Plan: 1 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

auth0_role.my_role: Creating...
╷
│ Error: failed to send the request: Post "https://fake_domain/api/v2/roles": Post "https://fake_domain/oauth/token": dial tcp: lookup fake_domain: no such host
│ 
│   with auth0_role.my_role,
│   on main.tf line 17, in resource "auth0_role" "my_role":
│   17: resource "auth0_role" "my_role" {
│ 
╵

@duedares-rvj duedares-rvj self-assigned this Nov 22, 2024
@duedares-rvj
Copy link
Contributor

@dylanCz Did you get a chance to try this out?

@cdsre
Copy link

cdsre commented Nov 26, 2024

@duedares-rvj Thanks for your update. I have taken a look at this and its not related to a mix of variables but instead to do with the design pattern that we have been using for a long while. So to first explain the logic. We have an M2M token that is responsible for creating another environment scoped M2M tokens.

This first M2M token is set at the environment level and applied to the default auth0 provider. We then call off to an auth0 module we have written that does things like create a new org, new api resources etc and a new M2M token for that environment. We then use that Newley generated M2M token as the input to the aliased provider to then create additional environment specific resources.

In 1.7.1 this works as the alias provider is initialized and then the value filled in to the provider at the apply time. But in 1.7.3 this no longer works as the provider config is being evaluated at initialization time when the value has not been generated yet so is essentially nill.

export AUTH0_DOMAIN=example.com
export AUTH0_CLIENT_ID=foo_client
export AUTH0_CLIENT_SECRET=foo_secret

I have mocked up an example for you that you can use to reproduce the issue.

some_auth0_module.tf

terraform {
  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "3.6.2"
    }
  }
}

# Use this is fake way to generate a client ID at apply time. This would normally be "auth0_client" rsource
resource "random_string" "user_management_m2m_token" {
  length = 16
}

output "m2m_user_management_client_id" {
  value = random_string.user_management_m2m_token.result
}

root modules main.tf

terraform {
  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "3.6.2"
    }
    auth0 = {
      source  = "auth0/auth0"
      version = "1.7.3"
    }
  }
}

module "auth0_config" {
  source = "./some_auth_module"
}

# This is added in the root module to avoid using the output from the auth0_config module as the data lookup can be
# delayed due to dependencies, as otherwise this causes reads on the provider alias to fail during the object refresh when planning
data "auth0_client" "user_management_m2m" {
  client_id = module.auth0_config.m2m_user_management_client_id
}

provider "auth0" {
  alias         = "user_management_auth0"
  client_id     = module.auth0_config.m2m_user_management_client_id
  client_secret = data.auth0_client.user_management_m2m.client_secret
}

resource "auth0_user" "internal_admin_user" {
  provider = auth0.user_management_auth0
  connection_name = "foo"
  email           = "[email protected]"
  email_verified  = true
}

Now if i run this with version 1.7.1 then it plans fine, and when its applied, the value of the client_id will be set on the provider before the provider is invoked.

1.7.1 plan

$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # data.auth0_client.user_management_m2m will be read during apply
  # (config refers to values not yet known)
 <= data "auth0_client" "user_management_m2m" {
      + addons                                = (known after apply)
...
...  
      + token_endpoint_auth_method            = (known after apply)
      + web_origins                           = (known after apply)
    }

  # auth0_user.internal_admin_user will be created
  + resource "auth0_user" "internal_admin_user" {
      + connection_name = "foo"
      + email           = "[email protected]"
      + email_verified  = true
      + id              = (known after apply)
...
...
      + user_id         = (known after apply)
    }

  # module.auth0_config.random_string.user_management_m2m_token will be created
  + resource "random_string" "user_management_m2m_token" {
      + id          = (known after apply)
      + length      = 16
...
...
      + upper       = true
    }

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

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

However if we upgrade to 1.7.3 version of the provider then this now fails because the validation is happening when the provider is initialised instead of allowing it to load that configuration lazily from values that are known at apply time.

$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform planned the following actions, but then encountered a problem:

  # module.auth0_config.random_string.user_management_m2m_token will be created
  + resource "random_string" "user_management_m2m_token" {
      + id          = (known after apply)
      + length      = 16
...
...
      + upper       = true
    }

Plan: 1 to add, 0 to change, 0 to destroy.
╷
│ Error: Invalid provider configuration
│
│ Provider "registry.terraform.io/auth0/auth0" requires explicit configuration. Add a provider block to the root module and configure the provider's required arguments as described in the provider      
│ documentation.
│
╵
╷
│ Error: Missing environment variables
│
│   with provider["registry.terraform.io/auth0/auth0"],
│   on <empty> line 0:
│   (source code not available)
│
│ Either AUTH0_API_TOKEN or AUTH0_DOMAIN:AUTH0_CLIENT_ID:AUTH0_CLIENT_SECRET must be configured. Ref: https://registry.terraform.io/providers/auth0/auth0/latest/docs
╵

@cdsre
Copy link

cdsre commented Nov 26, 2024

This change in behaviour seems to have come from these to pull requests.

#1053 - This added validation on required ENV vars meaning that was the only way to configure the provider

#1065 then changed this behaviour and moved this validation into the ProviderConfig to validate if its value is not empty. I.E it was either set directly or it was from the defaultFunc.

However this doesn't take into account lazy loading of values that might not be known until the provider is actually invoked rather than when the provider is initialized.

From my perspective this is a Breaking Change because it fundamentally changes how the provider works and is not backwards compatible.

@cdsre
Copy link

cdsre commented Nov 26, 2024

@duedares-rvj I have submitted a PR with what I see as a potential solution to this issue that allows you to keep your validation logic to check for missing env vars when we fell back to the EnvDefaultFunc but still allows for provider attributes configured non statically using a resource or data block that will lazily load the value when the provider is needed.

#1085

@cdsre
Copy link

cdsre commented Nov 28, 2024

@duedares-rvj Following the conversation on PR #1085 it doesn't seem there is an easy or clean way to solve environment variable validation in the provider without then blocking dynamic provider attributes that come from resources or delayed data lookups.

Until a more consistent way is found is it possible to remove the environment variables validation in the provider?

@duedares-rvj
Copy link
Contributor

It would be troublesome to go back and forth on the provider's validation.
I request you to use the workaround for your use case (passing a mix of vars) for now.

Once a more consistent way is found, we could add the required checks.
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🪲 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants