Cloud Agnostic Secure Delivery of a Website on Akamai Edge Platform using Terraform — Part I

Deepak
AWS Tip
Published in
10 min readMar 29, 2022

--

In this blogpost, I am going to discuss about how easy it is to build/host a website in any cloud ( i have used AWS as example public cloud) and deliver it securely over Akamai secure platform using terraform. For those who don’t know much about Akamai, here is brief about Akamai Technologies, Inc. is a content delivery network (CDN), a cybersecurity, and cloud service company, providing web and Internet security services. Akamai’s Intelligent Edge Platform is one of the world’s largest distributed computing platforms. For those who might be wondering what is content delivery network, good analogy might be thinking it as local grocery store where you can quickly go and grab your stuff rather than going back to farmer or manufacturer who actually produces the good, in same cases manufacturer can be in another city or country. Because you don’t have to go down to manufacturer so you can get your stuff quickly and conveniently. Same way CDN provides platform for a website to be delivered locally from location near to end user. Requests need not go down to origin server for fetching stuff all the time. Remember request over network always incur latency penalty. Closer the content to user, faster will be performance.

Another important point is that why headline of this post is cloud agnostic when we are going to use AWS for deployment? Answer to this question is that from Akamai perspective it does not matter where you host your cloud so akamai specific terraform files would remain exactly same, only thing that would change is public cloud provider terraform files.

Let’s jump into the real stuff, before starting to code it is always good to build a high level architecture diagram.

On a very high level we are going to achieve below:-

  1. Use Terraform as a tool for deployment of above architecture
  2. Create hosting environment on AWS — VPC, AZ, Subnet, Route Table, association etc
  3. Provision a VM in AWS
  4. Install Apache and host a website on it
  5. Create DNS hostname using Akamai’s Globally distributed Edge DNS platform
  6. Onboard Website on Akamai global CDN network so that users across the globe can access it
  7. Secure our website behind Akamai’s WAF — Restrict our site from particular location, protect site from known bad actors, enable DOS protection, enable WAF rules etc.

This part of this post consists of only AWS related provisioning. If you are comfortable in AWS related stuff and want to know only about Akamai then please move to part II.

Pre-requisites:- this post assumes that you have fair bit of understanding working with terraform, akamai api’s, akamai ecosystem, aws ecosystem and aws cli. Below are the important for getting started with

  1. Akamai API — https://developer.akamai.com/getting-started/edgegrid
  2. AWS CLI — https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html
  3. About Terraform — https://www.terraform.io/
  4. Terraform — Akamai provider https://registry.terraform.io/providers/akamai/akamai/latest/docs
  5. Terraform — AWS provider https://registry.terraform.io/providers/hashicorp/aws/latest

Let’s start the deployment:- As described in architecture we need to first build our infrastructure in public cloud that is AWS in this case.

Section 1 — Set up AWS API/CLI

If this is first time working with AWS CLI than follow along otherwise you may skip cli section.

  1. Create a User with admin access within AWS Console and give it programatic access i.e. this account can have secret key that can be used to manage AWS resources using api’s or as a code with tool like terraform

2. Give admin access, ideally should be more restrictive because this my test account so given admin access

3. Note down the AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY. For working with AWS API you need to pass these values. Although their are multiple ways to do it but as per me most easy and relatively safer way is to set it as environment variable within your shell environment file for e.g. .bashrc, .zshrc . Add below line (obviously by replacing key id and secret) in your .bashrc or .zshrc or profile files.

export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxexport AWS_SECRET_ACCESS_KEY=hsagkghkshhdljfdjfjdjkd

4. Setup AWS CLI — Again this is not must but good to have.

On Mac

On Other OS

5. Configure AWS CLI

Section 2 — Setup Akamai API

Follow the easy steps mentioned in link below to create your api client on akamai and store .edgerc file . Make sure that you give permission to your api client to manage

a) Akamai Edge DNS

b) Akamai PAPI (Property Manager API)

