I have came up with below:
resource "aws_network_interface" "eni_carl" {
subnet_id = module.vpc.public_subnets[3]
private_ip = "10.0.4.1/32"
security_groups = [module.vpc.ssh_sg]
}
resource "aws_instance" "carl" {
ami = var.ami
instance_type = "t2.micro"
key_name = var.key_name
network_interface {
network_interface_id = aws_network_interface.eni_carl.id
device_index = 0
}
}
But aws will randomly assign private ip for my instance. How can I achieve generating the same and fixed private ip address for my instance?
Terraform v1.3.4
on linux_amd64
provider registry.terraform.io/hashicorp/aws v4.39.0
From aws_instance | Resources | hashicorp/aws | Terraform Registry:
resource "aws_network_interface" "foo" {
subnet_id = aws_subnet.my_subnet.id
private_ips = ["172.16.10.100"]
tags = {
Name = "primary_network_interface"
}
}
Therefore, the parameter appears to be: private_ips = ["172.16.10.100"]
It takes an IP address instead of a CIDR block.
Related
Hello I'm trying to create multiple instance based on a count variable. I currently have 1 private subnet with 2 cidr blocks however when i try to create the instance i get
"Error: Error launching source instance: InvalidSubnetID.NotFound: The subnet ID '10.7.90.96/27' does not exist
status code: 400, request id: d7ef5147-ac30-4d31-815a-ad6a46bfe456
on .terraform\modules\vpc\AWS-VPC-Module\main.tf line 1427, in resource "aws_instance" "FID":
1427: resource "aws_instance" "FID" {"
when clearly the TF does create the subnets are present
resource "aws_instance" "FID" {
depends_on = [aws_kms_key.aws-wm-wmad-prod]
count = var.How_many_FID
ami = var.windows_dc_ami_2016
availability_zone = element(var.availability_zones, count.index)
ebs_optimized = var.windows_dc_ebs_optimized
instance_type = var.windows_dc_instance_type_FID
key_name = var.key_name
monitoring = true
subnet_id = element(var.private_subnet_cidr_blocks, count.index)
associate_public_ip_address = false
here is my subnet creation code:
resource "aws_subnet" "private" {
count = length(var.private_subnet_cidr_blocks) # count = 2
vpc_id = aws_vpc.default.id #id34odfjdf
cidr_block = var.private_subnet_cidr_blocks[count.index]
availability_zone = var.availability_zones[count.index]
tags = merge(
{
Name_TF = "dctr-ad-sbn-use1-az1A-prod-lan-0${count.index+1}",
Project = var.project,
Environment = var.environment
},
var.tags
)
}
subnet_id must be actual subnet id, not its CIDR:
subnet_id = element(aws_subnet.private, count.index).id
I need to create one EC2 and associate 2 subnets to it.
variables.tf
variable "aws_subnet_id_this" {
description = "Subnet ID"
default = ["subnet-09df122a4faee8882", "subnet-2fcc756f02ddb4b62"]
}
main.tf
resource "aws_instance" "test" {
ami = var.ami_id
instance_type = var.ec2_instance_type
subnet_id = var.aws_subnet_id_this
key_name = var.pki_name
vpc_security_group_ids = [aws_security_group.Allow_SSH_in.id]
}
Error:
Error: Incorrect attribute value type
on main_count_data.tf line 57, in resource "aws_instance" "test":
57: subnet_id = var.aws_subnet_id_this
|----------------
| var.aws_subnet_id_eks is tuple with 2 elements
Inappropriate value for attribute "subnet_id": string required.
So I tried this:
main.tf
resource "aws_instance" "prueba" {
ami = var.ami_id
instance_type = var.ec2_instance_type
#subnet_id = var.aws_subnet_id_this
count = 2
subnet_id = "${element(var.aws_subnet_id_this, count.index)}"
key_name = var.pki_name
vpc_security_group_ids = [aws_security_group.Allow_SSH_in.id]
}
}
but this last portion of code tries to create a new EC2 instance with the second subnet and this is not what I expect tough.
To sum up: I need 1 EC2 containing 2 subnets defined in the variables.tf file.
How can I do this?
Below is an example of how you can create one instance with two NICs in different subnets. The NICs must be in same AZ. So instance can have two NICs in different subnets as long as they are in same AZ:
variable "aws_subnet_id_this" {
description = "Subnet ID"
default = ["subnet-09df122a4faee8882", "subnet-2fcc756f02ddb4b62"]
}
resource "aws_network_interface" "nic1" {
subnet_id = var.aws_subnet_id_this[0]
}
resource "aws_network_interface" "nic2" {
subnet_id = var.aws_subnet_id_this[1]
}
resource "aws_instance" "prueba" {
ami = var.ami_id
instance_type = var.ec2_instance_type
key_name = var.pki_name
network_interface {
device_index = 0
network_interface_id = aws_network_interface.nic1.id
}
network_interface {
device_index = 1
network_interface_id = aws_network_interface.nic2.id
}
}
Is it possible to create an EC2 instance while reusing already existing VPC?
Running the following code yields Error launching source instance: VPCIdNotSpecified: No default VPC for this user. GroupName is only supported for EC2-Classic and default VPC. (status code: 400):
data "aws_security_groups" "my_tib_sg" {
tags = {
Name = "my-security-group"
}
}
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]
# more, irrelevant stuff...
}
FWIU from the error, the aws_instance block requires a reference to my VPC, which basically exists in my security group. Besides, I can't find a way to refer a VPC in an aws_instance block.
Updating code per answers:
I updated the code per answers below:
data "aws_security_groups" "my_tib_sg" {
tags = {
Name = "my-tib-sg"
}
}
data "aws_subnet" "my_subnet" {
tags = {
Name = "my-tib-subnet-1"
}
}
resource "aws_network_interface" "my_ani" {
subnet_id = data.aws_subnet.my_subnet.id
private_ips = ["10.0.0.10"]
tags = {
Name = "my-tib-ani"
by = "TF_TF"
}
}
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]
network_interface {
network_interface_id = aws_network_interface.my_ani.id
device_index = 0
}
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"
]
}
}
But the error changes to "network_interface": conflicts with vpc_security_group_ids.
(needless to mention: both my_subnet and my_tib_sg use same VPC)
I typically use the subnet_id parameter, directly on the aws_instance resource:
data "aws_security_groups" "my_tib_sg" {
tags = {
Name = "my-tib-sg"
}
}
data "aws_subnet" "my_subnet" {
tags = {
Name = "my-tib-subnet-1"
}
}
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.ids[0]]
# specify the subnet_id here
subnet_id = data.aws_subnet.my_subnet.id
# more, irrelevant stuff...
}
Yes, you can add a new EC2 instance to an existing VPC.
You should provide the subnet_id to aws_instance. You would typically pass that into Terraform as a parameter, rather than hard-coding its value into your template.
Note: the subnet ID implicitly indicates the actual VPC (because a subnet only exists in one VPC).
Is it possible to create an EC2 instance while reusing already existing VPC?
yes you can create an ec2 instance with an existing VPC. You can use a Data Source: aws_vpc to query existing VPC and then further reference the same in your resource like Resource: aws_instance below:
variable "vpc_id" {}
data "aws_vpc" "selected" {
id = var.vpc_id
}
resource "aws_subnet" "example" {
vpc_id = data.aws_vpc.selected.id
availability_zone = "us-west-2a"
cidr_block = cidrsubnet(data.aws_vpc.selected.cidr_block, 4, 1)
}
resource "aws_security_group" "allow_tls" {
name = "allow_tls"
description = "Allow TLS inbound traffic"
vpc_id = data.aws_vpc.selected.id
ingress {
description = "TLS from VPC"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [aws_vpc.main.cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "allow_tls"
}
}
resource "aws_network_interface" "foo" {
subnet_id = aws_subnet.example.id
private_ips = ["172.16.10.100"]
security_groups = [aws_security_group.allow_tls.id]
tags = {
Name = "primary_network_interface"
}
}
resource "aws_instance" "foo" {
ami = "ami-005e54dee72cc1d00" # us-west-2
instance_type = "t2.micro"
network_interface {
network_interface_id = aws_network_interface.foo.id
device_index = 0
}
credit_specification {
cpu_credits = "unlimited"
}
}
I currently have multiple subnets created within a VPC for each availability zone within a region. I am now trying to create one EC2 instance per subnet within each availability zone, and am running into an issue. Below is my code, I am having some trouble getting the subnet ID to attach to EC2 instances. Any advice would be appreciated.
Instance
resource "aws_instance" "public" {
for_each = aws_subnet.public
ami = data.aws_ami.ec2.id
instance_type = var.tableau_instance
key_name = aws_key_pair.main.key_name
subnet_id = [for subnet in aws_subnet.public : subnet.id]
}
Subnet
locals {
az_names = data.aws_availability_zones.azs.names
}
resource "aws_subnet" "public" {
for_each = { for index, az_name in local.az_names : index => az_name }
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, each.key + 1)
availability_zone = local.az_names[each.key]
map_public_ip_on_launch = true
tags = {
Name = "${var.vpc_tags}_PubSubnet"
}
}
Error
Error: Incorrect attribute value type
on vpc.tf line 18, in resource "aws_instance" "public":
18: subnet_id = [for subnet in aws_subnet.public : subnet.id]
|----------------
| aws_subnet.public is object with 3 attributes
Inappropriate value for attribute "subnet_id": string required.
The instance code should be as follows:
resource "aws_instance" "public" {
for_each = aws_subnet.public
ami = data.aws_ami.ec2.id
instance_type = var.tableau_instance
key_name = aws_key_pair.main.key_name
subnet_id = each.value.id
}
This will place 1 instance in each subnet.
I'm trying to create an aws instance with an aws_network_interface as below:
resource "aws_network_interface" "lustre-mds01" {
subnet_id = "${var.subnet_id}"
private_ips = ["10.1.0.10"]
}
resource "aws_instance" "lustre-mds01" {
ami = "${var.ec2_ami}"
instance_type = "t2.nano"
key_name = "${var.key_name}"
vpc_security_group_ids = [ "${var.vpc_security_group_id}" ]
root_block_device {
volume_type = "gp2"
volume_size = 128
}
network_interface {
network_interface_id = "${aws_network_interface.lustre-mds01.id}"
device_index = 0
}
}
However, this results in:
Error: "network_interface": conflicts with vpc_security_group_ids
It appears there is an issue for this, but the ticket was closed due to inactivity. I'm a terraform noob, so I'm not sure if this looks like a bug or is just user error.
My environment:
$ terraform -v
Terraform v0.12.2
+ provider.aws v2.15.0
+ provider.external v1.1.2
+ provider.local v1.2.2
+ provider.null v2.1.2
The aws_network_interface resource allows you to set the security group for the interface (security groups are scoped by the ENI so this makes sense) so if you define the network_interface block then you're overriding the default ENI and so can't specify security groups at the instance level.
So in your case you probably want something like:
resource "aws_network_interface" "lustre-mds01" {
subnet_id = "${var.subnet_id}"
private_ips = ["10.1.0.10"]
security_groups = ["${var.vpc_security_group_id}"]
}
resource "aws_instance" "lustre-mds01" {
ami = "${var.ec2_ami}"
instance_type = "t2.nano"
key_name = "${var.key_name}"
root_block_device {
volume_type = "gp2"
volume_size = 128
}
network_interface {
network_interface_id = "${aws_network_interface.lustre-mds01.id}"
device_index = 0
}
}
However, I would question why you are replacing the default ENI here when it's much simpler to just set the private IP address of the instance directly in the aws_instance resource instead:
resource "aws_instance" "lustre-mds01" {
ami = "${var.ec2_ami}"
instance_type = "t2.nano"
key_name = "${var.key_name}"
subnet_id = "${var.subnet_id}"
private_ip = "10.1.0.10"
vpc_security_group_ids = ["${var.vpc_security_group_id}"]
root_block_device {
volume_type = "gp2"
volume_size = 128
}
}
You would also probably benefit from using data sources to select your security group and AMI instead of passing in opaque IDs for these. This allows them to be more self documenting.