github.com/hugorut/terraform@v1.1.3/website/docs/language/modules/develop/providers.mdx (about)

     1  ---
     2  page_title: Providers Within Modules - Configuration Language
     3  ---
     4  
     5  # Providers Within Modules
     6  
     7  [inpage-providers]: #providers-within-modules
     8  
     9  In a configuration with multiple modules, there are some special considerations
    10  for how resources are associated with provider configurations.
    11  
    12  Each resource in the configuration must be associated with one provider
    13  configuration. Provider configurations, unlike most other concepts in
    14  Terraform, are global to an entire Terraform configuration and can be shared
    15  across module boundaries. Provider configurations can be defined only in a
    16  root Terraform module.
    17  
    18  Providers can be passed down to descendent modules in two ways: either
    19  _implicitly_ through inheritance, or _explicitly_ via the `providers` argument
    20  within a `module` block. These two options are discussed in more detail in the
    21  following sections.
    22  
    23  A module intended to be called by one or more other modules must not contain
    24  any `provider` blocks. A module containing its own provider configurations is
    25  not compatible with the `for_each`, `count`, and `depends_on` arguments that
    26  were introduced in Terraform v0.13. For more information, see
    27  [Legacy Shared Modules with Provider Configurations](#legacy-shared-modules-with-provider-configurations).
    28  
    29  Provider configurations are used for all operations on associated resources,
    30  including destroying remote objects and refreshing state. Terraform retains, as
    31  part of its state, a reference to the provider configuration that was most
    32  recently used to apply changes to each resource. When a `resource` block is
    33  removed from the configuration, this record in the state will be used to locate
    34  the appropriate configuration because the resource's `provider` argument
    35  (if any) will no longer be present in the configuration.
    36  
    37  As a consequence, you must ensure that all resources that belong to a
    38  particular provider configuration are destroyed before you can remove that
    39  provider configuration's block from your configuration. If Terraform finds
    40  a resource instance tracked in the state whose provider configuration block is
    41  no longer available then it will return an error during planning, prompting you
    42  to reintroduce the provider configuration.
    43  
    44  ## Provider Version Constraints in Modules
    45  
    46  Although provider _configurations_ are shared between modules, each module must
    47  declare its own [provider requirements](/language/providers/requirements), so that
    48  Terraform can ensure that there is a single version of the provider that is
    49  compatible with all modules in the configuration and to specify the
    50  [source address](/language/providers/requirements#source-addresses) that serves as
    51  the global (module-agnostic) identifier for a provider.
    52  
    53  To declare that a module requires particular versions of a specific provider,
    54  use a `required_providers` block inside a `terraform` block:
    55  
    56  ```hcl
    57  terraform {
    58    required_providers {
    59      aws = {
    60        source  = "hashicorp/aws"
    61        version = ">= 2.7.0"
    62      }
    63    }
    64  }
    65  ```
    66  
    67  A provider requirement says, for example, "This module requires version v2.7.0
    68  of the provider `hashicorp/aws` and will refer to it as `aws`." It doesn't,
    69  however, specify any of the configuration settings that determine what remote
    70  endpoints the provider will access, such as an AWS region; configuration
    71  settings come from provider _configurations_, and a particular overall Terraform
    72  configuration can potentially have
    73  [several different configurations for the same provider](/language/providers/configuration#alias-multiple-provider-configurations).
    74  
    75  ## Provider Aliases Within Modules
    76  
    77  To declare multiple configuration names for a provider within a module, add the
    78  `configuration_aliases` argument:
    79  
    80  ```hcl
    81  terraform {
    82    required_providers {
    83      aws = {
    84        source  = "hashicorp/aws"
    85        version = ">= 2.7.0"
    86        configuration_aliases = [ aws.alternate ]
    87      }
    88    }
    89  }
    90  ```
    91  
    92  The above requirements are identical to the previous, with the addition of the
    93  alias provider configuration name `aws.alternate`, which can be referenced by
    94  resources using the `provider` argument.
    95  
    96  If you are writing a shared Terraform module, constrain only the minimum
    97  required provider version using a `>=` constraint. This should specify the
    98  minimum version containing the features your module relies on, and thus allow a
    99  user of your module to potentially select a newer provider version if other
   100  features are needed by other parts of their overall configuration.
   101  
   102  ## Implicit Provider Inheritance
   103  
   104  For convenience in simple configurations, a child module automatically inherits
   105  default (un-aliased) provider configurations from its parent. This means that
   106  explicit `provider` blocks appear only in the root module, and downstream
   107  modules can simply declare resources for that provider and have them
   108  automatically associated with the root provider configurations.
   109  
   110  For example, the root module might contain only a `provider` block and a
   111  `module` block to instantiate a child module:
   112  
   113  ```hcl
   114  provider "aws" {
   115    region = "us-west-1"
   116  }
   117  
   118  module "child" {
   119    source = "./child"
   120  }
   121  ```
   122  
   123  The child module can then use any resource from this provider with no further
   124  provider configuration required:
   125  
   126  ```hcl
   127  resource "aws_s3_bucket" "example" {
   128    bucket = "provider-inherit-example"
   129  }
   130  ```
   131  
   132  We recommend using this approach when a single configuration for each provider
   133  is sufficient for an entire configuration.
   134  
   135  ~> **Note:** Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must [declare its own provider requirements](/language/providers/requirements). This is especially important for non-HashiCorp providers.
   136  
   137  In more complex situations there may be
   138  [multiple provider configurations](/language/providers/configuration#alias-multiple-provider-configurations),
   139  or a child module may need to use different provider settings than
   140  its parent. For such situations, you must pass providers explicitly.
   141  
   142  ## Passing Providers Explicitly
   143  
   144  When child modules each need a different configuration of a particular
   145  provider, or where the child module requires a different provider configuration
   146  than its parent, you can use the `providers` argument within a `module` block
   147  to explicitly define which provider configurations are available to the
   148  child module. For example:
   149  
   150  ```hcl
   151  # The default "aws" configuration is used for AWS resources in the root
   152  # module where no explicit provider instance is selected.
   153  provider "aws" {
   154    region = "us-west-1"
   155  }
   156  
   157  # An alternate configuration is also defined for a different
   158  # region, using the alias "usw2".
   159  provider "aws" {
   160    alias  = "usw2"
   161    region = "us-west-2"
   162  }
   163  
   164  # An example child module is instantiated with the alternate configuration,
   165  # so any AWS resources it defines will use the us-west-2 region.
   166  module "example" {
   167    source    = "./example"
   168    providers = {
   169      aws = aws.usw2
   170    }
   171  }
   172  ```
   173  
   174  The `providers` argument within a `module` block is similar to
   175  [the `provider` argument](/language/meta-arguments/resource-provider)
   176  within a resource, but is a map rather than a single string because a module may
   177  contain resources from many different providers.
   178  
   179  The keys of the `providers` map are provider configuration names as expected by
   180  the child module, and the values are the names of corresponding configurations
   181  in the _current_ module.
   182  
   183  Once the `providers` argument is used in a `module` block, it overrides all of
   184  the default inheritance behavior, so it is necessary to enumerate mappings
   185  for _all_ of the required providers. This is to avoid confusion and surprises
   186  that may result when mixing both implicit and explicit provider passing.
   187  
   188  Additional provider configurations (those with the `alias` argument set) are
   189  _never_ inherited automatically by child modules, and so must always be passed
   190  explicitly using the `providers` map. For example, a module
   191  that configures connectivity between networks in two AWS regions is likely
   192  to need both a source and a destination region. In that case, the root module
   193  may look something like this:
   194  
   195  ```hcl
   196  provider "aws" {
   197    alias  = "usw1"
   198    region = "us-west-1"
   199  }
   200  
   201  provider "aws" {
   202    alias  = "usw2"
   203    region = "us-west-2"
   204  }
   205  
   206  module "tunnel" {
   207    source    = "./tunnel"
   208    providers = {
   209      aws.src = aws.usw1
   210      aws.dst = aws.usw2
   211    }
   212  }
   213  ```
   214  
   215  The subdirectory `./tunnel` must then declare the configuration aliases for the
   216  provider so the calling module can pass configurations with these names in its `providers` argument:
   217  
   218  ```hcl
   219  terraform {
   220    required_providers {
   221      aws = {
   222        source  = "hashicorp/aws"
   223        version = ">= 2.7.0"
   224        configuration_aliases = [ aws.src, aws.dest ]
   225      }
   226    }
   227  }
   228  ```
   229  
   230  Each resource should then have its own `provider` attribute set to either
   231  `aws.src` or `aws.dst` to choose which of the two provider configurations to
   232  use.
   233  
   234  ## Legacy Shared Modules with Provider Configurations
   235  
   236  In Terraform v0.10 and earlier there was no explicit way to use different
   237  configurations of a provider in different modules in the same configuration,
   238  and so module authors commonly worked around this by writing `provider` blocks
   239  directly inside their modules, making the module have its own separate
   240  provider configurations separate from those declared in the root module.
   241  
   242  However, that pattern had a significant drawback: because a provider
   243  configuration is required to destroy the remote object associated with a
   244  resource instance as well as to create or update it, a provider configuration
   245  must always stay present in the overall Terraform configuration for longer
   246  than all of the resources it manages. If a particular module includes
   247  both resources and the provider configurations for those resources then
   248  removing the module from its caller would violate that constraint: both the
   249  resources and their associated providers would, in effect, be removed
   250  simultaneously.
   251  
   252  Terraform v0.11 introduced the mechanisms described in earlier sections to
   253  allow passing provider configurations between modules in a structured way, and
   254  thus we explicitly recommended against writing a child module with its own
   255  provider configuration blocks. However, that legacy pattern continued to work
   256  for compatibility purposes -- though with the same drawback -- until Terraform
   257  v0.13.
   258  
   259  Terraform v0.13 introduced the possibility for a module itself to use the
   260  `for_each`, `count`, and `depends_on` arguments, but the implementation of
   261  those unfortunately conflicted with the support for the legacy pattern.
   262  
   263  To retain the backward compatibility as much as possible, Terraform v0.13
   264  continues to support the legacy pattern for module blocks that do not use these
   265  new features, but a module with its own provider configurations is not
   266  compatible with `for_each`, `count`, or `depends_on`. Terraform will produce an
   267  error if you attempt to combine these features. For example:
   268  
   269  ```
   270  Error: Module does not support count
   271  
   272    on main.tf line 15, in module "child":
   273    15:   count = 2
   274  
   275  Module "child" cannot be used with count because it contains a nested provider
   276  configuration for "aws", at child/main.tf:2,10-15.
   277  
   278  This module can be made compatible with count by changing it to receive all of
   279  its provider configurations from the calling module, by using the "providers"
   280  argument in the calling module block.
   281  ```
   282  
   283  To make a module compatible with the new features, you must remove all of the
   284  `provider` blocks from its definition.
   285  
   286  If the new version of the module declares `configuration_aliases`, or if the
   287  calling module needs the child module to use different provider configurations
   288  than its own default provider configurations, the calling module must then
   289  include an explicit `providers` argument to describe which provider
   290  configurations the child module will use:
   291  
   292  ```hcl
   293  provider "aws" {
   294    region = "us-west-1"
   295  }
   296  
   297  provider "aws" {
   298    region = "us-east-1"
   299    alias  = "east"
   300  }
   301  
   302  module "child" {
   303    count = 2
   304    providers = {
   305      # By default, the child module would use the
   306      # default (unaliased) AWS provider configuration
   307      # using us-west-1, but this will override it
   308      # to use the additional "east" configuration
   309      # for its resources instead.
   310      aws = aws.east
   311    }
   312  }
   313  ```
   314  
   315  Since the association between resources and provider configurations is
   316  static, module calls using `for_each` or `count` cannot pass different
   317  provider configurations to different instances. If you need different
   318  instances of your module to use different provider configurations then you
   319  must use a separate `module` block for each distinct set of provider
   320  configurations:
   321  
   322  ```hcl
   323  provider "aws" {
   324    alias  = "usw1"
   325    region = "us-west-1"
   326  }
   327  
   328  provider "aws" {
   329    alias  = "usw2"
   330    region = "us-west-2"
   331  }
   332  
   333  provider "google" {
   334    alias       = "usw1"
   335    credentials = "${file("account.json")}"
   336    project     = "my-project-id"
   337    region      = "us-west1"
   338    zone        = "us-west1-a"
   339  }
   340  
   341  provider "google" {
   342    alias       = "usw2"
   343    credentials = "${file("account.json")}"
   344    project     = "my-project-id"
   345    region      = "us-west2"
   346    zone        = "us-west2-a"
   347  }
   348  
   349  module "bucket_w1" {
   350    source    = "./publish_bucket"
   351    providers = {
   352      aws.src    = aws.usw1
   353      google.src = google.usw2
   354    }
   355  }
   356  
   357  module "bucket_w2" {
   358    source    = "./publish_bucket"
   359    providers = {
   360      aws.src    = aws.usw2
   361      google.src = google.usw2
   362    }
   363  }
   364  ```