How to use terraform with environment variables in .tf file - amazon-web-services

I am new to Terraform and I ran into some issue when trying to use environment variables with .tf file, I tried to use terraform.tfvars / variables.tf.
./terraform apply -var-file="terraform.tfvars"
Failed to load root config module: Error parsing variables.tf: At 54:17: illegal char
What am I missing here?
Terraform Version: Terraform v0.9.2
main.tf:
provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region = "${var.aws_region}"
allowed_account_ids = ["${var.aws_account_id}"]
}
resource "aws_instance" "db" {
ami = "ami-49c9295"
instance_type = "t2.micro"
tags {
Name = "test"
}
connection {
user = "ubuntu"
}
security_groups = ["sg-ccc943b0"]
availability_zone = "${var.availability_zone}"
subnet_id = "${var.subnet_id}"
}
terraform.tfvars:
aws_profile = "default"
aws_access_key = "xxxxxx"
aws_secret_key = "xxxxxx"
aws_account_id = "xxxxxx"
key_name = "keyname"
key_path = "/home/user/.ssh/user.pem"
aws_region = "us-east-1"
subnet_id = "subnet-51997e7a"
vpc_security_group_ids = "mysql"
instance_type = "t2.xlarge"
availability_zone = "us-east-1a"
variables.tf:
variable "key_name" {
description = "Name of the SSH keypair to use in AWS."
default = "keypairname"
}
variable "key_path" {
description = "Path to the private portion of the SSH key specified."
default = "/home/user/.ssh/mypem.pem"
}
variable "aws_region" {
description = "AWS region to launch servers."
default = "us-east-1"
}
variable "aws_access_key" {
decscription = "AWS Access Key"
default = "xxxxxx"
}
variable "aws_secret_key" {
description = "AWS Secret Key"
default = "xxxxxx"
}
variable "aws_account_id" {
description = "AWS Account ID"
default = "xxxxxx"
}
variable "subnet_id" {
description = "Subnet ID to use in VPC"
default = "subnet-51997e7a"
}
variable "vpc_security_group_ids" {
description = "vpc_security_group_ids"
default = "sec"
}
variable "instance_type" {
description = "Instance type"
default = "t2.xlarge"
}
variable "instance_name" {
description = "Instance Name"
default = "test"
}
variable "availability_zone" {
description = "availability_zone"
default = "us-east-1a"
}
variable "aws_amis" {
default = {
"us-east-1": "ami-49c9295f",
"eu-west-1": "ami-49c9295f",
"us-west-1": "ami-49c9295f",
"us-west-2": "ami-49c9295f"
}
}
Update
After removing variable "aws_amis" section from variables.tf, I ran into another issue:
Failed to load root config module: Error loading variables.tf: 1 error(s) occurred:
* variable[aws_access_key]: invalid key: decscription

The aws_amis variable being used as a lookup map looks incorrectly formatted to me. Instead it should probably be of the format:
variable "aws_amis" {
default = {
us-east-1 = "ami-49c9295f"
eu-west-1 = "ami-49c9295f"
us-west-1 = "ami-49c9295f"
us-west-2 = "ami-49c9295f"
}
}
As an aside Terraform will look for a terraform.tfvars file by default so you can drop the -var-file="terraform.tfvars". You'll need to pass the -var-file option if you want to use a differently named file (such as prod.tfvars) but for this you can omit it.

Related

Terraform - I can not create EC2 instance using SG module

Could u please let me know why I'm not able to create a EC2 using a SG module that I built?
I'm getting the following error
Error: creating EC2 Instance: VPCIdNotSpecified: No default VPC for this user. GroupName is only supported for EC2-Classic and default VPC.
│ status code: 400, request id: e91aa79f-0d8f-44ec-84df-ba22cd3307d8
Indeed I don't wanna use a default VPC, follow below my main code:
module "vpc" {
source = "../modules/vpc/"
region = var.region
awsprofile = var.awsprofile
vpcname = var.vpcname
subnetaz1 = var.subnetaz1
subnetaz2 = var.subnetaz2
subnetaz3 = var.subnetaz3
private1_cidr = var.private1_cidr
private2_cidr = var.private2_cidr
private3_cidr = var.private3_cidr
public1_cidr = var.public1_cidr
public2_cidr = var.public2_cidr
public3_cidr = var.public3_cidr
vpc_cidr = var.vpc_cidr
}
module "security" {
source = "../modules/security/"
public_sg_name = var.public_sg_name
ingress_ports = var.ingress_ports
internet_access = var.internet_access
vpc_id = module.vpc.aws_vpc_id
}
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
resource "aws_instance" "web" {
count = var.instance_count
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_size
associate_public_ip_address = "true"
key_name = var.key_name
security_groups = [module.security.sg_name]
tags = {
Name = "${var.instance_name}-1"
}
}
In the "security_groups" I'm trying to get the output from security group module however unsucessfully.
output "sg_id" {
value = aws_security_group.PublicSG.id
}
output "sg_name" {
value = aws_security_group.PublicSG.name
}
Does anyone has any idea why it is not working?
Instead of security_groups you should be using vpc_security_group_ids:
resource "aws_instance" "web" {
count = var.instance_count
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_size
associate_public_ip_address = "true"
key_name = var.key_name
vpc_security_group_ids = [module.security.sg_id]
tags = {
Name = "${var.instance_name}-1"
}
}

