How do you launch an instance with EIP straight away? - amazon-web-services

Having trouble with attaching eip to ec2 instance. I can only do it be assigning public ip then after instance is built then attaching eip. I want to add the EIP before the instance builds.
resource "aws_instance" "third-WG" {
provider = aws.third
ami = data.aws_ami.ubuntu3.id
instance_type = "t2.micro"
key_name = aws_key_pair.third_WGkey.key_name
associate_public_ip_address = true
private_ip = "10.3.0.10"
subnet_id = aws_subnet.third-WG-Subnet.id
vpc_security_group_ids = [aws_security_group.third-SG.id]
depends_on = [aws_instance.WG_DL_SRV]
}
resource "aws_eip" "third_WG_EIP" {
provider = aws.third
vpc = true
instance = aws_instance.third-WG.id
depends_on = [aws_internet_gateway.third-IGW]
provisioner "local-exec" {
command = "echo ${aws_eip.third_WG_EIP.public_ip} > ~/Desktop/whole-
wash/var/3rd_PUB_IP.txt"
}
tags = {
Name = "third_WG_EIP"
}
}

Instead of attaching the Elastic IP to the instance, which makes the instance a dependency of the Elastic IP forcing it to be built first, you can instead create a network interface, and attach the Elastic IP to that. You then also make that interface used by the instance, and so everything is then brought up together.
resource "aws_network_interface" "nic" {
private_ips = ["10.3.0.10"]
subnet_id = aws_subnet.third-WG-Subnet.id
#Todo: populate any other needed NIC parameters
}
resource "aws_eip" "third_WG_EIP" {
provider = aws.third
vpc = true
network_interface = aws_network_interface.nic
depends_on = [aws_internet_gateway.third-IGW]
provisioner "local-exec" {
command = "echo ${aws_eip.third_WG_EIP.public_ip} > ~/Desktop/whole-
wash/var/3rd_PUB_IP.txt"
}
tags = {
Name = "third_WG_EIP"
}
}
resource "aws_instance" "third-WG" {
provider = aws.third
ami = data.aws_ami.ubuntu3.id
instance_type = "t2.micro"
key_name = aws_key_pair.third_WGkey.key_name
associate_public_ip_address = true
vpc_security_group_ids = [aws_security_group.third-SG.id]
depends_on = [aws_instance.WG_DL_SRV]
network_interface {
network_interface_id = aws_network_interface.nic.id
device_index = 0
}
}
If you find it's still in slightly the wrong order, you can also then add the EIP to the depends_on parameter of the instance, since the EIP is no longer dependent on the instance itself.
Note that it's been a while since I've done precisely this, you may find you need to move a few of the other networky type parameters (security groups etc) out of the instance and into the network interface block.

Related

Tagging multiple EC2 instances with terraform

how can I set different tags for whatever number of instances I'll create? the problem here is the servers will be server-1, server-2, etc.., but what I actually want is to set different values instead of using the value "Server" for all instances.
resource "aws_instance" "myapp-server" {
ami = data.aws_ami.Latest-amazon-linux-image.id
instance_type = var.instance_type
count = "${var.instance_count}"
subnet_id = aws_subnet.public-subnet-1.id
vpc_security_group_ids = [aws_default_security_group.default-sg.id]
availability_zone = var.az
associate_public_ip_address = true
tags = {
Name = "Server-${count.index+1}"
}
}

How do I add multiple instances to aws_network_interface_sg_attachment?

I have the following code and would like to attach a security group to an Elastic Network Interface (ENI).
resource "aws_instance" "foo" {
# us-west-2
count = var.instances
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
key_name = aws_key_pair.deployer.key_name
subnet_id = aws_subnet.tf_test_subnet.id
vpc_security_group_ids = [ aws_security_group.allow_tls.id ]
}
resource "aws_network_interface_sg_attachment" "sg_attachment" {
security_group_id = aws_security_group.allow_tls.id
network_interface_id = element(aws_instance.foo.*.primary_network_interface_id,0)
}
however upon deployment of the code I get
Error: security group sg-060153b203cbaa6d5 already attached to interface ID eni-006293e38b0056a91
I suspect that this may be because of the ,0 index value but I'm not sure?
so the question is how can I iterate over the instances and apply the security group to the ENI
Your template is actually trying to attach it twice:
Once as part of the aws_instance resource’s vpc_security_group_ids attribute,
and then again using the aws_network_interface_sg_attachment.
In your case, you don’t need the aws_network_interface_sg_attachment resource.

