Step by step first terraform project

Hi,

I am trying to set up my first project with Terraform on AWS.

This is my main.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
}

# Create a VPC
resource "aws_vpc" "first_vpc" {
#  vpc_id = aws_vpc.first_vpc.id # An argument named "vpc_id" is not expected here.
  cidr_block = "100.0.0.0/16"
}

# Create subnet for VPC
resource "aws_subnet" "first_subnet" {
  vpc_id            = aws_vpc.first_vpc.id
  cidr_block        = "100.200.0.0/24"
  availability_zone = "us-east-1"

  tags = {
    Name = "My first subnet for Ubuntu server"
  }
}

resource "aws_network_interface" "first_network_interface" {
  subnet_id   = aws_subnet.first_subnet.id
  private_ips = ["100.200.0.100"]

  tags = {
    Name = "primary_network_interface"
  }
}

# Use Ubuntu 22.04
resource "aws_instance" "first_ubuntuserver" {
  ami           = "ami-053b0d53c279acc90"
  instance_type = "t3.micro"
  
   network_interface {
    network_interface_id = aws_network_interface.first_network_interface.id
    device_index         = 0
  }

  tags = {
    Name = "My first Ubuntu on AWS instance"
  }
}

And this an error which I see when I run #terraform apply/validate:

 Error: creating EC2 Subnet: InvalidParameterValue: Value (us-east-1) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: us-east-1a, us-east-1b, us-east-1c, us-east-1d, us-east-1e, us-east-1f.
│       status code: 400, request id: 16245777-37a1-404b-bfd1-91a3cbb4547e
│
│   with aws_subnet.first_subnet,
│   on main.tf line 22, in resource "aws_subnet" "first_subnet":
│   22: resource "aws_subnet" "first_subnet" {

Would someone clarify what is going on here? I fill out each block one by one according to the documentation for a better understanding of what missing blocks lead to which errors. However over here I can not match what is missing according to the documentation: Terraform Registry

Thanks!

The error message has told you which value is incorrect, and what the acceptable values are. What more is there to say?

I focused on what followed by Error, not with. When I change a region us-east1a it works.

Coming back to my Terraform learning path, I have such maint.tf file now:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
}

# Configure the AWS VPC
resource "aws_vpc" "my_aws" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "my_aws_project"
  }
}

# Configure the AWS Internet Gateway
resource "aws_internet_gateway" "my_gw" {
  vpc_id = aws_vpc.my_aws.id
}

# Configure the AWS Route Table
resource "aws_route_table" "my_route" {
  vpc_id = aws_vpc.my_aws.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.my_gw.id
  }

  route {
    ipv6_cidr_block        = "::/0"
    gateway_id = aws_internet_gateway.my_gw.id
  }

  tags = {
    Name = "my_route"
  }
}

# Configure the AWS Subnet
resource "aws_subnet" "my_subnet" {
  vpc_id            = aws_vpc.my_aws.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-east-1a"

  tags = {
    Name = "my aws subnet"
  }
}

# Configure association the AWS Subnet with Route Table
resource "aws_route_table_association" "my_association_with_route_table" {
  subnet_id      = aws_subnet.my_subnet.id
  route_table_id = aws_route_table.my_route.id
}

