Deploy Webserver on AWS using EFS, Cloudfront with Terraform

Task 2: Have to create/launch Application using Terraform

1. Create the key and security group which allows the port 80.

2. Launch EC2 instance.

3. In this Ec2 instance use the key and security group which we have created in step 1.

4. Create EFS and mount that volume into /var/www/html

5. The developer has uploaded the code into the GitHub repo also the repo has some images.

6. Copy the GitHub repo code into /var/www/html

7. Create an S3 bucket, and copy/deploy the images from GitHub repo into the s3 bucket and change the permission to public readable.

8 Create a Cloudfront using s3 bucket(which contains images) and use the Cloudfront URL to update in code in /var/www/html

Prerequisite :

Step-1)Create the key and security group

  • code:
resource "aws_security_group" "http_ssh_protocol" {name        = "allow_http_ssh_NFS"description = "Allow http and ssh inbound traffic"vpc_id      = "vpc-4bc5d123"ingress {description = "HTTP from VPC"from_port   = 80to_port     = 80protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "ssh from VPC"from_port   = 22to_port     = 22protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "tcp from VPC"from_port   = 8080to_port     = 8080protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "allow nfs"from_port   = 2049to_port     = 2049protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "allow_protocols"}}resource "tls_private_key" "key_ssh" {depends_on = [aws_security_group.http_ssh_protocol,]algorithm  = "RSA"rsa_bits   = 4096}resource "aws_key_pair" "key2" {key_name   = "mykeys"public_key = tls_private_key.key_ssh.public_key_openssh}output "key_ssh" {value = tls_private_key.key_ssh.private_key_pem}resource "local_file" "save_key" {depends_on=[aws_key_pair.key2]content     = tls_private_key.key_ssh.private_key_pemfilename = "mykeys.pem"}

Explanation:

  • First, we need to add the resource i.e, aws_security_group which allows us to make a security group.
  • Port number 80 for http(website), 22 for ssh connection, 8080 for Jenkins, and for 2049 for NFS server.
  • Let’s comes on key, we need to add a resource ,i.e, tls_private_key which allow to generating the key for ssh in PEM format, for saving a file we need to add the resource,i.e, local_file.

Output:

Security Group
Keys

Step-2:)Setup EFS.

  • code:
resource "aws_efs_file_system" "efs" {
creation_token = "my-product"
tags = {
Name = "myefs"
}
}
resource "aws_efs_mount_target" "alpha" {
depends_on = [
aws_efs_file_system.efs,
aws_security_group.http_ssh_protocol
]
file_system_id = aws_efs_file_system.efs.id
security_groups = [aws_security_group.http_ssh_protocol.id]
subnet_id = aws_instance.webos.subnet_id
}

Explanation:

  • For creating efs use resource aws_efs_file_system.
  • Now we have to mount the efs on the region use resource aws_efs_mount_target, here I am using the same region which is configured in the ec2-instance.

Output:

EFS

Step-3)Launch EC2

  • code:
resource "aws_instance"  "webos"  {
depends_on = [
aws_key_pair.key2,
tls_private_key.key_ssh,
local_file.save_key,
aws_efs_file_system.efs
]
ami = "ami-0b5bff6d9495eff69"
instance_type = "t2.micro"
key_name = "mykeys"
security_groups = [ "allow_http_ssh_NFS" ]
tags = {
Name = "WebOSec2"
}
}

Explanation:

  • Here for launching ec2, you have to use resource aws_instance, and at there configure key_name, security_groups, etc which is already setup in the above step.
  • For giving name, use tags.

Output:

EC2

Step-4)Mount EFS, setup httpd, Jenkins.

  • code:
resource "null_resource" "null1"  {depends_on = [
aws_instance.webos,
local_file.save_key,
aws_efs_mount_target.alpha,

]
connection {
type = "ssh"
user = "ec2-user"
private_key = tls_private_key.key_ssh.private_key_pem
host = aws_instance.webos.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo git clone https://github.com/rootritesh/HMCC_TASK2.git /var/www/html",
"sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins.io/redhat-stable/jenkins.repo",
"sudo rpm --import http://pkg.jenkins.io/redhat-stable/jenkins.io.key",
"sudo yum update -y",
"sudo yum remove java-1.7.0-openjdk -y",
"sudo yum install httpd git amazon-efs-utils java-1.8.0-openjdk jenkins -y",
"sudo service jenkins start",
"sudo service httpd start",
"sudo mount -t efs -o tls ${aws_efs_file_system.efs.id}:/ /var/www/html",
"sudo cat /var/lib/jenkins/secrets/initialAdminPassword",
]
}
}

