Skip to content

Terraform Level 1, Task 26: Linking Resources with aws_eip_association

Today's task was a major step in my Terraform journey. Instead of just creating simple, isolated resources, my objective was to create and link multiple resources together. I was given a Terraform file that defined an EC2 instance and an Elastic IP (EIP), and my task was to add the "glue" to attach the EIP to the instance.

This was a fantastic lesson in how Terraform manages dependencies. I learned that I don't just define resources; I define the relationships between them. This document is my very detailed, first-person guide to that entire process, with a deep dive into the code and the concept of implicit dependencies.

Table of Contents


The Task

My objective was to use Terraform to attach an existing Elastic IP to an existing EC2 instance, all defined within the same main.tf file. The requirements were: 1. All code had to be in a single main.tf file. 2. The target EC2 instance was xfusion-ec2. 3. The target Elastic IP was xfusion-ec2-eip. 4. I needed to add the necessary Terraform code to create the association between them.


My Step-by-Step Solution

The process involved updating the existing main.tf file to add a new resource that would link the other two.

Phase 1: Writing the Code

In the /home/bob/terraform directory, I opened the main.tf file provided by the lab. It already contained the aws_instance and aws_eip resources. I added the new aws_eip_association resource block to the end of the file.

# (Provider block was in a separate provider.tf file)

# This block was already provided in main.tf
resource "aws_instance" "ec2" {
  ami           = "ami-0c101f26f147fa7fd"
  instance_type = "t2.micro"
  subnet_id     = "subnet-682895e98ea57e957"
  vpc_security_group_ids = [
    "sg-bd35a7488f5ddf617"
  ]

  tags = {
    Name = "xfusion-ec2"
  }
}

# This block was also provided in main.tf
resource "aws_eip" "ec2_eip" {
  tags = {
    Name = "xfusion-ec2-eip"
  }
}

# This is the new resource block I added to solve the task.
# It creates the link between the instance and the EIP.
resource "aws_eip_association" "eip_assoc" {
  instance_id   = aws_instance.ec2.id
  allocation_id = aws_eip.ec2_eip.id
}

Phase 2: The Terraform Workflow

From my terminal in the same directory, I executed the three core commands. 1. Initialize: terraform init. 2. Plan: terraform plan. The output was very clear. It showed Plan: 3 to add, 0 to change, 0 to destroy.. This confirmed Terraform would create the instance, the EIP, and the association all at once. 3. Apply: terraform apply. After I confirmed with yes, Terraform executed the plan. It intelligently created the instance and EIP first, and then, once it had their IDs, it created the association. The success message confirmed the task was done.


Why Did I Do This? (The "What & Why")

- Elastic IP (EIP): This is a static, public IPv4 address that I can provision for my account. Its key feature is that it's "elastic"—I can move it from one EC2 instance to another. This is crucial for high availability, as it gives my application a permanent, reliable public IP address, even if the underlying server instance fails and needs to be replaced. - aws_eip_association Resource: This is the "glue" resource. In Terraform, some resources are just simple objects (like an EIP), and others are "relationship" objects. The aws_eip_association resource has no purpose on its own; its only job is to create a link between an aws_instance and an aws_eip. - Implicit Dependencies (The Core Lesson): This was the most important concept I learned in this task. How did Terraform know to create the instance and EIP before creating the association? The answer is in these two lines: - instance_id = aws_instance.ec2.id - allocation_id = aws_eip.ec2_eip.id By referencing the attributes (.id) of other resources, I created an implicit dependency. Terraform read my code, built a dependency graph, and understood that it couldn't create the eip_assoc until it had the id from aws_instance.ec2 and the id from aws_eip.ec2_eip. This ensures all resources are created in the correct order, automatically.


Deep Dive: A Line-by-Line Explanation of My main.tf Script

This script shows how to build and connect a complete set of resources.

[Image of an EIP being associated with an EC2 instance]

# This resource block defines the virtual server.
# "aws_instance" is the Resource TYPE.
# "ec2" is the local NAME I use to refer to this instance.
resource "aws_instance" "ec2" {
  ami           = "ami-0c101f26f147fa7fd"
  instance_type = "t2.micro"
  subnet_id     = "subnet-682895e98ea57e957" # Specifies which subnet to launch in.
  vpc_security_group_ids = [
    "sg-bd35a7488f5ddf617" # Attaches a firewall.
  ]

  tags = {
    Name = "xfusion-ec2"
  }
}

# This resource block defines the static public IP.
# "aws_eip" is the Resource TYPE.
# "ec2_eip" is the local NAME.
resource "aws_eip" "ec2_eip" {
  tags = {
    Name = "xfusion-ec2-eip"
  }
}

# This is the resource block I added. It creates the link.
# "aws_eip_association" is the Resource TYPE.
# "eip_assoc" is the local NAME.
resource "aws_eip_association" "eip_assoc" {

  # This argument requires the ID of an instance.
  # I'm dynamically pulling the 'id' attribute from the 'aws_instance'
  # resource that I named "ec2".
  instance_id   = aws_instance.ec2.id

  # This argument requires the ID of the Elastic IP.
  # I'm pulling the 'id' (also called 'allocation_id' for EIPs) from the
  # 'aws_eip' resource that I named "ec2_eip".
  allocation_id = aws_eip.ec2_eip.id
}

Common Pitfalls

- EIP Already Associated: An Elastic IP can only be attached to one instance at a time. If the xfusion-ec2-eip was already associated with another instance, my apply command would have failed. - VPC vs. EC2-Classic: The aws_eip resource I created is a VPC-scoped EIP. It can only be attached to an instance in a VPC (which is the modern standard). - Using data vs. resource: In a previous task, I used data blocks to look up existing resources. In this task, I used resource blocks to create all three resources from scratch. It's critical to know when to create (resource) and when to read (data).


Exploring the Essential Terraform Commands

- terraform init: Prepared my working directory by downloading the aws provider plugin. - terraform validate: Checks the syntax of Terraform files. - terraform fmt: Auto-formats code to the standard style. - terraform plan: The "dry run" command. It showed me a plan to add 3 new resources and correctly identified the implicit dependencies. - terraform apply: Executed the plan and created all three resources in the correct order after I confirmed with yes. - terraform state list: After the apply, this command would list all three resources that Terraform is now managing: aws_instance.ec2, aws_eip.ec2_eip, and aws_eip_association.eip_assoc. - terraform show: Shows the current state of my managed infrastructure, including the allocated IP address and instance ID. - terraform destroy: The command to destroy all three of these resources, which it would also do in the correct order (destroying the association before the instance or EIP).