Using data for existing resource (security group), getting: A managed resource has not been declared in the root module

Learning Terraform, I'm trying to bring up an EC2 instance, reusing existing security group (tagged my-tib-sg).
I'm getting the following error, and not sure what I'm doing wrong:
Error: Reference to undeclared resource
on module_three.tf line 62, in resource "aws_instance" "nginx":
62: vpc_security_group_ids = [aws_security_groups.my-tib-sg.id]
A managed resource "aws_security_groups" "my-tib-sg" has not been declared in
the root module.
Here is the code:
##################################################################################
# VARIABLES
##################################################################################
variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "private_key_path" {}
variable "key_name" {}
variable "region" {
default = "us-east-1"
}
##################################################################################
# PROVIDERS
##################################################################################
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.region
}
##################################################################################
# DATA
##################################################################################
data "aws_ami" "aws-linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn-ami-hvm*"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
data "aws_security_groups" "my-tib-sg" {
tags = {
Name = "my-tib-sg"
}
}
##################################################################################
# RESOURCES
##################################################################################
resource "aws_instance" "nginx" {
ami = data.aws_ami.aws-linux.id
instance_type = "t2.micro"
key_name = var.key_name
vpc_security_group_ids = [aws_security_groups.my-tib-sg.id]
connection {
type = "ssh"
host = self.public_ip
user = "ec2-user"
private_key = file(var.private_key_path)
}
provisioner "remote-exec" {
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}
##################################################################################
# OUTPUT
##################################################################################
output "aws_instance_public_dns" {
value = aws_instance.nginx.public_dns
}
When referring to data sources you need to prefix the address with data. to differentiate between data sources and resources.
So in your case you should use data.aws_security_groups.my-tib-sg.id like so:
##################################################################################
# VARIABLES
##################################################################################
variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "private_key_path" {}
variable "key_name" {}
variable "region" {
default = "us-east-1"
}
##################################################################################
# PROVIDERS
##################################################################################
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.region
}
##################################################################################
# DATA
##################################################################################
data "aws_ami" "aws-linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn-ami-hvm*"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
data "aws_security_groups" "my-tib-sg" {
tags = {
Name = "my-tib-sg"
}
}
##################################################################################
# RESOURCES
##################################################################################
resource "aws_instance" "nginx" {
ami = data.aws_ami.aws-linux.id
instance_type = "t2.micro"
key_name = var.key_name
vpc_security_group_ids = [data.aws_security_groups.my-tib-sg.id]
connection {
type = "ssh"
host = self.public_ip
user = "ec2-user"
private_key = file(var.private_key_path)
}
provisioner "remote-exec" {
inline = [
"sudo yum install nginx -y",
"sudo service nginx start"
]
}
}

How to assign an AWS Elastic IP to a newly created EC2 instance with Terraform without it getting reassigned when another instance is created?

I currently have the following Terraform plan:
provider "aws" {
region = var.region
}
resource "aws_instance" "ec2" {
ami = var.ami
instance_type = var.instanceType
subnet_id = var.subnet
security_groups = var.securityGroups
timeouts {
create = "2h"
delete = "2h"
}
tags = {
Name = "${var.ec2ResourceName}"
CoreInfra = "false"
}
lifecycle {
prevent_destroy = true
}
key_name = "My_Key_Name"
connection {
type = "ssh"
user = "ec2-user"
password = ""
private_key = file(var.keyPath)
host = self.public_ip
}
provisioner "file" {
source = "/home/ec2-user/code/backend/ec2/setup_script.sh"
destination = "/tmp/setup_script.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/setup_script.sh",
"bash /tmp/setup_script.sh ${var.ec2ResourceName}"
]
}
}
resource "aws_eip" "eip_manager" {
name = "eip-${var.ec2ResourceName}"
instance = aws_instance.ec2.id
vpc = true
tags = {
Name = "eip-${var.ec2ResourceName}"
}
lifecycle {
prevent_destroy = true
}
}
This plan can be run multiple times, creating a single EC2 instance each time without removing the previous one. However, there is a single Elastic IP that ends up being reassigned to the most recently-created EC2 instance. How can I add an Elastic IP to each new instance that does not get reassigned?
maybe with aws_eip_association, here is the snippet:
resource "aws_eip_association" "eip_assoc" {
instance_id = aws_instance.ec2.id
allocation_id = aws_eip.eip_manager.id
}
More info here: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip_association