Explanation:

  • Here to do this setup, I am using resource null_resource, for connecting ssh with my EC2-instance, after that we have to use remote-exec for running our commands.

Output:

EFS is mounted

Step-5)Create S3:

  • Code:
resource "null_resource" "null2"  {
provisioner "local-exec" {
command = "git clone https://github.com/rootritesh/HMCC_TASK2.git ./gitcode"
}
}
resource "aws_s3_bucket" "b1" {
bucket = "codeofweb"
acl = "public-read"
versioning {
enabled = true
}
tags = {
Name = "HMCCTASk2"
Environment = "Dev"
}
}
resource "aws_s3_bucket_object" "obj1" {
key = "welcome.jpg"
bucket = aws_s3_bucket.b1.id
source = "./gitcode/welcome.jpg"
acl="public-read"
}

Explanation:

  • Here first I am downloading code for Github locally, for uploading code into the S3 bucket.
  • For creating S3 use resource aws_s3_bucket, and gave public-read access.
  • For uploading our code into S3 use the resource aws_s3_bucket_object.

Output:

S3 bucket with public

Step-6)Create a Cloudfront using s3 bucket(which contains images)

  • Code:
resource "aws_cloudfront_distribution" "cloudfront1" {
depends_on = [
aws_s3_bucket.b1,
null_resource.null1,
]
origin {
domain_name = "codeofweb.s3.amazonaws.com"
origin_id = aws_s3_bucket.b1.id
custom_origin_config {
http_port = 80
https_port = 80
origin_protocol_policy = "match-viewer"
origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"]
}
}
enabled = truedefault_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = aws_s3_bucket.b1.id
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
resource "null_resource" "null4" {
provisioner "local-exec" {
command = "echo ${aws_cloudfront_distribution.cloudfront1.domain_name
} > cloudfrontURL.txt"
}
}

Explanation:

  • For creating Cloudfront use resource aws_cloudfront_distribution.
  • Use domain_name, origin_id for CDN(Content Delivery Network).
  • Here I saved the CloudFront URL using resource i.e, null_resource because we need to update the CloudFront URL on the website in the img tag.

Output:

CloudFront

Step-7)Configure Jenkins

  • Copy Public_IP:Port(8080) paste on the browser.
  • For unlocking in the Jenkins installing, use putty, login into ec2-instance as root, type this two command:
#sudo su -- root#cat /var/lib/jenkins/secrets/initialAdminPassword"#echo "jenkins ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
  • The first command for login into the root account.
  • The second command for output the Jenkins password
  • The third command is for giving our Jenkins permission.
  • paste the given password from the above command.
  • Click on X, right now we don’t need to install plugins.
  • Go to Manage Jenkins > Manage Plugins > search in the tab GitHub >select it > Click on install without a restart.
Github Plugin

Now its time to configure the job.

  • Click on the New Item > Name it > Click on freestyle > Click on OK.
  • Here u need the Github repo to contain the website.
  • poll SCM * * * * * (it check every 60 sec if code changes or not if changes Jenkins will automatically download)
  • Execure shell > for copy github repo into /var/www/html
  • Save it
  • Build It.

Output:

  • Here our code is downloaded successfully and it is copied into folder /var/www/html.

Final Code:

