Terraform AWS: Cannot output VPC endpoints. Unsupported attribute - amazon-web-services

I cannot output vpc endpoints. I got
module.vpc-endpoints-oregon is an object. This object does not have an attribute named "endpoints".
In the modules/vpc_endpoints folder, there are three files,
main.tf outputs.tf variables.tf
cat modules/vpc_endpoints/main.tf
module "vpc_endpoints" {
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
version = "3.16.0"
vpc_id = var.vpc_id
security_group_ids = [data.aws_security_group.default.id]
endpoints = {
s3 = {
service = "s3"
tags = { Name = "s3-vpc-endpoint" }
},
dynamodb = {
service = "dynamodb"
service_type = "Gateway"
route_table_ids = flatten([var.intra_route_table_ids,
var.private_route_table_ids,
var.public_route_table_ids])
policy = data.aws_iam_policy_document.dynamodb_endpoint_policy.json
tags = { Name = "dynamodb-vpc-endpoint" }
},
lambda = {
service = "lambda"
private_dns_enabled = true
subnet_ids = var.private_subnets
tags = { Name = "lambda-vpc-endpoint" }
},
}
}
cat modules/vpc_endpoints/outputs.tf
cat outputs.tf
# VPC endpoints
output "vpc_endpoints" {
description = "Array containing the full resource object and attributes for all endpoints created"
value = module.vpc_endpoints.endpoints
}
In the vpc_endpoints folder, there are three files,
main.tf outputs.tf variables.tf
cat main.tf
module "vpc-endpoints-oregon" {
source = "../../modules/vpc_endpoints"
#version = "3.16.0"
cluster_name = var.cluster_name
environment = var.environment
vpc_id = var.vpc_id
intra_route_table_ids = var.intra_route_table_ids
private_route_table_ids = var.private_route_table_ids
public_route_table_ids = var.public_route_table_ids
private_subnets = var.private_subnets
vpc_cidr_block = var.vpc_cidr_block
name_prefix = "vpc_tls"
}
cat outputs.tf:
output "vpc-endpoints-oregon" {
description = "Array containing the full resource object and attributes for all endpoints created"
value = module.vpc-endpoints-oregon.endpoints
}
terragrunt validate
Error: Unsupported attribute
on outputs.tf line 4, in output "vpc-endpoints-oregon":
4: value = module.vpc-endpoints-oregon.endpoints
module.vpc-endpoints-oregon is a object
This object does not have an attribute named "endpoints".
ERRO[0002] Terraform invocation failed in path-to/vpc_endpoints
ERRO[0002] 1 error occurred:
* exit status 1
Why does it claim This object does not have an attribute named "endpoints"?

The output is called vpc_endpoints, not endpoints. So it should be:
value = module.vpc-endpoints-oregon.vpc_endpoints

Related

Terraform unable to import transit gateway route

I am trying to import an existing transit gateway route to my terraform project.
my setup is like this:
resource "aws_ec2_transit_gateway" "tgw" {
description = "gateway for vpn"
tags = {
"Name" = "openvpn-gateway"
"managed_by_terraform" = "true"
}
}
resource "aws_ec2_transit_gateway_vpc_attachment" "tgw-attachments-private-vpc" {
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
vpc_id = var.private-vpc-id
subnet_ids = var.private-vpc-subnets
tags = {
"Name" = "private-vpc-gateway-attachment"
"managed_by_terraform" = "true"
}
}
resource "aws_ec2_transit_gateway_route_table" "tgw-route-table" {
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
tags = {
"Name" = "openvpn-gateawy-route-table"
"managed_by_terraform" = "true"
}
}
resource "aws_ec2_transit_gateway_route" "private-vpc-route" {
destination_cidr_block = var.private-vpc-cidr
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.tgw-attachments-private-vpc.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.tgw-route-table.id
}
And this configuration is on a module named gateway, for the import command I tried:
terraform import
'module.gateway.aws_ec2_transit_gateway_route.private-vpc-route'
'tgw-rtb-xxx_10.0.0.0/16'
as the documentation says at this page: documantation
but I am getting the following error:
Error: Cannot import non-existent remote object │ │ While attempting
to import an existing object to
"module.gateway.aws_ec2_transit_gateway_route.private-vpc-route", the
provider detected that no object exists with the given id. Only
pre-existing objects can be imported; check that the id is correct and
that it is associated with the provider's configured region or │
endpoint, or use "terraform apply" to create a new remote object for
this resource.
I have double checked transit gateway route table id and destination cidr block and active region.
edit: This is how I use the module:
module "vpc" {
source = "../modules/vpc"
public-subnets-name = var.public-subnets-name
public-subnets-cidr = var.public-subnets-cidr
private-cidr = var.private-cidr
private-subnets-name = var.private-subnets-name
private-subnets-cidr = var.private-subnets-cidr
igw-id = module.gateway.igw-id
private-igw-id = module.gateway.private-igw-id
tg-id = module.gateway.tgw-id
pcx-id = var.pcx-id
nat-id = module.gateway.nat-id
development-private-vpc-cidr = var.development-private-vpc-cidr
}
module "gateway" {
source = "../modules/gateway"
public-vpc-id = module.vpc.public-vpc-id
public-vpc-cidr = var.public-cidr
private-vpc-id = module.vpc.private-vpc-id
private-vpc-cidr = var.private-cidr
nat-subnet = module.vpc.private-vpcs_public-subnet-id
nat-allocation = var.nat-allocation
private-vpc-subnets = module.vpc.private-vpc-subnet_ids
public-vpc-subnets = module.vpc.public-vpc-subnet_ids
}

