Main.tf not detecting TF_VARs I setup

I have terraform code that follows the following structure

→ main dir
main.tf
state.tf
versions.tf
→ modules/eks dir
eks.tf
variables.tf
aws.tf
versions.tf

my variables.tf looks like this:

variable "environment" {
  type = string
}

variable "region" {
  type = string
}

My main.tf looks like this

module "aws-deploy" {
 source = "../../modules/eks"
 

I am sourcing an .env file initially before doing terraform init and terraform plan

the .env file looks like

# Cloud Provider

export TF_VAR_environment="terraform-test"

export TF_VAR_region="us-east-1"

After I source the .env file and perform terraform init and apply, I am getting issues that terraform cannot detect the environment variables

 Error: Missing required argument
│ 
│   on main.tf line 1, in module "aws-deploy":
│    1: module "aws-deploy" {
│ 
│ The argument "region" is required, but no definition was found.

I am unsure what to do as I am new to TF_VARs and I want to source my vars apart of my code approach

If anyone can help on this it would be awesome- I am stuck

It looks like you have a root module (main dir) plus a sub-module (modules/eks dir). Both of those have variable definitions (by convention in variables.tf as you have).

For the root module the variables are set from the command line, a tfvars file, environment variables (TF_VAR_<name>) or an interactive prompt.

For sub modules the variables are set from the module {} block.

Your error indicates that the sub-module is expecting a required variable called “region” which is missing. If your main.tf is literally just a module block that has the source line it would give that error. You also need to include lines for “region” and any other variables you want your module to use.

If you are wanting to pass the same value that the root module has, you would have something like:

module "aws-deploy" {
  source = "../../modules/eks"

  region = var.region
...
}

hi @stuart-c - thank you so much!

So you are saying: if I source this .env file

# Cloud Provider

export TF_VAR_environment="terraform-test"

export TF_VAR_region="us-east-1"

and specify the

region = var.region

the var.region is gotten from TF_VAR_region if I understand ?

Correct, for code in the root module.

I am still doing this wrong and wondering how best to modify this code, I guess my parent module “aws-deploy” is trying to provide TF_VAR_region to the child module “eks” but its not working for me

 Error: Reference to undeclared input variable
│ 
│   on main.tf line 9, in module "aws-deploy":
│    9:   region              = var.region
│ 
│ An input variable with the name "region" has not been declared. This variable can be declared with a
│ variable "region" {} block.

I know I am misunderstanding what you mentioned above, my ambition is for the “main.tf” in main dir to call “modules/eks” directory but I want to pass the TF_VARs somehow to child module “modules/eks”

I guess I am either writing my terraform code wrong or do something wrong

I followed the code snippet you shared @stuart-c

module "aws-deploy" {
  source = "../../modules/eks"

  region = var.region
...
}

is better way to organize this code @stuart-c - I maybe not doing the optimal approach for using TF_VARs

@apparentlymart - I see you posted on a similar topic here- Trying to understand input variables - tfvars/variables.tf - do you have any input on this issue? Many thanks!

So you have your root module (the top level directory). It needs to have a variable block for the “region”. You then also have a module block that calls your eks module, passing in the value of the region.

Within the eks module you have a variable block for the “region”.

Then when you run Terraform the root level “region” variable will get its value from the environment variable. You then pass that (in the module block) to your eks module (region = var.region) which can then use it as needed.

@stuart-c : Just want to confirm I understand this (sorry for repetitive questions as first time I ever use TF VAR but trying to build this into my CI/CD pipeline for terraform builds)

  1. For the root module (main), the main.tf looks like

→ main dir
main.tf
state.tf
versions.tf

main.tf

module "aws-deploy" {
  source = "../../modules/eks"

  # AWS
  region              = var.region
}

variable "region" {
  type = string
}

and then for the eks module or eks.tf (child module) in eks folder

→ modules/eks dir
eks.tf
variables.tf
aws.tf
versions.tf

for variables.tf inside eks folder :

variable "region" {
  type = string
}

and then the code for aws.tf inside the (eks folder):

provider "aws" {
  region  = var.region
}

does that look similar to the strategy to getting the region var from environment TF_VAR?

Thank you that worked @stuart-c !!

Yes, however you shouldn’t be putting provider blocks inside a sub-module. All providers should be being defined at the top level and then passed into modules (either explicitly or implicitly).

You are correct indeed.
but there are some providers like elasticsearch which do require provider declaration in the submodules as well, otherwise you might face errors like “required module is not present” when you try to DELETE a module block from the root module.
I have faced these type of issues and adding a provider block in the submodule solved my problem.

Provider blocks shouldn’t be added to submodules, and aren’t allowed if you are wanting to use count or for_each with a module. Within the submodule there should be a required_providers section in the terraform {} block, but no actual provider definitions.

Yeah, I mean “required_providers” section only.

terraform {
  required_providers {
    elasticstack = {
      source  = "elastic/elasticstack"
      version = "0.5.0"
    }
    elasticsearch = {
      source  = "phillbaker/elasticsearch"
      version = "2.0.7"
    }
  }
}

Sorry for the confusion.

Yes. That should really be added into every submodule

1 Like

I posted a question in the forum.
Can you please help me out on that, if possible?

Thank you in advance.