Terraform 0.12.13 - Not able to spin AWS instance

AWS EC2 instance creation is failing while creating a network interface in the aws_instance section. The configuration is following configuration as defined in Terraform Network Interfaces
Configuration.
On removing the network block the configuration works seamlessly. With network block the following error was logged
"Error: Error launching source instance: Unsupported: The requested configuration is currently not supported. Please check the documentation for supported configurations."
variable "aws_region" {}
variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "vpc_cidr_block" {}
variable "environment" {}
variable "applicationtype" {}
variable "subnet_cidr_block" {}
variable "amiid" {}
variable "instancetype" {}
variable "bucketname" {}
variable "publickey-fe" {}
variable "publickey-be" {}
provider "aws" {
profile = "default"
region = "${var.aws_region}"
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
}
data "aws_availability_zones" "availability" {
state = "available"
}
resource "aws_vpc" "sitespeed_vpc" {
cidr_block = "${var.vpc_cidr_block}"
instance_tenancy = "dedicated"
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
Name = "site-speed-VPC"
}
}
resource "aws_subnet" "sitespeed_subnet" {
vpc_id = "${aws_vpc.sitespeed_vpc.id}"
cidr_block = "${var.subnet_cidr_block}"
availability_zone = "${data.aws_availability_zones.availability.names[0]}"
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
Name = "site-speed-Subnet"
}
}
resource "aws_network_interface" "sitespeed_frontend_NIC" {
subnet_id = "${aws_subnet.sitespeed_subnet.id}"
private_ips = ["192.168.10.100"]
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
Name = "site-speed-frontend-nic"
}
}
resource "aws_network_interface" "sitespeed_backend_NIC" {
subnet_id = "${aws_subnet.sitespeed_subnet.id}"
private_ips = ["192.168.10.110"]
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
Name = "site-speed-backend-nic"
}
}
resource "aws_key_pair" "sitespeed_front_key" {
key_name = "site_speed_front_key"
public_key = "${var.publickey-fe}"
}
resource "aws_key_pair" "sitespeed_back_key" {
key_name = "site_speed_back_key"
public_key = "${var.publickey-be}"
}
resource "aws_instance" "sitespeed_front" {
ami = "ami-00942d7cd4f3ca5c0"
instance_type = "t2.micro"
key_name = "site_speed_front_key"
availability_zone = "${data.aws_availability_zones.availability.names[0]}"
network_interface {
network_interface_id = "${aws_network_interface.sitespeed_frontend_NIC.id}"
device_index = 0
}
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
Name = "site-speed-frontend-server"
public = "yes"
}
}
resource "aws_instance" "sitespeed_backend" {
ami = "ami-00942d7cd4f3ca5c0"
instance_type = "t2.micro"
key_name = "site_speed_back_key"
network_interface {
network_interface_id = "${aws_network_interface.sitespeed_backend_NIC.id}"
device_index = 0
}
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
Name = "site-speed-backend-server"
public = "No"
}
}
resource "aws_s3_bucket" "b" {
bucket = "${var.bucketname}"
acl = "private"
tags = {
env = "${var.environment}"
application = "${var.applicationtype}"
}
}
The issue was due to the Terraform Version. Following is the updated script that supports Terraform V.0.12.16 to create an EC2 Instance on AWS.
// Variable Definition
variable "aws_region" {}
variable "aws_vpc_cidr_block" {}
variable "aws_subnet_cidr_block" {}
variable "aws_private_ip_fe" {}
variable "aws_Name" {}
variable "aws_Application" {}
variable "aws_ami" {}
variable "aws_instance_type" {}
// Provider Definition
provider "aws" {
version = "~> 2.40"
region = var.aws_region
}
// Adds a VPC
resource "aws_vpc" "aws_ec2_deployment_test-vpc" {
cidr_block = var.aws_vpc_cidr_block
tags = {
Name = join("-", [var.aws_Name, "vpc"])
Application = var.aws_Application
}
}
//Adds a subnet
resource "aws_subnet" "aws_ec2_deployment_test-subnet" {
vpc_id = aws_vpc.aws_ec2_deployment_test-vpc.id
cidr_block = var.aws_subnet_cidr_block
availability_zone = join("", [var.aws_region, "a"])
tags = {
Name = join("-", [var.aws_Name, "subnet"])
Application = var.aws_Application
}
}
//Adds a Network Interface
resource "aws_network_interface" "aws_ec2_deployment_test-fe" {
subnet_id = aws_subnet.aws_ec2_deployment_test-subnet.id
private_ips = [ var.aws_private_ip_fe ]
tags = {
Name = join("-", [var.aws_Name, "network-interface-fe"])
Application = var.aws_Application
}
}
//Adds an EC2 Instance
resource "aws_instance" "aws_ec2_deployment_test-fe"{
ami = var.aws_ami
instance_type = var.aws_instance_type
network_interface {
network_interface_id = aws_network_interface.aws_ec2_deployment_test-fe.id
device_index = 0
}
tags = {
Name = join("-", [var.aws_Name, "fe-ec2"])
Application = var.aws_Application
}
}
// Print Output Values
output "aws_ec2_deployment_test-vpc" {
description = "CIDR Block for the VPC: "
value = aws_vpc.aws_ec2_deployment_test-vpc.cidr_block
}
output "aws_ec2_deployment_test-subnet" {
description = "Subnet Block: "
value = aws_subnet.aws_ec2_deployment_test-subnet.cidr_block
}
output "aws_ec2_deployment_test-private-ip" {
description = "System Private IP: "
value = aws_network_interface.aws_ec2_deployment_test-fe.private_ip
}
output "aws_ec2_deployment_test-EC2-Details" {
description = "EC2 Details: "
value = aws_instance.aws_ec2_deployment_test-fe.public_ip
}
Gist link to the solution