provider "aws" {
region = "ap-south-1"
}
resource "aws_security_group" "http_ssh_protocol" {
name = "allow_http_ssh_NFS"
description = "Allow http and ssh inbound traffic"
vpc_id = "vpc-4bc5d123"
ingress {
description = "HTTP from VPC"
from_port = 80
to_port = 80
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"]
}
ingress {
description = "ssh 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"]
}
ingress {
description = "tcp from VPC"
from_port = 8080
to_port = 8080
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"]
}
ingress {
description = "allow nfs"
from_port = 2049
to_port = 2049
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"]
}
tags = {
Name = "allow_protocols"
}
}
resource "aws_efs_file_system" "efs" {
creation_token = "my-product"
tags = {
Name = "myefs"
}
}
resource "aws_efs_mount_target" "alpha" {
depends_on = [
aws_efs_file_system.efs,
aws_security_group.http_ssh_protocol
]
file_system_id = aws_efs_file_system.efs.id
security_groups = [aws_security_group.http_ssh_protocol.id]
subnet_id = aws_instance.webos.subnet_id
}
resource "tls_private_key" "key_ssh" {
depends_on = [aws_security_group.http_ssh_protocol,
]
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "key2" {
key_name = "mykeys"
public_key = tls_private_key.key_ssh.public_key_openssh
}
output "key_ssh" {
value = tls_private_key.key_ssh.private_key_pem
}
resource "local_file" "save_key" {
depends_on=[aws_key_pair.key2]
content = tls_private_key.key_ssh.private_key_pem
filename = "mykeys.pem"
}
resource "aws_instance" "webos" {
depends_on = [
aws_key_pair.key2,
tls_private_key.key_ssh,
local_file.save_key,
aws_efs_file_system.efs
]
ami = "ami-0b5bff6d9495eff69"
instance_type = "t2.micro"
key_name = "mykeys"
security_groups = [ "allow_http_ssh_NFS" ]
tags = {
Name = "WebOSec2"
}
}
resource "null_resource" "null1" {depends_on = [
aws_instance.webos,
local_file.save_key,
aws_efs_mount_target.alpha,

]
connection {
type = "ssh"
user = "ec2-user"
private_key = tls_private_key.key_ssh.private_key_pem
host = aws_instance.webos.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo git clone https://github.com/rootritesh/HMCC_TASK2.git /var/www/html",
"sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins.io/redhat-stable/jenkins.repo",
"sudo rpm --import http://pkg.jenkins.io/redhat-stable/jenkins.io.key",
"sudo yum update -y",
"sudo yum remove java-1.7.0-openjdk -y",
"sudo yum install httpd git amazon-efs-utils java-1.8.0-openjdk jenkins -y",
"sudo service jenkins start",
"sudo service httpd start",
"sudo mount -t efs -o tls ${aws_efs_file_system.efs.id}:/ /var/www/html",

]
}
}
resource "null_resource" "null2" {
provisioner "local-exec" {
command = "git clone https://github.com/rootritesh/HMCC_TASK2.git ./gitcode"
}
}
resource "aws_s3_bucket" "b1" {
bucket = "codeofweb"
acl = "public-read"
versioning {
enabled = true
}
tags = {
Name = "HMCCTASk2"
Environment = "Dev"
}
}
resource "aws_s3_bucket_object" "obj1" {
key = "welcome.jpg"
bucket = aws_s3_bucket.b1.id
source = "./gitcode/welcome.jpg"
acl="public-read"
}
resource "aws_cloudfront_distribution" "cloudfront1" {
depends_on = [
aws_s3_bucket.b1,
null_resource.null1,
]
origin {
domain_name = "codeofweb.s3.amazonaws.com"
origin_id = aws_s3_bucket.b1.id
custom_origin_config {
http_port = 80
https_port = 80
origin_protocol_policy = "match-viewer"
origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"]
}
}
enabled = truedefault_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = aws_s3_bucket.b1.id
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
resource "null_resource" "null4" {
provisioner "local-exec" {
command = "echo ${aws_cloudfront_distribution.cloudfront1.domain_name
} > cloudfrontURL.txt"
}
}

Command:

  • Run your Command prompt in the current directory where .tf file is stored
  • Type=> terraform init (to initialize terraform and download plugins )
  • Type=> terraform validate (to check the syntax of code)
  • Type=> terraform apply -auto-approve (to Run the Code).

Final Output:

  • Copy the Public_IP:Port(80)/index.html
  • Here you can see it is using Cloudfront for img Tag.

Github Link:

DevOps/Cloud Enthusiast