c) Akamai Application Security Configuration

Section 3 — Setup Terraform

Install Terraform

Section 3 —Structure your terraform files

Four types of file that we are going to use within terraform ecosystem:-

  1. Resource specific *.tf file — provision/manage resources
  2. variables.tf — Variables declaration file
  3. terraform.tfvars — values of variables
  4. Output.tf — returning details about the managed resources

Although there is no specific rule that terraform dictates on defining resources i.e. you can have all resources in single *.tf file let’s say main.tf or you can have smaller chunks for e.g. akamai.tf for akamai specific resources whereas aws.tf for Aws specific resources. I prefer structured pattern with small chunks, reason being you can have different team managing Akamai v/s aws, further you can have separate team managing aws network v/s compute v/s web server etc. For this example here is my structure of tf files.

My terraform structure is below:-

As you can see in above screenshot, i have different tf file for different part of solution. Let’s look at each tf file one by one, i will start in logical order i.e. first aws network setup(aws-network-setup.tf), then aws security group(aws-sg-setup.tf) , followed by ec2 setup including web server installation and website hosting(aws-ec2-setup.tf) and then Akamai related stuff like property provisioning i.e. CDN configuration (akamai-property.tf), appsec for securing the website(akamai-appsec.tf) and akamai-dns(akamai-dns.tf) for setting up records in akamai Edge DNS to publish the website to public internet.

Section 4 — Start writing terraform code

  1. aws-network-setup.tf — As i said earlier this is the file where we will put code to build network infrastructure within AWS cloud

Here is the content of my file

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
akamai = {
source = "akamai/akamai"
version = "1.9.0"
}
}
}
provider "aws" {
region = var.aws_region
# their is no need to specify access credentials as we are setting them as env variable in the shell
}
# Create a VPC
resource "aws_vpc" "app_vpc" {
cidr_block = var.vpc_cidr
tags = {
Name = "akamai-vpc"
}
}
# Create an Internet gateway
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.app_vpc.id
tags = {
Name = "akamai_vpc_igw"
}
}
# Create a Public Subnet
resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.app_vpc.id
cidr_block = var.public_subnet_cidr
map_public_ip_on_launch = true
availability_zone = "us-east-1a"
tags = {
Name = "akamai_public_subnet"
}
}
# Create a Route table
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.app_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
Name = "akamai_public_rt"
}
}
#Associate route table
resource "aws_route_table_association" "public_rt_asso" {
subnet_id = aws_subnet.public_subnet.id
route_table_id = aws_route_table.public_rt.id
}

Above code consists of :-

a) terraform block — that defines the provider’s i am going to work with along with versions for the provider. Clearly we want to use Akamai and AWS so both has been defined here.

b) Next block is about provider aws that is there to define aws region. This can be avoided by using environment variable.

c) Other resources block are to provision vpc, subnet, internet gateway (igw), route table and association of route table and subnet.

Please note that i have used var in the code, that is for variablizing the code so that it can be reused. It is generally a good practice to keep your code DRY by using variables. We will come to variable later in this blogpost.

2. aws-sg-setup.tf — This file consists of security group, a kind of firewall to control inbound and outbound traffic from your instances.

resource "aws_security_group" "sg" {
name = "allow_ssh_icmp_https"
description = "Allow ssh icmp http/s inbound traffic"
vpc_id = aws_vpc.app_vpc.id
ingress {
description = "SSH Traffic"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
description = "HTTP Traffic"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
description = "HTTPS Traffic"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
description = "ICMP Traffic"
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = "akamai_allow_traffic"
}
}

Above file consists of various ingress and egress rules. I have allowed ingress for http/s, icmp and ssh traffic from any host(it can be much more restrictive but for my demo i wanted to keep it simple) and egress to any site.

3. aws-ec2-setup.tf — This file consists of EC2 provisioning and website configuration.

