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 ```