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 init
Just to to see which resources terraform is going to create you can run:
terraform plan
In order to create resources run:
terraform apply
After 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