getting error while using list(string) data type in terraform module

I am trying to create 2 subnets in aws (with terraform) by passing 2 values in single variable.
Getting below error while executing "terraform validate" command
Please guide me how to correctly define list(string) variable data type in terraform module and correctly use it.
│ Error: Invalid value for input variable
│
│ on usage-test.tf line 11, in module "vpc_module":
│ 11: subnet_cidr_block = ["10.0.0.0/24","10.0.1.0/24"]
│
│ The given value is not suitable for module.vpc_module.var.subnet_cidr_block declared at vpc/var-test.tf:21,1-29: string required.
╵
╷
│ Error: Invalid value for input variable
│
│ on usage-test.tf line 12, in module "vpc_module":
│ 12: subnet_az = ["ap-south-1a","ap-south-1b"]
│
│ The given value is not suitable for module.vpc_module.var.subnet_az declared at vpc/var-test.tf:25,1-21: string required.
╵
refer terraform files below:-
variable.tf:
variable "subnet_cidr_block" {
type = list(string)
}
variable "subnet_az" {
type = list(string)
}
main.tf:
resource "aws_subnet" "mysubnet_public" {
vpc_id = aws_vpc.myvpc.id
cidr_block = var.subnet_cidr_block
availability_zone = var.subnet_az
map_public_ip_on_launch = "true"
depends_on = [aws_internet_gateway.mygw]
}
usage.tf
provider "aws" {
region = "ap-south-1"
}
module "vpc_module" {
source = "./vpc"
vpc_cider_block = "10.0.0.0/16"
vpc_name = "myvpc"
route_table_name = "myrt"
subnet_cidr_block = ["10.0.0.0/24","10.0.1.0/24"]
subnet_az = ["ap-south-1a","ap-south-1b"]
# subnet_cidr_block = "10.0.0.0/24"
# subnet_az = "ap-south-1a"
# subnet_public_name = "mysubnet_public"
sg_mgmt_name = "mysg_mgmt"
}
Well, the error is pretty clear. You cannot use a list of strings, rather a single string value, as the provider documentation also shows [1]:
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24" # <---- A single string value, not a list of strings
tags = {
Name = "Main"
}
}
As a hint for the future: the argument is singular, i.e., cidr_block so that usually means it's a single value.
[1] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet#basic-usage
Thank you #Marko E for your suggestion
after some research found solution for this issue, refer below code.:-
main.tf
#below code is for creating multiple subnets
resource "aws_subnet" "mysubnet_public" {
count = length(var.public_subnet_cidr)
vpc_id = aws_vpc.myvpc.id
cidr_block = element(var.public_subnet_cidr,count.index)
availability_zone = element(var.azs,count.index)
map_public_ip_on_launch = true
tags = {
Name = "Subnet-${count.index+1}"
}
}
#below code is for associating above created multiple subnets to route table
resource "aws_route_table_association" "myroutetableassociation_public" {
count = length(var.public_subnet_cidr)
subnet_id = element(aws_subnet.mysubnet_public[*].id, count.index)
route_table_id = aws_route_table.myroutetable_public.id
}
output.tf
output "mysubnet_public" {
description = "List of IDs of public route tables"
value = aws_subnet.mysubnet_public[*].id
}
output "myroutetableassociation_public" {
value = aws_route_table_association.myroutetableassociation_public[*].id
}
variable.tf
variable "public_subnet_cidr" {
type = list
}
variable "azs" {
type = list
}
usage.tf
provider "aws" {
region = "ap-south-1"
}
module "vpc_module" {
source = "./vpc"
vpc_name = "myvpc"
public_subnet_cidr = ["10.0.0.0/24", "10.0.1.0/24"]
azs = ["ap-south-1a", "ap-south-1b"]
}

