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