resource "aws_key_pair" "terraform-keys" {
key_name = "terraform-keys"
public_key = "${file("${path.module}/ec2_id_ed25519.pub")}"
}
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
key_name = "terraform-keys"
subnet_id = aws_subnet.public_subnet.id
security_groups = [aws_security_group.sg.id]
user_data = "${file("apache_mod.txt")}"
tags = {
Name = "akamai_web_instance"
}
volume_tags = {
Name = "akamai_web_instance"
}
}

First block in above code is to upload instance key to manage the ec2 instance. If you already don’t have keys then you can easily create it using openssh cli. See below document for more details

Once you are done with creating keys than have a look at second block, which is about provisioning aws EC2 instance:-

ami_id — this is an image that can be yours or publicly available free or paid one. For this experiment we are going to use free Amazon linux image i.e. ami-0c02fb55956c7d316 as of now. Please note that these ami id keeps on changing as version upgrades so best way is to find it either using aws cli or login into console and find it.

instance_type — defines processing power for EC2 instance. I will use t2.micro which is covered under free tier.

Key-Name — this is the key that we are going to use for logging into our EC2 instance

subnet-id and security_groups — are the one that we defined earlier in the network section.

user-data — this blocks give us opportunity to run a script just after instance is provisioned. We are going to use it for building our Website. Here is my apache.txt

#!/bin/sh
sudo echo Script started > /tmp/script.log
FILE="/tmp/index.html"
CONFIG_FILE="/tmp/origin.<site_name>.conf"
SERVER_CONFIG_FILE="/etc/apache2/conf-available/servername.conf"
sudo /bin/cat <<EOF >$FILE
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head><title>Here you are Papy</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><style>
.videoWrapper { position: absolute;top: 0;left: 0;width: 100%;height: 100%;background-image: linear-gradient(to top, #86377b 20%, #27273c 80%);}
.videoWrapper iframe { top: 10;left: 50;width: 100%;height: 100%;}
.centered {position: absolute;top: 10%;left: 35%;}</style>
</head>
<body>
<div class="videoWrapper">
<div class="centered"><H1 style="color:#D83623;font-family: Impact, Charcoal, sans-serif;text-shadow: 1px 2px #FFFFF;">What is life <b> if not on the Edge :D !!!</b></h1> </div>
<iframe src="https://player.vimeo.com/video/563317583?autoplay=1&color=ff0179&title=0&byline=0&portrait=0" width="1024" height="768" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>
</div>
</body>
</html>
EOF
sudo /bin/cat <<EOF >$CONFIG_FILE
<VirtualHost *:80>
ServerAdmin admin@<site_name>
ServerName origin.<site_name>
ServerAlias origin.<site_name>
DocumentRoot /var/www/origin.<site_name>/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
EOF
sudo yum install -y httpd
sudo cp $FILE /var/www/html/index.html
sudo systemctl enable httpd
sudo systemctl start httpd
#Setting up new site <site_name>
sudo mkdir -p /var/www/origin.<site_name>/html
sudo chown -R $USER:$USER /var/www/origin.<site_name>/html
sudo chmod -R 755 /var/www/origin.<site_name>
sudo cp $FILE /var/www/origin.<site_name>/html/index.html
sudo cp $CONFIG_FILE /etc/apache2/sites-available
sudo a2ensite /etc/apache2/sites-available/origin.<site_name>.config
sudo /bin/cat <<EOF >$SERVER_CONFIG_FILE
ServerName origin.<site_name>
EOF
sudo systemctl restart httpd

In above script we are creating index.html, creating apache config file, installing apache, making changes to host web server on apache and restarting the apache. I have redacted the above script to hide my origin hostname.

Now we are done with AWS related stuff, oof might be looking too much of work but trust me once you start using it, it is going to save lot of time and money.

If you are interested then move to part II of this series where we will look into akamai terraform files and provision the resources.

https://deepakjd2004.medium.com/cloud-agnostic-secure-delivery-of-a-website-on-akamai-edge-platform-using-terraform-part-ii-fd72f43bb0e8

Code Repo — In case you are interested in checking out the code

--

--