"Error: Invalid count argument" error when trying to find the routing table' s id from the subnet ids to add new route entries

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.
╵

Terraform code for creating AWS EC2 instances with volumes

I'm trying to create two EC2 instances on AWS with the following features:
Instance: Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
Type: ami for 64-bit x86 us-east-1 region ami-0747bdcabd34c712a (64-bit x86)
Type: 2 processors, 8 GB Memory, Up to 10 Gigabit Network, m5a type m5a.large
Number of instances: 2
Storage: 20 GB General Purpose SSD, Delete storage on termination
Tags: Name=lfs258_class
Allow all traffic from everywhere
Use the existing SSH Keypair I have on my laptop
This is the tree file structure
.
├── README.md
├── ec2.tf
├── outputs.tf
├── provider.tf
├── variables.tf
└── versions.tf
file ec2.tf
locals {
availability_zone = "${local.region}a"
name = "kubernetes-lfs258-course"
region = "us-east-1"
tags = {
Owner = "pss-cli-user1 "
Environment = "kubernetes-lfs258-course"
}
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.0"
name = local.name
azs = ["${local.region}a", "${local.region}b", "${local.region}c"]
public_subnets = lookup(var.init,"public-subnet")
tags = local.tags
}
module "security_group" {
source = "terraform-aws-modules/security-group/aws"
version = "~> 4.0"
name = local.name
description = "Security group for example usage with EC2 instance"
vpc_id = module.vpc.vpc_id
ingress_cidr_blocks = ["0.0.0.0/0"]
ingress_rules = ["all-all"]
egress_rules = ["all-all"]
tags = local.tags
}
################################################################################
# Supporting Resources for the EC2 module
################################################################################
module "ec2" {
source = "../../"
name = local.name
ami = lookup(var.init,"ami")
#instance_type = "c5.large"
instance_type = lookup(element(var.instances,0),"instance_type")
availability_zone = local.availability_zone
subnet_id = element(module.vpc.private_subnets, 0)
vpc_security_group_ids = [module.security_group.security_group_id]
associate_public_ip_address = true
tags = local.tags
}
resource "aws_volume_attachment" "this" {
device_name = "/dev/sdh"
volume_id = aws_ebs_volume.this.id
instance_id = module.ec2.id
}
resource "aws_ebs_volume" "this" {
availability_zone = local.availability_zone
size = 20
tags = local.tags
}
file outputs.tf
# EC2
output "ec2_id" {
description = "The ID of the instance"
value = module.ec2.id
}
output "ec2_arn" {
description = "The ARN of the instance"
value = module.ec2.arn
}
output "ec2_capacity_reservation_specification" {
description = "Capacity reservation specification of the instance"
value = module.ec2.capacity_reservation_specification
}
output "ec2_instance_state" {
description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`"
value = module.ec2.instance_state
}
output "ec2_primary_network_interface_id" {
description = "The ID of the instance's primary network interface"
value = module.ec2.primary_network_interface_id
}
output "ec2_private_dns" {
description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC"
value = module.ec2.private_dns
}
output "ec2_public_dns" {
description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC"
value = module.ec2.public_dns
}
output "ec2_public_ip" {
description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached"
value = module.ec2.public_ip
}
output "ec2_tags_all" {
description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block"
value = module.ec2.tags_all
}
file provider. tf
provider "aws" {
region = local.region
profile = "pss-cli-user1"
shared_credentials_file = "~/.aws/credentials"
}
file variables.tf
# This file defines variables types and their initial hardcoded values
variable "zones" {
type = list(string)
default = ["us-east-1a", "us-east-1b"]
}
variable "instances" {
type = list(object({
instance_type = string
count = number
tags = map(string)
}))
# If instances is not defined in terraforms.tfvars use this value
default = [
{
instance_type = "m5a.large"
count = 2
tags = { "UsedFor" = "kubernetes lfs258 course"}
}
]
}
variable "init" {
type = object({
vpc-id=list(string),
public-subnet=list(string),
aws_region=string,
ami=string
vpc-sec-group= list(string)
})
# if not defined in terraform.tfvars takes this default
default = {
vpc-id = ["vpc-02938578"]
public-subnet = ["subnet-94e25d9a"]
aws_region = "us-east-1"
ami = "ami-0747bdcabd34c712a"
vpc-sec-group = ["sg-d60bf3f5"]
}
}
file versions.tf
terraform {
required_version = ">= 0.13.1"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 3.51"
}
}
}
The command terraform init works without errors
However terraform plan is giving me the following complains
╷
│ Error: Unsupported argument
│
│ on ec2.tf line 41, in module "ec2":
│ 41: name = local.name
│
│ An argument named "name" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on ec2.tf line 43, in module "ec2":
│ 43: ami = lookup(var.init,"ami")
│
│ An argument named "ami" is not expected here.
..... more errors like this removed
Questions are :
What am I doing wrong and how to fix it ?
How to create a better IaC Terraform deployment?
BR
David

Terraform using output from module

I just started with Terraform infrastructure. Trying to create a vpc module that will contain code for vpc, subnets, internet gateway, rout table. Also creating a separate tf file for rds , which will refer to the vpc module and utilize the private subnets declared in vpc module.
Created a vpc module that has vpc.tf with following
provider "aws" {
region = var.region
}
terraform {
backend "s3" {}
}
resource "aws_vpc" "production-vpc" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
Name = "Dev-VPC"
}
}
// Private Subnets
resource "aws_subnet" "private-subnet-1" {
cidr_block = var.private_subnet_1_cidr
vpc_id = aws_vpc.production-vpc.id
availability_zone = "us-east-1a"
tags = {
Name = "Private-Subnet-1"
}
}
resource "aws_subnet" "private-subnet-2" {
cidr_block = var.private_subnet_2_cidr
vpc_id = aws_vpc.production-vpc.id
availability_zone = "us-east-1b"
tags = {
Name = "Private-Subnet-2"
}
}
The output.tf has following
output "private-subnet1-id" {
description = "Private Subnet1 Id"
value = aws_subnet.private-subnet-1.*.id
}
output "private-subnet2-id" {
description = "Private Subnet2 Id"
value = aws_subnet.private-subnet-2.*.id
}
The file is saved in folder \module\vpc folder
Created rds.tf as follows in folder \rds
provider "aws" {
region = var.region
}
terraform {
backend "s3" {}
}
module "vpc" {
source = "../module/vpc"
}
resource "aws_db_subnet_group" "subnetgrp" {
name = "dbsubnetgrp"
subnet_ids = [module.vpc.private-subnet1-id.id, module.vpc.private-subnet2-id.id]
}
When I run terraform plan , I get following error
Error: Unsupported attribute
on rds.tf line 16, in resource "aws_db_subnet_group" "subnetgrp":
16: subnet_ids = [module.vpc.private-subnet1-id.id, module.vpc.private-subnet2-id.id]
|----------------
| module.vpc.private-subnet1-id is tuple with 1 element
This value does not have any attributes.
Error: Unsupported attribute
on rds.tf line 16, in resource "aws_db_subnet_group" "subnetgrp":
16: subnet_ids = [module.vpc.private-subnet1-id.id, module.vpc.private-subnet2-id.id]
|----------------
| module.vpc.private-subnet2-id is tuple with 1 element
This value does not have any attributes.
You don't need the splat expression in the output.tf. Try the following,
output "private-subnet1-id" {
description = "Private Subnet1 Id"
value = aws_subnet.private-subnet-1.id
}
output "private-subnet2-id" {
description = "Private Subnet2 Id"
value = aws_subnet.private-subnet-2.id
}