Terraform lookup AWS region

I have the following code in my main.tf file:
provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region = "us-east-1"
alias = "us-east-1"
}
provider "aws" {
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
region = "us-west-1"
alias = "us-west-1"
}
module "us-east_vpc" {
source = "./setup-networking"
providers = {
"aws.region" = "aws.us-east-1"
}
}
module "us-west_vpc" {
source = "./setup-networking"
providers = {
"aws.region" = "aws.us-west-1"
}
}
And then in my modules file I have:
provider "aws" {
alias = "region"
}
resource "aws_vpc" "default" {
provider = "aws.region"
cidr_block = "${lookup(var.vpc_cidr, ${aws.region.region})}"
enable_dns_hostnames = true
tags {
Name = "AWS VPC"
}
}
resource "aws_internet_gateway" "default" {
provider = "aws.region"
vpc_id = "${aws_vpc.default.id}"
}
resource "aws_subnet" "default" {
provider = "aws.region"
vpc_id = "${aws_vpc.default.id}"
cidr_block = "${lookup(var.subnet_cidr, ${aws.region.region})}"
availability_zone = "aws.region"
tags {
Name = "AWS Subnet"
}
}
resource "aws_route_table" "default" {
provider = "aws.region"
vpc_id = "${aws_vpc.default.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.default.id}"
}
tags {
Name = "Main Gateway"
}
}
As you can see in the modules file code I am trying to do a lookup to find the VPC CIDR mask and the subnet CIDR mask from map variables.
The trouble is that I can't seem to sort out how to get the region to be used as a lookup value.
If I hard code these values:
cidr_block = "10.10.0.0/16"
cidr_block = "10.10.10.0/24"
The script works as expected but I don't want to hard code the values.
Can someone with more Terraform experience help me understand how I can properly reference the region to lookup the correct value?
I was looking for the same answer for a different problem. I wanted to get the region for a name of a role, I was able to get the info by doing this:
1.- Create a file like data.tf and add this info:
data "aws_region" "current" {}
2.- Get the info from the data by calling this variable in any TF file:
name = "${var.vpc-name}-${data.aws_region.current.name}-Bastion-Role"
This way it will get the region where you are executing the code, and you don't have to mess with the provider.tf file.
You can get the region that's currently in use by the provider by using the aws_region data source.
So in your case you could do something like this:
provider "aws" {
alias = "region"
}
data "aws_region" "current" {
provider = "aws.region"
}
resource "aws_vpc" "default" {
provider = "aws.region"
cidr_block = "${lookup(var.vpc_cidr, ${data.aws_region.current.name})}"
enable_dns_hostnames = true
tags {
Name = "AWS VPC"
}
}
...
provider "aws" {
alias = "region"
}
data "aws_region" "current" {
provider = "aws.region"
}
data "aws_availability_zone" "current" {
provider = "aws.region"
name = "${data.aws_region.current.name}a"
}
resource "aws_vpc" "default" {
provider = "aws.region"
cidr_block = "${lookup(var.vpc_cidr, data.aws_availability_zone.current.name)}"
enable_dns_hostnames = true
tags {
Name = "${data.aws_region.current.name} Security VPC1"
Region = "${data.aws_region.current.name}"
Account = "Security"
}
}