Terraform config isn't using output from other file for already created resource, instead tries to recreate it and fails (security group id)

In terraform/aws/global/vpc/security_groups.tf I have the below code to create my bastion security group, and the output.tf file as well which is below. But in terraform/aws/layers/bastion/main.tf (code also below) I reference that security group as I need its security group ID to create my EC2 instance, the issue I have is that rather than getting the ID from the already existing security group created by the /vpc/security_groups.tf config it tries to create the whole security group and the run obviously fails because it already exists. How can I change my code to get the ID of the existing SG? I don't want to create my SG in the same config file as my instance, some of my security groups are shared between different resources. I am using Terraform Cloud and VPC has its own workspace, so I assume this could actually be an issue with the states being different.. is there a work around for this?
terraform/aws/global/vpc/security_groups.tf
provider "aws" {
region = "eu-west-1"
}
resource "aws_security_group" "bastion" {
name = "Bastion_Terraform"
description = "Bastion SSH access Terraform"
vpc_id = "vpc-12345"
ingress {
description = "Bastion SSH"
from_port = ##
to_port = ##
protocol = "##"
cidr_blocks = ["1.2.3.4/56"]
}
ingress {
description = "Bastion SSH"
from_port = ##
to_port = ##
protocol = "##"
cidr_blocks = ["1.2.3.4/0"]
}
egress {
description = "Access to "
from_port = ##
to_port = ##
protocol = "tcp"
security_groups = ["sg-12345"]
}
egress {
description = "Access to ##"
from_port = ##
to_port = ##
protocol = "tcp"
security_groups = ["sg-12345"]
}
tags = {
Name = "Bastion Terraform"
}
}
terraform/aws/global/vpc/outputs.tf
output "bastion-sg" {
value = aws_security_group.bastion.id
}
terraform/aws/layers/bastion/main.tf
provider "aws" {
region = var.region
}
module "vpc" {
source = "../../global/vpc"
}
module "ec2-instance" {
source = "terraform-aws-modules/ec2-instance/aws"
name = "bastion"
instance_count = 1
ami = var.image_id
instance_type = var.instance_type
vpc_security_group_ids = ["${module.vpc.bastion-sg}"]
subnet_id = var.subnet
iam_instance_profile = var.iam_role
tags = {
Layer = "Bastion"
}
}
When you have a child module block like this in a TF module:
module "ec2-instance" {
source = "terraform-aws-modules/ec2-instance/aws"
name = "bastion"
instance_count = 1
ami = var.image_id
instance_type = var.instance_type
vpc_security_group_ids = ["${module.vpc.bastion-sg}"]
subnet_id = var.subnet
iam_instance_profile = var.iam_role
tags = {
Layer = "Bastion"
}
}
It doesn't just reference that child module, it instatiates a completely new instance of it unique only to the parent module and its state. Think of this not like an assignment or a pointer but the construction of a whole new instance of the module (using the module as a template) with all of its resources created again.
You will need to either directly reference the outputs of the child module in the parent module that has its module block or you will need to use a terraform_remote_state data source or Terragrunt dependency to load the outputs from the state file.

How to create EC2 instance with two private IPs using Terraform

