I'm trying to use a vpc module i made for aws in a top module.
My tree is as follows:
.
├── dev.vars.json
├── modules
│ └── vpc
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── outputs.tf
├── variables.tf
└── main.tf
the "vpc" module works fine, I'm trying to use that module in my main.tf file on the root folder like this:
$ cat main.tf
module "dev_vpc" {
source = "./modules/vpc"
}
my variables:
variable "vpc" {
type = object({
name = string
})
}
my outputs.tf
# VPC
output "vpc_id" {
description = "The ID of the VPC"
value = module.vpc.vpc_id
}
...
and my dev.vars.json:
{
"vpc": {
"name": "development-vpc"
},
}
Once i got the vpc in "modules/vpc" working, I want to use it on the top main.tf file, but when i run apply (after init) i get:
$ terraform plan -var-file dev.vars.json
╷
│ Error: Missing required argument
│
│ on main.tf line 1, in module "dev_vpc":
│ 1: module "dev_vpc" {
│
│ The argument "vpc" is required, but no definition was found.
the main.tf in modules/vpc:
provider "aws" {
region = local.region
}
locals {
region = "us-east-1"
}
################################################################################
# VPC Module
################################################################################
resource "aws_vpc" "dev_vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.66.0"
name = var.vpc.name
cidr = "10.0.0.0/16"
azs = ["${local.region}a", "${local.region}b", "${local.region}c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_ipv6 = true
enable_nat_gateway = false
single_nat_gateway = true
public_subnet_tags = {
Name = "overridden-name-public"
}
tags = {
Owner = "user"
Environment = "dev"
}
vpc_tags = {
Name = "vpc-name"
}
}
I haven't been able to figure out how to fix this.
Many thanks!
davidcsi
It ended up being that i used a terraform from terraform's github, and there's a lot of dependencies that wouldn't work.
my final vpc code is:
$ cat main.tf
provider "aws" {
region = "${var.region}"
}
/*==== The VPC ======*/
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_cidr}"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.environment}-vpc"
Environment = "${var.environment}"
}
}
$ cat subnets.tf
/* Internet gateway for the public subnet */
resource "aws_internet_gateway" "ig" {
vpc_id = "${aws_vpc.vpc.id}"
tags = {
Name = "${var.environment}-igw"
Environment = "${var.environment}"
}
}
/* Elastic IP for NAT */
resource "aws_eip" "nat_eip" {
vpc = true
depends_on = [aws_internet_gateway.ig]
}
/* NAT */
resource "aws_nat_gateway" "nat" {
allocation_id = "${aws_eip.nat_eip.id}"
subnet_id = "${element(aws_subnet.public_subnet.*.id, 0)}"
depends_on = [aws_internet_gateway.ig]
tags = {
Name = "nat"
Environment = "${var.environment}"
}
}
/* Public subnet */
resource "aws_subnet" "public_subnet" {
vpc_id = "${aws_vpc.vpc.id}"
count = "${length(var.public_subnets_cidr)}"
cidr_block = "${element(var.public_subnets_cidr, count.index)}"
availability_zone = "${element(var.availability_zones, count.index)}"
map_public_ip_on_launch = true
tags = {
Name = "${var.environment}-${element(var.availability_zones, count.index)}- public-subnet"
Environment = "${var.environment}"
}
}
/* Private subnet */
resource "aws_subnet" "private_subnet" {
vpc_id = "${aws_vpc.vpc.id}"
count = "${length(var.private_subnets_cidr)}"
cidr_block = "${element(var.private_subnets_cidr, count.index)}"
availability_zone = "${element(var.availability_zones, count.index)}"
map_public_ip_on_launch = false
tags = {
Name = "${var.environment}-${element(var.availability_zones, count.index)}-private-subnet"
Environment = "${var.environment}"
}
}
/* Routing table for private subnet */
resource "aws_route_table" "private" {
vpc_id = "${aws_vpc.vpc.id}"
tags = {
Name = "${var.environment}-private-route-table"
Environment = "${var.environment}"
}
}
/* Routing table for public subnet */
resource "aws_route_table" "public" {
vpc_id = "${aws_vpc.vpc.id}"
tags = {
Name = "${var.environment}-public-route-table"
Environment = "${var.environment}"
}
}
resource "aws_route" "public_internet_gateway" {
route_table_id = "${aws_route_table.public.id}"
destination_cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.ig.id}"
}
resource "aws_route" "private_nat_gateway" {
route_table_id = "${aws_route_table.private.id}"
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = "${aws_nat_gateway.nat.id}"
}
/* Route table associations */
resource "aws_route_table_association" "public" {
count = "${length(var.public_subnets_cidr)}"
subnet_id = "${element(aws_subnet.public_subnet.*.id, count.index)}"
route_table_id = "${aws_route_table.public.id}"
}
resource "aws_route_table_association" "private" {
count = "${length(var.private_subnets_cidr)}"
subnet_id = "${element(aws_subnet.private_subnet.*.id, count.index)}"
route_table_id = "${aws_route_table.private.id}"
$ cat security_groups.tf
/*==== VPC's Default Security Group ======*/
resource "aws_security_group" "default" {
name = "${var.environment}-default-sg"
description = "Default security group to allow inbound/outbound from the VPC"
vpc_id = "${aws_vpc.vpc.id}"
depends_on = [aws_vpc.vpc]
ingress {
from_port = "0"
to_port = "0"
protocol = "-1"
self = true
}
egress {
from_port = "0"
to_port = "0"
protocol = "-1"
self = "true"
}
tags = {
Environment = "${var.environment}"
}
}
$ cat outputs.tf
output "vpc_id" {
value = "${aws_vpc.vpc.id}"
}
cat variables.tf
variable "region" {
description = "AWS Deployment region.."
default = "us-east-1"
}
variable "vpc_cidr" {
description = "CIDR to assign to this VPC"
default = "10.0.0.0/16"
}
variable "environment" {
description = "On what environment is this running?"
default = "dev"
}
variable "availability_zones" {
description = "On what environment is this running?"
default = [
"us-east-1a",
"us-east-1b",
"us-east-1c"
]
}
variable "public_subnets_cidr" {
description = "public_subnets_cidr"
default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}
variable "private_subnets_cidr" {
description = "On what environment is this running?"
default = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
}
This doesn't give me any issues when using it as a module.
Related
I am trying to update the routing tables of the subnets in VPC A and VPC B to include a route to a VPC peering end-point. This is my terraform code.
main.tf
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.14.2"
for_each = local.vpc_list
name = each.key
cidr =each.value.vpc_cidr
azs = each.value.vpc_azs
public_subnets = each.value.vpc_public_subnets
private_subnets = each.value.vpc_private_subnets
enable_nat_gateway = each.value.vpc_enable_nat_gateway
enable_vpn_gateway = each.value.vpc_enable_vpn_gateway
tags = each.value.vpc_tags
public_subnet_tags = each.value.vpc_public_subnet_tags
private_subnet_tags = each.value.vpc_private_subnet_tags
}
resource "aws_vpc_peering_connection" "vpc_peering_conn" {
peer_owner_id = data.aws_caller_identity.current.account_id
peer_vpc_id = module.vpc["vpcB"].vpc_id
vpc_id = module.vpc["vpcA"].vpc_id
auto_accept = true
tags = {
Name = "VPC Peering between ${module.vpc["vpcA"].name} and ${module.vpc["vpcB"].name}."
}
}
data "aws_route_tables" "vpcA_public_subnet_rts" {
depends_on = [ module.vpc ]
vpc_id = module.vpc["vpcA"].vpc_id
filter {
name = "tag:Subnet"
values = ["*public*"]
}
}
resource "aws_route" "route_vpcA" {
count = length(data.aws_route_tables.vpcA_public_subnet_rts.ids)
route_table_id = tolist(data.aws_route_tables.vpcA_public_subnet_rts.ids)[count.index]
destination_cidr_block = "10.10.11.0/24"
vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_conn.id
}
data "aws_route_tables" "vpcB_private_subnet_rts" {
depends_on = [ module.vpc ]
vpc_id = module.vpc["vpcB"].vpc_id
filter {
name = "tag:Subnet"
values = ["*private*"]
}
}
resource "aws_route" "route_vpcB" {
count = length(data.aws_route_tables.vpcB_private_subnet_rts.ids)
route_table_id = tolist(data.aws_route_tables.vpcB_private_subnet_rts.ids)[count.index]
destination_cidr_block = "10.10.10.0/24"
vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_conn.id
}
locals.tf
locals {
vpc_list = {
"vpcA" = {
vpc_cidr = "10.10.10.0/24",
vpc_azs = ["ap-southeast-1a"],
vpc_public_subnets = ["10.10.10.0/25"],
vpc_private_subnets = ["10.10.10.128/25"],
vpc_enable_nat_gateway = false,
vpc_enable_vpn_gateway = false,
vpc_tags = {
Name= "VPC A"
Terraform = "true"
Environment = "1st VPC"
Facing= "public and private"
},
vpc_public_subnet_tags = {
Subnet = "vpcA_public_subnet"
},
vpc_private_subnet_tags = {
Subnet = "vpcA_private_subnet"
},
},
"vpcB" = {
vpc_cidr = "10.10.11.0/24",
vpc_azs = ["ap-southeast-1b"],
vpc_public_subnets = [],
vpc_private_subnets = ["10.10.11.0/24"],
vpc_enable_nat_gateway = false,
vpc_enable_vpn_gateway = false,
vpc_tags = {
Name= "VPC B"
Terraform = "true"
Environment = "2nd VPC"
Facing= "private"
},
vpc_public_subnet_tags = {
Subnet = "vpcB_public_subnet"
},
vpc_private_subnet_tags = {
Subnet = "vpcB_private_subnet"
},
},
}
}
locals {
routing_table = {
route_peer_con_vpcA = {
vpc_id = module.vpc["vpcA"].vpc_id
route = {
route_peer_to_vpcB = {
cidr_block = "10.10.11.0/24"
}
}
}
route_peer_con_vpcB = {
vpc_id = module.vpc["vpcB"].vpc_id
route = {
route_peer_to_vpcA = {
cidr_block = "10.10.10.0/24"
}
}
}
}
}
When I run the terraform plan or apply I am getting the below error. Does anyone knows how to address the issue or Is there a better way to achieve what I want?
I saw this post "terraform: data.aws_subnet, value of 'count' cannot be computed" but am not sure how to refer to the output of the subnet' s id for the routing table id.
Thanks.
➜ 01-tf-deploy terraform apply --auto-approve
data.aws_region.current: Reading...
data.aws_caller_identity.current: Reading...
data.aws_region.current: Read complete after 0s [id=ap-southeast-1]
data.aws_ami.amzlinux2: Reading...
data.aws_ami.amzlinux2: Read complete after 1s [id=ami-0c802847a7dd848c0]
data.aws_caller_identity.current: Read complete after 1s [id=500295128231]
╷
│ Error: Invalid count argument
│
│ on main.tf line 70, in resource "aws_route" "route_vpcA":
│ 70: count = length(data.aws_route_tables.vpcA_public_subnet_rts.ids)
│
│ The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count
│ depends on.
╵
╷
│ Error: Invalid count argument
│
│ on main.tf line 88, in resource "aws_route" "route_vpcB":
│ 88: count = length(data.aws_route_tables.vpcB_private_subnet_rts.ids)
│
│ The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count
│ depends on.
╵
My terraform module structure looks like this.
├───dev
│ dev.auto.tfvars
│ main.tf
│ output.tf
│ variables.tf
│
└───modules
├───instances
│ main.tf
│ output.tf
│ variables.tf
│ versions.tf
│
└───networking
main.tf
output.tf
variables.tf
versions.tf
My learning objective is to add aws_vpc,aws_subnet under networking module.
networking (main.tf)
resource "aws_vpc" "vpc" {
cidr_block = var.cidr_block
instance_tenancy = "default"
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
}
resource "aws_subnet" "private_subnets" {
cidr_block = var.private_subnets
vpc_id = aws_vpc.vpc.id
availability_zone = var.az
}
resource "aws_subnet" "public_subnets" {
cidr_block = var.public_subnets
vpc_id = aws_vpc.vpc.id
availability_zone = var.az
}
I'm referring this from my dev(main.tf)
module "vpc_subnets" {
source = "../modules/networking"
cidr_block = var.vpc_cidr_block
enable_dns_hostnames = true
enable_dns_support = true
az = var.az
}
But I can't understand how to refer/call to resource "aws_subnet" "private_subnets" and resource "aws_subnet" "public_subnets" in my dev (main.tf) .
Your module has to output values that you want to use in your dev (main.tf). For example:
resource "aws_vpc" "vpc" {
cidr_block = var.cidr_block
instance_tenancy = "default"
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
}
resource "aws_subnet" "private_subnets" {
cidr_block = var.private_subnets
vpc_id = aws_vpc.vpc.id
availability_zone = var.az
}
resource "aws_subnet" "public_subnets" {
cidr_block = var.public_subnets
vpc_id = aws_vpc.vpc.id
availability_zone = var.az
}
output "public_subnets" {
value = aws_subnet.public_subnets
}
output "private_subnets" {
value = aws_subnet.private_subnets
}
then in your dev (main.tf) your refer to them as
module "vpc_subnets" {
source = "../modules/networking"
cidr_block = var.vpc_cidr_block
enable_dns_hostnames = true
enable_dns_support = true
az = var.az
}
# for example:
locals {
my_public_subnet_id = module.vpc_subnets.public_subnets.id
my_private_subnet_id = module.vpc_subnets.private_subnets.id
}
Hello i have 3 files in my terraform directory
vpc.tf aerospike-ec2.tf vars.tf
and here is contents of vpc.tf file
resource "aws_vpc" "wizzair-dev-qa-vpc" {
cidr_block = var.wizzair-dev-qa-vpc_cidr
tags = {
Environment = "dev-qa"
Name = "wizzair-aws-vpc"
Project = "Network"
}
}
data "aws_availability_zones" "available" {}
resource "aws_subnet" "private_subnets" {
vpc_id = aws_vpc.wizzair-dev-qa-vpc.id
cidr_block = var.subnet_cidr
availability_zone = "eu-north-1a"
tags = {
Environment = "dev-qa"
Project = "Network"
Name = "wizzair-aws-subnet-private"
}
}
here is my aerospike.tf file
resource "aws_network_interface" "private" {
subnet_id = aws_subnet.private_subnets.id
private_ips = ["10.249.10.4"]
security_groups = [aws_security_group.aerospike_traffic.id, aws_security_group.general.id]
tags = {
Environment = "dev"
Project = "wizzair"
Name = "aerospike-interface"
}
}
resource "aws_instance" "dev-wizzair-aerospike" {
ami = "ami-077b12cf33hb9a995"
availability_zone = "eu-north-1a"
instance_type = "t3.large"
key_name = "${var.generated_key_name}"
network_interface {
device_index=0
network_interface_id = aws_network_interface.private.id
}
tags = {
Environment = "dev"
Project = "wizzair"
Name = "aerospike-instance-dev"
}
}
resource "aws_ebs_volume" "dev-wizzair-aerospike-ebs" {
availability_zone = "eu-north-1a"
size = 10
tags = {
Environment = "dev"
Project = "wizzair"
Name = "aerospike-volume"
}
}
resource "aws_volume_attachment" "dev-wizzair-aerospike-ebs-att" {
device_name = "/dev/sdh"
volume_id = aws_ebs_volume.dev-wizzair-aerospike-ebs.id
instance_id = aws_instance.dev-wizzair-aerospike.id
}
and vars.tf
variable "wizzair-dev-qa-vpc-cidr" {
default = "10.249.10.0/24"
}
and if the files are in the same directory, then everything works, but if I create the aerospike directory and transfer the aerospike.tf file there, then go to the aerospike directory and enter terraform plan there, then an error occurs
mkdir aerospike && mv aerospike.tf aerospike && cd aerospike && terraform plan
terraform plan
╷
│ Error: Reference to undeclared resource
│
│ on main.tf line 2, in resource "aws_network_interface" "private":
│ 2: subnet_id = aws_subnet.private_subnets.id
│
│ A managed resource "aws_subnet" "private_subnets" has not been declared in the root module.
i've heard about state outputs, but how to deal with it in my case?
You can't just randomly move files to sub-folders. You have to construct TF modules for that, which you then have to appropriately call and use in your parent script.
I've a two modules under modules directory named as prienv and vpc
nnice#MPL-G8WW7D3:~/terra-test/modules/prienv$ pwd
/home/nnice/terra-test/modules/prienv
nnice#MPL-G8WW7D3:~/terra-test/modules/prienv$ ls
data.tf main.tf variable.tf
Here is my data.tf file under prienv module
nnice#MPL-G8WW7D3:~/terra-test/modules/prienv$ cat data.tf
data "aws_security_groups" "mysg-data" {
filter {
name = "tag:Name"
values = ["MySG"]
}
depends_on = [aws_security_groups.mysg]
}
data "aws_subnet" "myprisn-data" {
filter {
name = "tag:Name"
values = ["MyPriSN"]
}
depends_on = [aws_subnet.myprisn]
}
Here is my variable.tf file under prienv module
variable "pri_av" {
description = "for private availability zone"
type = string
default = "us-east-1b"
}
variable "ami" {
description = "ami for ec2"
type = string
default = "ami-03ededff12e34e59e"
}
variable "instance_type" {
description = "Instance type t2.micro"
type = string
default = "t2.micro" #will use double quotes for string type
}
variable "key_pair" {
description = "key pair for ec2"
type = string
default = "learner_key"
}
variable "instance_count" {
description = "EC2 instance count"
type = number
default = 1 #here we're using it to create two private instances
}
variable "project_environment" {
description = "project name and environment for private instances"
type = map(string)
default = {
project = "private", # it works upon key value pair where project is for key and environment is value
environment = "testing" # you will find them under tag on aws console
}
}
And this is my main.tf file under prienv module
resource "aws_instance" "mypriec2" {
ami = var.ami
instance_type = var.instance_type
count = var.instance_count
availability_zone = var.pri_av
#subnet_id = aws_subnet.myprisn.id
subnet_id = data.aws_subnet.myprisn-data.id
#vpc_security_group_ids = [aws_security_group.mysg.id]
vpc_security_group_ids = data.aws_security_groups.mysg-data.ids
key_name = var.key_pair
# disable_api_termination = true
tags = var.project_environment
}
resource "aws_key_pair" "mykeypair" {
key_name = var.key_pair
public_key = "ssh-rsa AAAAB3NaffrWscf59juCakElys9F3+zVuz0ta4gRUtKgWVPIj6ACr00VNDzsTTW2/sSjYtE5zWolVKCITlhqiIhgRKUDLKoxclxUKnK6IGIafdaefafaheiufa;fdaeoasfdkQvNtGrrHzY5/dbZhIUTxDUyvT5O5U= nnice#MPL-G8WW7D3"
}
and here is my vpc moduls
nnice#MPL-G8WW7D3:~/terra-test/modules/vpc$ pwd
/home/nnice/terra-test/modules/vpc
nnice#MPL-G8WW7D3:~/terra-test/modules/vpc$ ls
data.tf main.tf variable.tf
This is my data.tf file under vpc module
nnice#MPL-G8WW7D3:~/terra-test/modules/vpc$ cat data.tf
data "aws_vpc" "myvpc-data" {
filter {
name = "tag:Name"
values = ["MyVPC"]
}
depends_on = [aws_vpc.myvpc]
}
data "aws_subnet" "mypubsn-data" {
filter {
name = "tag:Name"
values = ["MyPubSN"]
}
depends_on = [aws_subnet.mypubsn]
}
data "aws_subnet" "myprisn-data" {
filter {
name = "tag:Name"
values = ["MyPriSN"]
}
depends_on = [aws_subnet.myprisn]
}
This is my main.tf file under vpc module
nnice#MPL-G8WW7D3:~/terra-test/modules/vpc$ cat main.tf
##################################################################
############################## VPC ###############################
##################################################################
resource "aws_vpc" "myvpc" {
cidr_block = var.vpc_cidr
instance_tenancy = var.vpc_tenancy
tags = {
Name = var.vpc_tag
}
}
##################################################################
############################# Subnet #############################
##################################################################
#PUBLIC SUBNET
resource "aws_subnet" "mypubsn" {
#vpc_id = aws_vpc.myvpc.id
vpc_id = data.aws_vpc.myvpc-data.id
cidr_block = var.mypubsn_cidr
availability_zone = var.pub_av
map_public_ip_on_launch = var.map_public_ip_on_launch
tags = {
Name = var.mypubsn_tag
}
}
#PRIVATE SUBNET
resource "aws_subnet" "myprisn" {
#vpc_id = aws_vpc.myvpc.id
vpc_id = data.aws_vpc.myvpc-data.id
cidr_block = var.myprisn_cidr
availability_zone = var.pri_av
tags = {
Name = var.myprisn_tag
}
}
##################################################################
############################### IGW ##############################
##################################################################
resource "aws_internet_gateway" "myigw" {
#vpc_id = aws_vpc.myvpc.id
vpc_id = data.aws_vpc.myvpc-data.id
tags = {
Name = var.igw_tag
}
}
##################################################################
############################ Route Table #########################
##################################################################
#PUBLIC RT
resource "aws_route_table" "mypubrt" {
#vpc_id = aws_vpc.myvpc.id
vpc_id = data.aws_vpc.myvpc-data.id
tags = {
Name = var.mypubsn_tag
}
}
#PRIVATE RT
resource "aws_route_table" "myprirt" {
#vpc_id = aws_vpc.myvpc.id
vpc_id = data.aws_vpc.myvpc-data.id
tags = {
Name = var.myprisn_tag
}
}
####################################################################
######################## Route Table Associate #####################
####################################################################
#PUBLIC RT association
resource "aws_route_table_association" "pub" {
#subnet_id = aws_subnet.mypubsn.id
subnet_id = data.aws_subnet.mypubsn-data.id
route_table_id = aws_route_table.mypubrt.id
}
#PRIVATE RT association
resource "aws_route_table_association" "pri" {
#subnet_id = aws_subnet.myprisn.id
subnet_id = data.aws_subnet.myprisn-data.id
route_table_id = aws_route_table.myprirt.id
}
###################################################################
########################### Route #################################
###################################################################
#PUBLIC Route
resource "aws_route" "mypubroute" {
route_table_id = aws_route_table.mypubrt.id
destination_cidr_block = var.pubroute
gateway_id = aws_internet_gateway.myigw.id
depends_on = [aws_route_table.mypubrt]
}
#PRIVATE Route
#resource "aws_route" "mypriroute" {
# route_table_id = aws_route_table.myprirt.id
# destination_cidr_block = "0.0.0.0/0"
# gateway_id = aws_internet_gateway.myigw.id
# depends_on = [aws_route_table.myprirt]
#}
###################################################################
############################ SG ###################################
###################################################################
resource "aws_security_group" "mysg" {
name = "MySecurityGroup"
description = "Allow TLS inbound traffic"
#vpc_id = aws_vpc.myvpc.id
vpc_id = data.aws_vpc.myvpc-data.id
ingress {
description = "TLS from VPC"
from_port = 22
to_port = 22
protocol = "tcp"
# cidr_blocks = [aws_vpc.myvpc.cidr_block]
cidr_blocks = ["0.0.0.0/0"]
# ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
}
ingress {
description = "TLS from VPC"
from_port = 80
to_port = 80
protocol = "tcp"
# cidr_blocks = [aws_vpc.myvpc.cidr_block]
cidr_blocks = ["0.0.0.0/0"]
# ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = var.SG_tag
}
}
And this is my variable.tf file under vpc module
nnice#MPL-G8WW7D3:~/terra-test/modules/vpc$ cat variable.tf
variable "vpc_tenancy" {
description = "vpc instance tenancy"
type = string
default = "default"
}
variable "pub_av" {
description = "for public availability zone"
type = string
default = "us-east-1a"
}
variable "pri_av" {
description = "for private availability zone"
type = string
default = "us-east-1b"
}
variable "vpc_tag" {
description = "Tag for VPC"
type = string
default = "MyVPC"
}
variable "vpc_cidr" {
description = "for vpc cidr"
type = string
default = "10.0.0.0/16"
}
variable "mypubsn_cidr" {
description = "for public subnet cidr"
type = string
default = "10.0.1.0/24"
}
variable "myprisn_cidr" {
description = "for private subnet cidr"
type = string
default = "10.0.2.0/24"
}
variable "mypubsn_tag" {
description = "tag for public subnet"
type = string
default = "MyPubSN"
}
variable "myprisn_tag" {
description = "tag for private subnet"
type = string
default = "MyPriSN"
}
variable "igw_tag" {
description = "tag for IGW subnet"
type = string
default = "MyIGW"
}
variable "pubrt_tag" {
description = "tag for private subnet"
type = string
default = "MyPubRT"
}
variable "prirt_tag" {
description = "tag for IGW subnet"
type = string
default = "MyPriRT"
}
variable "pubroute" {
description = "cidr for public route"
type = string
default = "0.0.0.0/0"
}
variable "SG_tag" {
description = "tag for SG"
type = string
default = "MySG"
}
variable "map_public_ip_on_launch" {
description = "auto enable public ip to public subnet"
type = bool
default = true
}
And there is env directory where I have my main.tf file
nnice#MPL-G8WW7D3:~/terra-test$ ls
env modules
nnice#MPL-G8WW7D3:~/terra-test$ cd env/private-ec2/
nnice#MPL-G8WW7D3:~/terra-test/env/private-ec2$ pwd
/home/nnice/terra-test/env/private-ec2
nnice#MPL-G8WW7D3:~/terra-test/env/private-ec2$ ls
main.tf
nnice#MPL-G8WW7D3:~/terra-test/env/private-ec2$ cat main.tf
#Provider
provider "aws" {
region = "us-east-1"
}
#VPC
module "vpc" {
source = "../../modules/vpc"
}
#EC2
module "prienv" {
source = "../../modules/prienv"
}
When I'm trying to run terraform plan, I'm getting following errors
Error: Reference to undeclared resource
│
│ on ../../modules/prienv/data.tf line 6, in data "aws_security_groups" "mysg-data":
│ 6: depends_on = [aws_security_groups.mysg]
│
│ A managed resource "aws_security_groups" "mysg" has not been declared in module.prienv.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../../modules/prienv/data.tf line 14, in data "aws_subnet" "myprisn-data":
│ 14: depends_on = [aws_subnet.myprisn]
│
│ A managed resource "aws_subnet" "myprisn" has not been declared in module.prienv.
Could anyone please let me know its solution? I already using vpc module in my main.tf file
The issue you are running into is that aws_security_groups.mysgand aws_subnet.myprisn are locally defined in the vpc module but you are referencing them in the depends_on statement in the prienv module.
Also the Terraform documentation suggests that the depends_on argument
should be used only as a last resort.
So the way to go would be, to define the security group and the subnet as an output in the vpc module, as variable in the prienv module, and then passing the outputs of vpc as parameter values to prienv.
This way terraform will recognize the dependencies between the resources from the dependency graph it creates and you won't neet the depends_on argument.
So in consequence, the diffs to your config could look like:
modules/vpc/outputs.tf
output "sec_group" {
value = aws_security_group.mysg
description = "..."
}
output "subnet" {
value = aws_subnet.myprisn
description = "..."
}
modules/prienv/variable.tf
variable "sec_group" {
description = "..."
}
variable "subnet" {
description = "..."
}
modules/prienv/main.tf
resource "aws_instance" "mypriec2" {
...
subnet_id = var.subnet.id
vpc_security_group_ids = var.sec_group.ids
...
}
env/main.tf
module "vpc" {
source = "../../modules/vpc"
}
#EC2
module "prienv" {
source = "../../modules/prienv"
sec_group = module.vpc.sec_group
subnet = module.vpc.subnet
}
main.tf
module "vpc" {
source = "../modules/aws/vpc"
env_prefix = "prod"
environment = "production"
env_name = "test"
vpc_cidr = "10.1.0.0/16"
public_subnet_cidrs = {
test-prod-nat = {
subnet = "10.1.15.0/24"
name = "test-prod-nat"
az = "ap-northeast-1a"
}
}
}
nat.tf
resource "aws_nat_gateway" "private" {
for_each = var.public_subnet_cidrs
allocation_id = aws_eip.nat_gateway.id
subnet_id = aws_subnet.public[each.key].id
tags = merge(
local.tags,
{
Name = format("%s_%s_%s", var.env_prefix, var.env_name, "nat-gateway")
}
)
lifecycle {
prevent_destroy = false
}
}
route_table.tf
/**
* for private subnet
*/
resource "aws_route_table" "private" {
vpc_id = aws_vpc.dandori.id
tags = merge(
local.tags,
{
Name = format("%s_%s", var.env_prefix, var.env_name)
}
)
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = [
for v in aws_nat_gateway.private : v.id
]
}
lifecycle {
prevent_destroy = false
}
}
When I run the terraform plan after creating the above tf file, I get the following Error
【Error】
╷
│ Error: Incorrect attribute value type
│
│ on ../modules/aws/vpc/route_table.tf line 55, in resource "aws_route_table" "private":
│ 55: nat_gateway_id = [
│ 56: for v in aws_nat_gateway.private : v.id
│ 57: ]
│ ├────────────────
│ │ aws_nat_gateway.private is object with 1 attribute "test-prod-nat"
│
│ Inappropriate value for attribute "nat_gateway_id": string required.
route_table.tf and nat.tf will be files in the module
I'm trying to set the nat_gateway_id in route_table.tf using the for loop method, but I can't set it correctly as shown in the Error message.
What should I do to solve this problem?
Please give me some advice.
If you want to create a route table for each aws_nat_gateway.private, then it should be:
resource "aws_route_table" "private" {
for_each = aws_nat_gateway.private
vpc_id = aws_vpc.dandori.id
tags = merge(
local.tags,
{
Name = format("%s_%s", var.env_prefix, var.env_name)
}
)
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = each.value["id"]
}
lifecycle {
prevent_destroy = false
}
}