# Configure Security Group
resource "aws_security_group" "my_allow_web_traffic" {
  name        = "allow_web_traffic"
  description = "Allow web traffic"
  vpc_id      = aws_vpc.my_aws.id

  ingress {
    description = "HTTPS traffic from VPC"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    # ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }
  ingress {
    description = "HTTP traffic from VPC"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    # ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }
  ingress {
    description = "SSH traffic from VPC"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    # ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "allow_web_traffic"
  }
}

# Configure Network Interface
resource "aws_network_interface" "my_network_interface" {
  subnet_id       = aws_subnet.my_subnet.id
  private_ips     = ["10.0.1.50"]
  security_groups = [aws_security_group.my_allow_web_traffic.id]
}

# Assign Elastic IP
resource "aws_eip" "my_eip" {
  domain                    = "vpc"
  network_interface         = aws_network_interface.my_network_interface.id
  associate_with_private_ip = "10.0.1.50"
  depends_on                = [aws_internet_gateway.my_gw]
}

resource "aws_instance" "my_ubuntu_server" {
  ami               = "ami-053b0d53c279acc90"
  instance_type     = "t3.micro"
  availability_zone = "us-east-1a"
  key_name          = "my-key"

  network_interface {
    network_interface_id = aws_network_interface.my_network_interface.id
    device_index         = 0
  }

  user_data = <<-EOF
  #!/bin/bash
  sudo apt update -y
  sudo apt install apache2 -y
  sudo systemctl start apache2
  sudo bash -c 'echo your very first web server > /var/www/html/index.html'
  EOF

  tags = {
    Name = "my-first-web-server"
  }
}

I run #terraform apply, then go the AWS account to check instances. There is my-first-web-server I open IPv4 Public address: 54.88.81.135 which does not work, why? I am getting error “This sie can’t be reached”.

I should see your very first web server. How to debug it? What to check?

Resolved. It works with http, not https (example: http://44.218.3.226/). However I have configured both HTTPs and HTTP in main.tf for Security Group, so why does it not work also for https://44.218.3.226/, and how to change on AWS to open a website with http by default?

Hey there, congratulations on successfully running your web server via TF.

Your browser trying HTTPS by default might be force HTTPS enable settings or similar security feature enabled inside the browser, its not from AWS or your web server.

HTTPS needs to be configured in your apache2 webserver with a valid domain and a certificate to work.

Ref : How Do I Enable HTTPS On Apache Web Server

Thanks @tanmay-bhat.

I can’t resolve the next issue with idea coming to my head (“Oh! Let’s add Load Balancer”). According to the documentation Terraform Registry I added block of code to the main.tf file and modified it a bit:

# Create AWS Load Balancer
resource "aws_lb" "my_first_load_balancer" {
  name               = "lb"
  internal           = false
  load_balancer_type = "application"
  subnet_id          = aws_subnet.my_subnet_1.id
  security_groups    = [aws_security_group.my_allow_web_traffic.id]
  subnets            = [for my_subnet_1 in aws_subnet.public : my_subnet_1.id]

  enable_deletion_protection = true

  access_logs {
    bucket  = aws_s3_bucket.my_bucket.id
    prefix  = "test-lb"
    enabled = true
  }

# Configure the AWS Subnet 1
resource "aws_subnet" "my_subnet_1" {
  vpc_id            = aws_vpc.my_aws.id
  cidr_block        = var.subnet_prefix[0]
  availability_zone = "us-east-1a"

  tags = {
    Name = "my 1st aws subnet"
  }
}

terraform.tfvars file:
subnet_prefix = ["10.0.1.0/24", "10.0.1.129/25", "10.0.1.193/26"]

I got an error:

2023-09-04T21:28:32.481+0200 [ERROR] Checkpoint error: Get "https://checkpoint-api.hashicorp.com/v1/check/terraform?arch=386&os=windows&signature=f046a149-be7b-15f9-2e2c-f078fffd74eb&version=1.5.6": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
2023-09-04T21:28:35.279+0200 [ERROR] vertex "aws_lb.my_first_load_balancer" error: Reference to undeclared resource
╷
│ Error: Reference to undeclared resource
│
│   on main.tf line 228, in resource "aws_lb" "my_first_load_balancer":
│  228:   subnets            = [for my_subnet_1 in aws_subnet.public : my_subnet_1.id]
│
│ A managed resource "aws_subnet" "public" has not been declared in the root module.

So I went to the Terraform docs again, but this time looking for aws_subnet resource: Terraform Registry , but I do not see any mention for public subnet creation. How to specify the public subnet resource to fix that issue?

Anyone would like to instruct me how to proceed with the above error?
I am practice Terraform so I am aware my mistakes, but not sure how to resolve each of them.

I’ll try to help, but cannot promise :slight_smile: .

Let me take a look at the above errors.

You cannot create public subnet resource as a type in terraform. You need to understand the difference between a public and a private subnet in AWS.

So a public subnet is the subnet that has a Internet Gateway attached to its route and private subnet has NAT gateway attached to the route. That’s the difference.

If you want to create a public subnet, you have to follow the same above procedure, i,e :

  • Create a subnet as above.
  • Create a route table
  • Attach the route table with that subnet
  • Create a route 0.0.0.0/0 into the already created internet gateway of your VPC.

If an Internet gateway doesn’t exist for your VPC, you need to create one.

Now, if you want to avoid doing these, use the VPC module, and it will do those for you.

https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest/examples/simple

Wow, it is amazing: Terraform Registry in one shot I create VPC, NAT, Net Int, DG and Subnets in over several lines of code. Prevously it was in over a dozens lines of code using resources.

Thanks for that advice. BTW, modules were on the learning agenda but for later. However, I skipped the other stuff to hop into modules it was a good idea to start it now.

And I really now start see the power of Terraform.

You’re welcome and happy learning.

Coming back to the module which I created:

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"
  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1f"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = true

  tags = {
    Terraform = "true"
    Environment = "dev"
  }
}

Now I would like to pass argument id of vpc to resource for aws_vpc_endpoint. id was not declare in vpc module that is why I do not see it over here:

resource "aws_vpc_endpoint" "s3" {
  vpc_id       = module.vpc.???
  service_name = "com.amazonaws.us-east-1.s3"
}

On the other hand the id is mandatory for aws_vpc_endpoint. So how to resolve it?

May be it is referring to this line since availability_zone value should be like us-east-1a or us-east-1b etc.

Hope this helps :pray:

Thanks nkrishnakishor for reply.

I will try out this.