I am trying to create 3 EC2 instances with two private IPs attached to eth0 and eth1 using terraform.
Can you suggest the correct Terraform resource I need to use to create and attach secondary private IP address' to each of the EC2 machines?
I know by default it creates eth0 and attaches a private IP address, I am looking to create eth1 as part of instance creation and attach a private IP from a different subnet.
resource "aws_instance" "test" {
count = "${var.instance_count["test"]}"
ami = "${var.ami}"
instance_type = "${var.instance_type}"
key_name = "${var.key_name}"
vpc_security_group_ids = ["${aws_security_group.kafka_sg.id}"]
associate_public_ip_address = "${var.associate_public_ip_address}"
ebs_optimized = "${var.ebs_optimized}"
disable_api_termination = "${var.disable_api_termination}"
subnet_id = "${var.subnet_id}"
user_data = "${base64encode(file("${path.module}/mount.sh"))}"
tags = {
Name = "test-${var.instance_prefix}-${format("%02d", count.index+1)}"
}
root_block_device {
volume_type = "${var.root_volume_type}"
volume_size = "${var.root_volume_size}"
}
ebs_block_device{
device_name = "/dev/sdb"
volume_size = 10
volume_type = "gp2"
}
}
Add an Elastic Network Interface to the server by creating the ENI via aws_network_interface, and then attaching it via aws_network_interface_attachment

Terraform - DB and security group are in different VPCs

What am I trying to achive:
Create and RDS Aurora cluster and place it in the same VPC as EC2 instances that I start so they can comunicate.
I'm trying to start an SG named "RDS_DB_SG" and make it part of the VPC i'm creating in the process.
I also create an SG named "BE_SG" and make it part of the same VPC.
I'm doing this so I can get access between the 2 (RDS and BE server).
What I did so far:
Created an .tf code and started everything up.
What I got:
It starts ok if I don't include the RDS cluster inside the RDS SG - The RDS creates it's own VPC.
When I include the RDS in the SG I want for him, The RDS cluster can't start and get's an error.
Error I got:
"The DB instance and EC2 security group are in different VPCs. The DB instance is in vpc-5a***63c and the EC2 security group is in vpc-0e5391*****273b3d"
Workaround for now:
I started the infrastructure without specifing a VPC for the RDS. It created it's own default VPC.
I then created manuall VPC-peering between the VPC that was created for the EC2's and the VPC that was created for the RDS.
But I want them to be in the same VPC so I won't have to create the VPC-peering manuall.
My .tf code:
variable "vpc_cidr" {
description = "CIDR for the VPC"
default = "10.0.0.0/16"
}
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_cidr}"
tags = {
Name = "${var.env}_vpc"
}
}
resource "aws_subnet" "vpc_subnet" {
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "${var.vpc_cidr}"
availability_zone = "eu-west-1a"
tags = {
Name = "${var.env}_vpc"
}
}
resource "aws_db_subnet_group" "subnet_group" {
name = "${var.env}-subnet-group"
subnet_ids = ["${aws_subnet.vpc_subnet.id}"]
}
resource "aws_security_group" "RDS_DB_SG" {
name = "${var.env}-rds-sg"
vpc_id = "${aws_vpc.vpc.id}"
ingress {
from_port = 3396
to_port = 3396
protocol = "tcp"
security_groups = ["${aws_security_group.BE_SG.id}"]
}
}
resource "aws_security_group" "BE_SG" {
name = "${var.env}_BE_SG"
vpc_id = "${aws_vpc.vpc.id}"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "BE" {
ami = "ami-*********************"
instance_type = "t2.large"
associate_public_ip_address = true
key_name = "**********"
tags = {
Name = "WEB-${var.env}"
Porpuse = "Launched by Terraform"
ENV = "${var.env}"
}
subnet_id = "${aws_subnet.vpc_subnet.id}"
vpc_security_group_ids = ["${aws_security_group.BE_SG.id}", "${aws_security_group.ssh.id}"]
}
resource "aws_rds_cluster" "rds-cluster" {
cluster_identifier = "${var.env}-cluster"
database_name = "${var.env}-rds"
master_username = "${var.env}"
master_password = "PASSWORD"
backup_retention_period = 5
vpc_security_group_ids = ["${aws_security_group.RDS_DB_SG.id}"]
}
resource "aws_rds_cluster_instance" "rds-instance" {
count = 1
cluster_identifier = "${aws_rds_cluster.rds-cluster.id}"
instance_class = "db.r4.large"
engine_version = "5.7.12"
engine = "aurora-mysql"
preferred_backup_window = "04:00-22:00"
}
Any suggestions on how to achieve my first goal?