Skip to main content
Knowledge Base

Using Terraform Modules with provider.tf

Answer

I am working on modularising a monolithic structured terraform environment. 1 provider.tf is included per module. The modules are uploaded into a private terraform cloud registry. The terragrunt.hcl that uses the module references it like below: ``` terraform { source = "tfr://app.terraform.io/<WORKSPACE>/<FUNCTION>/<NAME>?version=x.x.x" } ``` Structure: ``` code | --> root.hcl --> linux_user | --> terragrunt.hcl --> bucket | --> terragrunt.hcl ... ``` The module linux_user has a provider.tf which requires 2 additional providers (publically available). So dependency looks like this: * terragrent -- REQUIRES --> linux_user * linux_user -- REQUIRES --> aws & system The problem is that I use a root.hcl that creates the provider.tf which is especially needed for localstack integration and keeping my code dry. ``` generate "provider" { path = "provider.tf" if_exists = "overwrite_terragrunt" #if_exists = "overwrite" contents = <<EOF provider "aws" { access_key = "${local.settings.inputs.access_key}" secret_key = "${local.settings.inputs.secret_key}" region = "${local.settings.inputs.aws_region}" s3_use_path_style = true skip_credentials_validation = true skip_metadata_api_check = true skip_requesting_account_id = true endpoints { acm = "http://${local.settings.inputs.host}:${local.settings.inputs.port}" apigateway = "http://${local.settings.inputs.host}:${local.settings.inputs.port}" ... ``` What is the best practices for creating modules and specifying required providers? Shouldn't this be included in the module? How should Terragrunt handle dependencies inside of modules? Also note, that I don't want to put all of the providers in the root.hcl because some of the providers have specific requirements [neuspaces/system](https://registry.terraform.io/providers/neuspaces/system/latest) where the provider needs additional configuration. Shouldn't the module dictate the versions of providers needed? Terragrunt should just dictate the version of the root module and not its dependencies? --- <ins datetime="2024-03-07T03:16:24Z"> <p><a href="https://support.gruntwork.io/hc/requests/110814">Tracked in ticket #110814</a></p> </ins>

I found a solution: * Add required_providers block into root.hcl * Add a stub block in root.hcl that dynamically applies stubs for all providers that require configuration. * Terragrunt folders that use Modules that configure the providers block will turn off the stubs. * Create a separate file for managing private registry module versions. This way, all module versions & provider versions are in the same place. It will be the responsiblity of the terraform_control repository for managing the versions of everything (which is similar to other orchestration tools like Puppetfile for Puppet). ### stub block in root.hcl This section shows an example of auto-generating the stub block from per folder configuration. You can add additional %{if VARIABLE} blocks as needed. ```hcl locals { stubs = read_terragrunt_config("stubs.hcl") } generate "stub_block" { path = "stub.tf" if_exists = "overwrite_terragrunt" contents = <<EOF %{if local.stubs.inputs.use_system_stub} provider "system" { sudo = false ssh { host = localhost port = 22 user = user private_key = empty } } %{endif} EOF } ``` ### example of stubs.hcl Note, each terragrunt.hcl folder should also have a stub.hcl. ```hcl inputs = { use_system_stub = true } ```