How to use terraform to Launch an AWS EC2 Instance

Terraform is an open-source infrastructure as code software tool created by HashiCorp. To use terraform, you define the resources you want to create using a declarative configuration language created by Hashicorp known as HashiCorp Configuration Language (HCL), or optionally JSON.

AWS is a popular cloud provider similar to Azure and GCP.

Also check

# Prerequisites

To follow along this guide, you need the following:

  • AWS IAM credentials with permissions to manage EC2 instances - access key and secret key
  • AWS cli installed in your system. Install it here if you don’t have it already.
  • Terraform installed in your machine, get terraform from here if you don’t have it

This is the terraform version I am using:

1
2
3
4
$ terraform --version

Terraform v1.6.6
on darwin_arm64

Export aws credentials in your terminal before proceeding.

1
2
3
export AWS_ACCESS_KEY_ID=your-key-id-here
export AWS_SECRET_ACCESS_KEY=youe-access-key-here
export AWS_DEFAULT_REGION=aws-region

# Adding a Provider

A Terraform Provider represents an integration that is responsible for understanding API interactions with the underlying infrastructure. The provider in our case defines connection to AWS. We also define that we want to provision resources in us-west-2 region.

1
2
3
provider "aws" {
  region = "us-west-2"
}

# Defining Terraform Version

Let us also define the version of terraform that we want to use. We define the terraform version to be any version above 1.6.6.

1
2
3
terraform {
  required_version = ">= 1.6.6"
}

# Defining variables

Input variables serve as parameters for a Terraform module, allowing aspects of the module to be customized without altering the module’s own source code, and allowing modules to be shared between different configurations.

In our case we define a key path for the ssh public key that we will use to ssh to the server.

1
2
3
variable "key_path" {
  default = "~/.ssh/id_rsa.pub"
}

# Defining Key Pair

Next, let’s create a public key resource that we can use to ssh to the server. Here we define key-pair my-pub-key with the public key value of the variable defined in the variables.

1
2
3
4
resource "aws_key_pair" "my-pub-key" {
  key_name   = "my-pub-key"
  public_key = file("${var.key_path}")
}

# Creating EC2 instance

Next, we define the resource creating our ec2 instance. We have to specify the instance properties like the AMI, Instance type, SSH key to use, Security groups, Subnet to launch the instance in. We also define that the instance be associated with a public ip address so we can access from the outside.

Next we define a disk size and give the instance tags.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
resource "aws_instance" "instance" {
  ami                         = "ami-0ddb956ac6be95761"
  instance_type               = "t2.small"
  key_name                    = aws_key_pair.my-pub-key.id
  vpc_security_group_ids      = [aws_security_group.sg.id]
  subnet_id                   = "subnet-xxxxxxx"
  associate_public_ip_address = true

  root_block_device {
    volume_size           = 50
    delete_on_termination = true
  }

  tags = {
    Name = "Citizix-Debian-Server"
  }
}

# Defining Security Group

Next we define a security group. A security group acts as a virtual firewall for your EC2 instances to control incoming and outgoing traffic. We define rules in our security group outlining the traffic that we want to accept.

In our case, we want to have all outgoing traffic whitelisted and only allow incoming traffic from port 22.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
resource "aws_security_group" "sg" {
  name        = "Citizix-Server-SG"
  description = "Restrictions for Citizix server"

  ingress {
    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"]
  }

  vpc_id = "vpc-xxxxxx"

  tags = {
    Name = "Citizix-Server-SG"
  }
}

# Defining outputs

Finally, we define outputs. Terraform output values allow you to export structured data about your resources. In our case, we can use outputs to export data about the instance we just created like the IP that it has been assignend.

1
2
3
4
5
6
7
output "instance-private-ip" {
  value = aws_instance.instance.private_ip
}

output "instance-public-ip" {
  value = aws_instance.instance.public_ip
}

# Full Code

This is the full code for provisioning an ec2 instance in AWS.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
provider "aws" {
  region = "us-west-2"
}

terraform {
  <meta charset="utf-8">required_version = ">= 1.6.6"
}

variable "key_path" {
  default = "~/.ssh/id_rsa.pub"
}

resource "aws_key_pair" "my-pub-key" {
  key_name   = "my-pub-key"
  public_key = file("${var.key_path}")
}

resource "aws_instance" "instance" {
  ami                         = "ami-0ddb956ac6be95761"
  instance_type               = "t2.small"
  key_name                    = aws_key_pair.my-pub-key.id
  vpc_security_group_ids      = [aws_security_group.sg.id]
  subnet_id                   = "subnet-xxxxxxx"
  associate_public_ip_address = true

  root_block_device {
    volume_size           = 50
    delete_on_termination = true
  }

  tags = {
    Name = "Citizix-Debian-Server"
  }
}

resource "aws_security_group" "sg" {
  name        = "Citizix-Server-SG"
  description = "Restrictions for Citizix server"

  ingress {
    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"]
  }

  vpc_id = "vpc-xxxxxx"

  tags = {
    Name = "Citizix-Server-SG"
  }
}

output "instance-private-ip" {
  value = aws_instance.instance.private_ip
}

output "instance-public-ip" {
  value = aws_instance.instance.public_ip
}

# Creating resources

With all the full code in place, let us create the AWS resources.

1
2
3
terraform init
terraform plan
terraform apply

# Conclusion

In this guide we managed to create an EC2 instance using terraform.

comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy