How to create hierarchical module structures

The issue that I am running into now is related to AWS permissions. The question is does the root module pass aws permissions down to the sub-modules? For example,

module nf_cis_benchmark {
    source = "./modules/nf_cis_benchmark"
    name        = local.name
    environment = "${local.environments[terraform.workspace]}"
    region      = data.aws_region.current.name
    organization_id = data.aws_organizations_organization.org.id
    account_id  = data.aws_caller_identity.current.account_id
    workspace   = "${terraform.workspace}"
    workspace_iam_role = var.workspace_iam_roles[terraform.workspace]

    providers = {
        aws.us-east-1       = aws.us-east-1,
        aws.af-south-1      = aws.af-south-1,
        aws.ap-east-1       = aws.ap-east-1,
        aws.ap-northeast-1  = aws.ap-northeast-1,
        aws.ap-northeast-2  = aws.ap-northeast-2,
        aws.ap-south-1      = aws.ap-south-1,
        aws.ap-southeast-1  = aws.ap-southeast-1,
        aws.ap-southeast-2  = aws.ap-southeast-2
        aws.ca-central-1    = aws.ca-central-1,
        aws.eu-central-1    = aws.eu-central-1,
        aws.eu-north-1      = aws.eu-north-1,
        aws.eu-south-1      = aws.eu-south-1,
        aws.eu-west-1       = aws.eu-west-1,
        aws.eu-west-2       = aws.eu-west-2,
        aws.eu-west-3       = aws.eu-west-3,
        aws.me-south-1      = aws.me-south-1,
        aws.sa-east-1       = aws.sa-east-1,
        aws.us-east-2       = aws.us-east-2,
        aws.us-west-1       = aws.us-west-1,
        aws.us-west-2       = aws.us-west-2
    }
}

In this case is my user account id

account_id  = data.aws_caller_identity.current.account_id

I haven’t had issues provisioning resources before and I haven’t changed my ~/.aws/credentials file, but now I’m getting

│ Error: error reading SQS Queue (https://sqs.us-east-1.amazonaws.com/{ENV-ACCOUNT-ID}/nf-cisbenchmark-cloudwatch-alerts-nf-sandbox): AccessDenied: Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied.
│       status code: 403, request id: db812f03-1d4d-55c0-9e75-750c48210c83

Where ENV-ACCOUNT-ID is the account id for the environment.

The question I am trying to answer is how to pass the aws account id down from the root configuration to the nf_cis_benchmark module.

Hi @EvanGertis,

Terraform Core doesn’t directly interact with credentials itself, but passing a provider configuration should effectively pass in whatever credentials that configuration is using.

A way to think about it is that Terraform is going to create one instance of the provider plugin per distinct provider configuration, and so if you pass a provider configuration from the root module into a child module then it’s making its requests against exactly the same plugin process – configured with credentials, etc just once for each action – and so the remote AWS API can’t see any difference between requests made in the root vs. requests made in the module as long as both of the resources are associated with the same provider configuration and thus the same plugin process.

1 Like

I’m running into an unusual issue. Previously, I was able to run terraform apply from the root dir, but since I’ve changed the structure to a module hierarchy I am getting a permissions denied error.

Error: error reading S3 bucket Public Access Block (nf-cisbenchmark-nf-sandbox-cloudtrail): AccessDenied: Access Denied
│       status code: 403, request id: xxxxx, host id: xxxxxx=

The issue was in the list of providers. I need to add a default provider.

provider aws {
  region = "us-east-1"

  assume_role {
    role_arn = var.workspace_iam_roles[terraform.workspace]
  }
}

In addition to the original list of providers


provider aws {
  alias = "us-east-1"
  region = "us-east-1"

  assume_role {
    role_arn = var.workspace_iam_roles[terraform.workspace]
  }
}

provider aws {
  alias = "af-south-1"
  region = "af-south-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ap-east-1"
  region = "ap-east-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ap-northeast-1"
  region = "ap-northeast-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ap-northeast-2"
  region = "ap-northeast-2"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ap-south-1"
  region = "ap-south-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ap-southeast-1"
  region = "ap-southeast-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ap-southeast-2"
  region = "ap-southeast-2"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "ca-central-1"
  region = "ca-central-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "eu-central-1"
  region = "eu-central-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "eu-north-1"
  region = "eu-north-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "eu-south-1"
  region = "eu-south-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "eu-west-1"
  region = "eu-west-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "eu-west-2"
  region = "eu-west-2"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "eu-west-3"
  region = "eu-west-3"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "me-south-1"
  region = "me-south-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "sa-east-1"
  region = "sa-east-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "us-east-2"
  region = "us-east-2"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "us-west-1"
  region = "us-west-1"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}

provider aws {
  alias = "us-west-2"
  region = "us-west-2"
 
 assume_role {
   role_arn = var.workspace_iam_roles[terraform.workspace]
 }
}




terraform {
  required_version = ">= 0.13.7"

  backend "s3" {
    bucket         = "nf-mop-tf-state"
    key            = "security/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "nf-terraform-state-lock"
  }
}

# Current Account ID
data aws_caller_identity current {
}

data aws_region current {
}