Prerequisites:
- AWS Account: You must have an active AWS account. If you don't have one, you can sign up for an AWS account on the AWS website. You can create it here
 - IAM User or Role: Create an IAM (Identity and Access Management) user or role in your AWS account with the necessary permissions to create and manage EC2 Instances. At a minimum, the user or role should have permissions to create EC2 instances, VPCs, and related resources.
 - Terraform Installed: Install Terraform on your local machine. You can download Terraform from the official Terraform website and follow the installation instructions for your operating system here
 
Terraform
Providers
Link to Github code repo here
First lets create our providers, in you project folder create provider.tf file:
provider "aws" {
  region  = var.aws_region
  profile = var.aws_profile
}Main.tf
Create VPC
You can find more detailed guide on VPC creation in our article here
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.1.2"
  name = "${var.env}-vpc"
  cidr = var.cidr
  azs  = var.aws_availability_zones
  private_subnets = var.private_subnets
  public_subnets  = var.public_subnets
  enable_nat_gateway   = true
  single_nat_gateway   = true
  enable_dns_hostnames = true
  public_subnet_tags = merge(
    var.additional_tags,
    {
      "Subnet" = "Public"
    }
  )
  private_subnet_tags = merge(
    var.additional_tags,
    {
      "Subnet" = "Private"
    }
  )
}
resource "aws_security_group" "ssh" {
  name        = "allow_ssh"
  description = "Allow ssh inbound traffic"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description      = "TLS from VPC"
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
  }
}Security group added to allow ssh connection to instance
Create new SSH Key
In this example we would create a new SSH Key to connect to our instance:
resource "tls_private_key" "ssh_key" {
  algorithm = "RSA"
  rsa_bits  = 4096
}
resource "local_file" "private_key" {
    content  = tls_private_key.ssh_key.private_key_pem
    filename = "${var.path}/${var.private_key_name}"
    file_permission = "0600"
}
resource "aws_key_pair" "public_key" {
  key_name   = var.ssh_key_name
  public_key = tls_private_key.ssh_key.public_key_openssh
}resource "tls_private_key" "ssh_key": Generates a secure private key and encodes it
resource "local_file" "private_key": Saves value of private_key_pem attribute to a file in a specified location. In order to use the key we would need to specify permisions
resource "aws_key_pair" "public_key": Terraform add ssh key to instance
Create EC2 Instance:
Here we would create EC2 instance using created key for access to it:
module "ec2-instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "5.5.0"
  name = var.ec2_name
  instance_type = var.ec2_type
  subnet_id = module.vpc.public_subnets[0]
  associate_public_ip_address = true
  key_name = aws_key_pair.public_key.key_name
  vpc_security_group_ids = [aws_security_group.ssh.id]
}name: The name for the EC2 instance
instance_type: Specifies the instance type for the EC2 instance.
subnet_id: The ID of the subnet where the EC2 instance will be launched. It selects the first public subnet from the VPC module provided by module.vpc.
associate_public_ip_address: This attribute is set to true, indicating that the EC2 instance should be assigned a public IP address.
key_name: The SSH key pair name to associate with the EC2 instance. It uses the key name created by an aws_key_pair resource.
vpc_security_group_ids: This specifies a list of security group IDs that should be associated with the EC2 instance.
Variables and Outputs
Don't forget to declare variables:
variable "aws_profile" {
  description = "Set this variable if you use another profile besides the default awscli profile called 'default'."
  type        = string
  default     = "default"
}
variable "aws_region" {
  description = "Set this variable if you use another aws region."
  type        = string
  default     = "us-east-1"
}
variable "env" {
  description = "Set this variable to specify environment"
  type        = string
  default     = "dev"
}
variable "private_subnets" {
  description = "private subnets to create, need to have 1 for each AZ"
  default     = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}
variable "public_subnets" {
  description = "public subnets to create, need to have 1 for each AZ"
  default     = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
}
variable "aws_availability_zones" {
  description = "AWS availability zones"
  default     = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
variable "cidr" {
  description = "Cird block for your VPC"
  type        = string
  default     = "10.0.0.0/16"
}
variable "additional_tags" {
  default     = {
    "project"     = "cloudtipss-vpc"
    "owner"       = "cloudtipss.com"
  }
  description = "Additional resource tags"
  type        = map(string)
}
variable "ssh_key_name" {
  description = "File name to save your private key"
  type        = string
  default     = "ec2-terraform"
}
variable "private_key_name" {
  description = "File name to save your private key"
  type        = string
  default     = "ec2-terraform.pem"
}
variable "path" {
  description = "Full path to you ssh folder or other folder to save private key"
  type        = string
  default     = "/Users/user1/.ssh"
}
variable "ec2_name" {
  description = "Name for your EC2 Instance"
  type        = string
  default     = "ec2-terraform"
}
variable "ec2_type" {
  description = "Type of your instance"
  type        = string
  default     = "t3.small"
}Also we would declare output to get command to run to connect to instance after terraform applied:
output "EC2_public_ip" {
  description = "The public IP address assigned to the instance"
  value       = "ssh -i ${var.path}/${var.private_key_name} ec2-user@${module.ec2-instance.public_ip}"
}Provisoning resources and verification:
After we prepared our code, we would need to initialize it. From your project folder run:
terraform initJust to to see which resources terraform is going to create you can run:
terraform planIn order to create resources run:
terraform applyAfter apply complete you will see output similar to this:
Outputs:
Connect_to_instance = "ssh -i /Users/user1/.ssh/ec2-terraform.pem ec2-user@18.232.182.201"You can run output value in your terminal to connect to your new instance
Use existing ssh key
In this example we would use in terraform already excisting SSH Key. You can find source code here. There would be slight adjustments in a code, variables and output
- In a project folder I would create a key pair to use:
 
ssh-keygen -t rsa -b 4096 -f ./ec2-manual-key- Now we need terraform to read ssh key from file we created:
 
### SSH Key 
resource "aws_key_pair" "public_key" {
  key_name   = var.ssh_key_name
  public_key = "${file("ec2-manual-key.pub")}"
}
### EC2 Instance 
module "ec2-instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "5.5.0"
  name = var.ec2_name
  instance_type = var.ec2_type
  subnet_id = module.vpc.public_subnets[0]
  associate_public_ip_address = true
  key_name = aws_key_pair.public_key.key_name
  vpc_security_group_ids = [aws_security_group.ssh.id]
}You will find both usescases in our Github repo here