Using output in another module or resource - terraform

I've seen a good amount of posts that talk about passing a module's output into another module. For some reason I can't get this to work.
I can get the output of the module without any issues
$ terraform output
this_sg_id = sg-xxxxxxxxxxxxxxxxx
However, when I call the module in the resource or into another module, it asks me for the Security group ID.
$ terraform plan
var.vpc_security_group_ids
Security Group ID
Enter a value:
Here's my file structure:
── dev
│ └── service
│ └── dev_instance
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
├── modules
│ ├── ec2
│ │ ├── build_ec2.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── sg
│ ├── build_sg.tf
│ ├── outputs.tf
│ └── variables.tf
Not sure if this is correct but in dev/service/dev_instance/main.tf:
module "build_sg" {
source = "../../../modules/sg/"
vpc_id = var.vpc_id
sg_name = var.sg_name
sg_description = var.sg_description
sg_tag = var.sg_tag
sg_tcp_ports = var.sg_tcp_ports
sg_tcp_cidrs = var.sg_tcp_cidrs
sg_udp_ports = var.sg_udp_ports
sg_udp_cidrs = var.sg_udp_cidrs
sg_all_ports = var.sg_all_ports
sg_all_cidrs = var.sg_all_cidrs
}
module "build_ec2" {
source = "../../../modules/ec2/"
vpc_security_group_ids = ["${module.build_sg.this_sg_id}"]
}
In dev/service/dev_instance/output.tf:
output "this_sg_id" {
description = "The security group ID"
value = "${module.build_sg.this_sg_id}"
}
My ec2 module build_ec2.tf file has the following:
resource "aws_instance" "ec2" {
vpc_security_group_ids = ["${module.build_sg.this_sg_id}"]
}

You have a var "vpc_security_group_ids" defined somewhere, I assume in one of your variables.tf files. Terraform doesn't automatically know to fill that in with the output from a module. You need to remove the var definition and just use the module output reference in your template.
Variables are used to pass in values from the command line. They are not tied to module outputs in any way. If you expect values to come from a module you are using then you should not be also defining that value as a variable.

I also think, you need to remove var definition from your variable tf file and use only module output reference.

Related

How to use output of one child module as an input to another child module in Terraform

