It is not possible to dynamically associate a resource with a provider. Similar to how in statically-typed programming languages you typically can't dynamically switch a particular symbol to refer to a different library at runtime, Terraform needs to bind resource blocks to provider configurations before expression evaluation is possible.
What you can do is write a module that expects to receive a provider configuration from its caller and then statically select a provider configuration per instance of that module:
provider "azurerm" {
# ...
alias = "core-prod"
}
module "provider-agnostic-example" {
source = "./modules/provider-agnostic-example"
providers = {
# This means that the default configuration for "azurerm" in the
# child module is the same as the "core-prod" alias configuration
# in this parent module.
azurerm = azurerm.core-prod
}
}
In this case, the module itself is provider agnostic, and so it can be used in both your production and non-production settings, but any particular use of the module must specify which it is for.
A common approach is to have a separate configuration for each environment, with shared modules representing any characteristics the environments have in common but giving the opportunity for representing any differences that might need to exist between them. In the simplest case, this might just be two configurations that consist only of a single module
block and a single provider
block, each with some different arguments representing the configuration for that environment, and with the shared module containing all of the resource
and data
blocks. In more complex systems there might be multiple modules integrated together using module composition techniques.