I have the below directory structure
├── main.tf
├── output.tf
├── variables.tf
├── modules
│ ├── ServicePrincipal
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ ├── main.tf
│ ├── aks
│ │ ├── main.tf
│ │ ├── output.tf
│ │ └── variables.tf
...
Issue:
I want to use client_id and client_secret generated from service principal module as an input to create my aks cluster. I am able to reference the below output variables from my root main.tf by module.modulename.outputvarname however, I cannot access it in another child module(aks) as var.client_id or module.serviceprincipal.client_id
main.tf of root module where I am able to use client_id and client_secret
module "ServicePrincipal" {
source = "./modules/ServicePrincipal"
service_principal_name = var.service_principal_name
redirect_uris = var.redirect_uris
}
module "aks" {
source = "./modules/aks/"
service_principal_name = var.service_principal_name
serviceprinciple_id = module.ServicePrincipal.service_principal_object_id
serviceprinciple_key = module.ServicePrincipal.client_secret
location = var.location
resource_group_name = var.rgname
depends_on = [
module.ServicePrincipal
]
}
main.tf of aks module
service_principal {
client_id = var.client_id
client_secret = var.client_secret
}
output.tf for my ServicePrincipal module
output "client_id" {
description = "The application id of AzureAD application created."
value = azuread_application.main.application_id
}
output "client_secret" {
description = "Password for service principal."
value = azuread_service_principal_password.main.*.value
}
Below is the error I am getting:
Error: Missing required argument
on main.tf line 136, in module "aks":
136: module "aks" {
The argument "client_id" is required, but no definition was found.
Error: Missing required argument
on main.tf line 136, in module "aks":
136: module "aks" {
The argument "client_secret" is required, but no definition was found.
I already defined those as variables in aks module and root module, am I missing something here?
Thanks in advance!
Piyush
Child modules can't reference each others outputs. You have to explicitly pass them in the root module from one module to the second, e.g.
in root:
module "ServicePrincipal" {
}
module "aks" {
client_id = module.ServicePrincipal.client_id
}
You're using output name as client_id and client_secret but in module you're calling with different names ?
module.ServicePrincipal.service_principal_object_id

Terraform aws_iam_access_key secret in another division (using remote_state)

I have a Terraform infrastructure that is divided into "parts" that looks something like this.
.
├── network
│   ├── locals.tf
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
├── ecs
│   ├── locals.tf
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
└── sqs
├── locals.tf
├── main.tf
├── output.tf
└── variables.tf
In SQS, I'm creating a programmatic user with aws_iam_user and aws_iam_access_key.
resource "aws_iam_user" "sqs_write" {
name = "sqs-queue-name-read"
path = "/system/"
}
resource "aws_iam_access_key" "sqs_write" {
user = aws_iam_user.sqs_write.name
pgp_key = local.settings.gpg_public_key
}
Now I need to be able to use aws_iam_access_key.sqs_write.secret in my ECS division.
I tried sending the secret to an "output" and use it with data.terraform_remote_state in my ECS division but Terraform says the output does not exist (most likely because it is marked as sensitive = true.
I tried to save the aws_iam_access_key.sqs_write.secret to a SSM parameter with:
resource "aws_ssm_parameter" "write_secret" {
name = "sqs-queue-name-write-secret-access-key"
description = "SQS write secret access key"
key_id = "aws/secretsmanager"
type = "String"
value = aws_iam_access_key.sqs_write.secret
overwrite = true
}
But I get this error:
╷
│ Error: Missing required argument
│
│ with aws_ssm_parameter.write_secret,
│ on main.tf line 109, in resource "aws_ssm_parameter" "write_secret":
│ 109: value = aws_iam_access_key.sqs_write.secret
│
│ The argument "value" is required, but no definition was found.
╵
So I can't seem to find a way to use the "secret" value outside of my SQS division. I could use the "encrypted_secret" version of it that works fine, but I don't know how I could decrypt it directly from Terraform so I guess it is not an option.
Any thoughts?
My version is:
Terraform v1.0.2 on linux_amd64
provider registry.terraform.io/hashicorp/aws v3.52.0
provider registry.terraform.io/hashicorp/http v2.1.0

Declaring same module twice: duplicate ressources

I am working on a 100% terraform project and I am trying to use the output value from one module into another module. Based on different StackOverflow posts, the most popular way to import the output from module a to module b is to reference the module a inside module b such as:
modules/b/main.tf
module "a" {
source = "./modules/a"
}
After that, you can access output variables from module a inside module b.
My project structure
├── main.tf # declaring all my modules here
├── modules
│ ├── accounts
│ │ ├── main.tf
│ │ └── variables.tf
│ └── organizations
│ ├── main.tf
│ ├── outputs.tf # the var. that I wanna use in accounts
│ └── variables.tf
├── providers.tf
├── variables.tf
└── versions.tf
So my issue is I am declaring all my modules in my main.tf
main.tf
module "organizations" {
source = "./modules/organizations"
}
module "accounts" {
source = "./modules/accounts"
}
However, I need to use one output of module/organizations into module/accounts. And the only way I found to do that is to have (another) organizations module in my modules/accounts/main.tf
modules/accounts/main.tf
module "organizations" {
source = "../organizations"
}
resource "aws_organizations_account" "this" {
name = "uuuu"
email = "udduu#gmail.com"
parent_id = module.organizations.sandbox_organizational_unit_id #HERE
}
But since I already have an organizations module in my main.tf, it's creating/deleting resources in my organization module twice.
organisations/main.tf
data "aws_organizations_organization" "root" {}
locals {
root_id = data.aws_organizations_organization.root.roots[0].id
}
resource "aws_organizations_organizational_unit" "sandboxs" {
name = var.aws_sandboxs_unit_name
parent_id = local.root_id
}
organisations/outputs.tf
output "sandbox_organizational_unit_id" {
value = aws_organizations_organizational_unit.sandboxs.id
description = "ID of the Sandboxs OU"
sensitive = false
}
Neither of your modules should explicitely refer to the other one. Instead, they should declare what kind of variable they expect as input (via a variable key), and what output they provide in return (via the output key)
Then in your main.tf, you can plug everything together:
module "organizations" {
source = "./modules/organizations"
some_variable = module.accounts.some_output
}
module "accounts" {
source = "./modules/accounts"
}
in "organizations", a some_variable must be declared as input: variable some_variable {}
in accounts , a some_output must be declared as output: output some_output { value = ... }

why does my terraform not working with minikube?

I am trying to launch pods using terraform in minikube. While running terraformError Image apply I am getting an error, "zip: not a valid zip file".
provider "kubernetes" {
config_context_cluster = "minikube"
}
resource "kubernetes_pod" "echo" {
metadata {
name = "echo-example"
labels {
App = "echo"
} }
spec {
container {
image = "hashicorp/http-echo:0.2.1"
name = "example2"
args = ["-listen=:80", "-text='Hello World'"]
port {
container_port = 80
}
}
}
}
There are a lot of similar cases. For example this issue
You need to move your individual tf files to their own directories, and then you can point terraform to that directory.
The plan command only accepts directories, and the apply command will only take the entire dir, or plan output file (use -out on plan). I think this limitation is due to the fact that terraform requires a state file for each plan. Here is how I've setup my terraform project, note secrets.tfvars and terraform.tfvars are common between both terraform plans.
$ tree
.
├── 1-base
│ ├── provider.tf
│ ├── backend.tf
│ └── core.tf
├── 2-k8s
│ ├── 1-k8s.tf
│ ├── 2-helm.tf
│ ├── apps
│ ├── provider.tf
│ ├── backend.tf
│ ├── chart-builds
│ └── charts
├── secrets.tfvars
├── terraform.tfvars
└── todo.md
#From here you can run:
$ terraform init -var-file=secrets.tfvars ./1-base
$ terraform plan -var-file=secrets.tfvars ./1-base

can't declare map variables in child modules in terraform 0.12

I used to have (working) map variables in terraform, but after upgrading to terraform 0.12 I keep getting errors of the form:
Error: Invalid value for module argument
on main.tf line 84, in module "gke":
84: gke_label = "var.gke_label"
The given value is not suitable for child module variable "gke_label" defined
at gke/variables.tf:40,1-19: map of any single type required.
I don't understand how to upgrade these map variables. Documentation on this is not particularly clear (to me).
My set-up is as follows:
I have a terraform folder structure:
├── infrastructure
│   ├── backend
│   │   ├── subnet
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   └── vpc
│   │   ├── main.tf
│   │   └── outputs.tf
│   ├── backend.tf
│   ├── backend.tfvars
│   ├── gke
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── main.tf
│   ├── outputs.tf
│   ├── variables.tf
│   └── versions.tf
within main.tf I had / have (among others):
module "gke" {
source = "./gke"
region = "var.region"
min_master_version = "var.min_master_version"
node_version = "var.node_version"
gke_num_nodes = "var.gke_num_nodes" # [MAP VARIABLE]
vpc_name = "module.vpc.vpc_name"
subnet_name = "module.subnet.subnet_name"
gke_master_user = "var.gke_master_user"
gke_master_pass = "var.gke_master_pass"
gke_node_machine_type = "var.gke_node_machine_type"
gke_label = "var.gke_label" # [MAP VARIABLE]
}
and in variables.tf (among others)
variable "gke_label" {
default = {
prod = "prod"
dev = "dev"
}
variable "gke_num_nodes" {
default = {
prod = 2
dev = 1
}
description = "Number of nodes in each GKE cluster zone"
}
within gke/variables.tf I had:
variable "gke_num_nodes" {
type = map
description = "Number of nodes in each GKE cluster zone"
}
variable gke_label {
type = map
description = "label"
}
This used to work fine, but with the upgrade to terraform 0.12 this results in:
Error: Invalid value for module argument
on main.tf line 78, in module "gke":
78: gke_num_nodes = "var.gke_num_nodes"
The given value is not suitable for child module variable "gke_num_nodes"
defined at gke/variables.tf:15,1-25: map of any single type required.
Error: Invalid value for module argument
on main.tf line 84, in module "gke":
84: gke_label = "var.gke_label"
The given value is not suitable for child module variable "gke_label" defined
at gke/variables.tf:40,1-19: map of any single type required.
I changed in gke/variables.tf (same for num_nodes)
variable gke_label {
type = map(any)
description = "label"
}
but the error remains
Error: Invalid value for module argument
on main.tf line 84, in module "gke":
84: gke_label = "var.gke_label"
The given value is not suitable for child module variable "gke_label" defined
at gke/variables.tf:40,1-19: map of any single type required.
How do I update these map variables to terraform 0.12?
This Terraform 0.12 code will assign the value as expected (not a literal string):
gke_num_nodes = var.gke_num_node
In either Terraform 0.11.x or Terraform 0.12, if you use quotes around your variable assignments without interpolation, they will be treated as strings.
gke_num_nodes = "var.gke_num_node"
The code above will assign the literal string "var.gke_num_node" to gke_num_nodes in the module, instead of assigning the value of var.gke_num_nodes as you intend. Since string is not assignable to map(any), Terraform outputs the type error you presented:
Error: Invalid value for module argument
on main.tf line 78, in module "gke":
78: gke_num_nodes = "var.gke_num_nodes"
In Terraform 0.11.x and earlier, you would use string interpolation with ${} to get the value of a variable:
gke_num_nodes = "${var.gke_num_node}"
That kind of expression is deprecated in Terraform 0.12, but will still work in most cases. Do not use string interpolation in Terraform 0.12 unless you are building a string from multiple variable.
You leapt halfway to Terraform 0.12 by removing the ${}. Leap the remaining gap by removing the quotes so your variable assignments will work as expected:
gke_num_nodes = var.gke_num_node
Here is the entire module block, corrected to remove the quotes:
module "gke" {
source = "./gke"
region = var.region
min_master_version = var.min_master_version
node_version = var.node_version
gke_num_nodes = var.gke_num_node # [MAP VARIABLE]
vpc_name = module.vpc.vpc_name
subnet_name = module.subnet.subnet_name
gke_master_user = var.gke_master_user
gke_master_pass = var.gke_master_pass
gke_node_machine_type = var.gke_node_machine_type
gke_label = var.gke_label # [MAP VARIABLE]
}

Resources