Awless tutorial: Try a smarter CLI for AWS

A guided tour of the Awless CLI for Amazon Web Services, an alternative to the AWS CLI with simpler syntax, smart defaults, and powerful templates

1 2 Page 2
Page 2 of 2

Use an Awless template to create subnets and routing

Create a text file called with the following content:

# Filename: “” 
# 2 public subnets in different AZs attached to internet gateway
pubSub1 = create subnet cidr= vpc=@wordpress-vpc name=wordpress-public-subnet-1 availabilityzone={az1}
update subnet id=$pubSub1 public=true
pubSub2 = create subnet cidr= vpc=@wordpress-vpc name=wordpress-public-subnet-2 availabilityzone={az2}
update subnet id=$pubSub2 public=true rt = create routetable vpc=@wordpress-vpc
create route table=$rt cidr= gateway={vpc.internetgateway}
attach routetable id=$rt subnet=$pubSub1
attach routetable id=$rt subnet=$pubSub2

# 2 private subnets in different AZs
privSub1 = create subnet cidr= vpc=@wordpress-vpc name=wordpress-private-subnet-1 availabilityzone={az1}
privSub2 = create subnet cidr= vpc=@wordpress-vpc name=wordpress-private-subnet-2 availabilityzone={az2}  

# NAT Gateway in public subnet with a fixed IP
ip = create elasticip
natgw = create natgateway elasticip-id=$ip subnet=@wordpress-public-subnet
check natgateway id=$natgw state=available timeout=180  

# Routing between private subnets and NAT gateway
natgw_rtable = create routetable vpc=@wordpress-vpc
attach routetable id=$natgw_rtable subnet=$privSub1
attach routetable id=$natgw_rtable subnet=$privSub2
create route cidr= gateway=$natgw table=$natgw_rtable

Run this template with the awless run command, providing the file path and the required parameters on the command line. If you don’t know the list of available AZs, Awless can list them for the current region:

>awless list availabilityzones 
|   NAME ▲   |   STATE   |  REGION   | MESSAGES |
| us-east-1a | available | us-east-1 |          |
| us-east-1b | available | us-east-1 |          |
>awless run az1=us-east-1a az2=us-east-1e

Use an Awless template to configure load balancing

Now that the network is set up, we will use a second template to configure the load balancer:

# Filename: “” 
# Create the load balancer security group
lbsecgroup = create securitygroup vpc=@wordpress-vpc description="authorize HTTP from the internet" name=wordpress-lb-securitygroup
update securitygroup id=$lbsecgroup inbound=authorize protocol=tcp cidr= portrange=80
# Provision the load balancer listening in the public subnets, with its target group and HTTP listener
tg = create targetgroup name=wordpress-workers port=80 protocol=HTTP vpc=@wordpress-vpc
update targetgroup id=$tg stickiness=true
lb = create loadbalancer name=wordpress-loadbalancer subnets={public.subnets} securitygroups=$lbsecgroup
create listener actiontype=forward loadbalancer=$lb port=80 protocol=HTTP targetgroup=$tg

We just need to grab the IDs of the public subnet and run the template:

>PUBLIC_SUBNETS=$(awless show wordpress-public-subnet-1 —values-for ID),$(awless show wordpress-public-subnet-2 —values-for ID) >awless run public.subnets=$PUBLIC_SUBNETS

Use an Awless template to set up the database

Now that our load balancer is set up, we create the RDS instance in a third template:

# Filename: “” 
# Database security group (authorize access from private subnets to port 3306)
dbsec = create securitygroup name=wordpress-database-securitygroup vpc=@wordpress-vpc description="authorize mysql port 3306 from private subnets"
update securitygroup id=$dbsec inbound=authorize cidr= portrange=3306
update securitygroup id=$dbsec inbound=authorize cidr= portrange=3306
# Distribute the MariaDB database in the 2 subnets
dbsub = create dbsubnetgroup name=wordpress-dbsubnets description="subnets for wordpress databases" subnets={private.subnets}
create database engine=mariadb id=wordpress-database password={dbpassword} size=8 type=db.t2.micro username=wordpress dbname=wordpress multiaz=true subnetgroup=$dbsub vpcsecuritygroups=$dbsec

Run this template with:

>PRIVATE_SUBNETS=$(awless show wordpress-private-subnet-1 —values-for ID),$(awless show wordpress-private-subnet-2 —values-for ID) 
>awless run private.subnets=$PRIVATE_SUBNETS dbpassword=mysqlpassword

The provisioning of the database may take a few minutes before it is fully usable. We will need to wait until the database is available:

>awless check —force database id=wordpress-database state=available timeout=600

The —force flag disables the confirmation step before executing the command. You can now grab a cup of coffee as the database provisioning may take more than 10 minutes in some regions.

Use an Awless template to enable Auto Scaling

We will use an AWS Auto Scaling group to ensure that there are at least two WordPress instances running. The following template creates the Auto Scaling group and provisions the instances, reusing best practices we already saw in Challenge 1 (security groups, user data provisioning, etc.).

# : 
# Create the security group and launch configuration for the instances
instSecGroup = create securitygroup vpc=@wordpress-vpc description="HTTP + SSH within VPC" name=wordpress-private-secgroup
update securitygroup id=$instSecGroup inbound=authorize cidr= portrange=22
update securitygroup id=$instSecGroup inbound=authorize cidr= portrange=80
launchconf = create launchconfiguration image={instance.image} keypair={keypair} name=wordpress-launch-configuration type=t2.micro userdata= securitygroups=$instSecGroup
create scalinggroup desired-capacity=2 launchconfiguration=$launchconf max-size=2 min-size=2 name=wordpress-scalinggroup subnets={private.subnets} targetgroups=@wordpress-workers

We get the database host name and run the template:

>DBHOST=$(awless show wordpress-database —values-for PublicDNS) 
>awless run private.subnets=$PRIVATE_SUBNETS keypair=johnkey dbname=wordpress dbhost=$DBHOST dbuser=wordpress dbpassword=mysqlpassword

To connect to our domain, we wait until the load balancer is active to get its domain name:

>awless check loadbalancer id=@wordpress-loadbalancer state=active timeout=180 
>awless show wordpress-loadbalancer —values-for PublicDNS

When accessing the URL, you might receive a 50X error at first (“The instances are provisioning”). Refresh periodically until success.

Well done! You are running a secure, highly available WordPress deployment with a replicated and managed database, ready for production use (provided you also set up HTTPS).

Challenge 3: Use AWS serverless services

Serverless services are multi-tenant instances operated by Amazon. There is no allocated instance for the AWS customer and no low-level access. As a result, the cost of these services is much lower than dedicated alternatives and proportional to real usage. These services—S3, CloudFront, Lambda, DynamoDB, etc.—represent a new way of architecting software.

Let’s optimize our WordPress deployment with serverless services. Our database is managed and can grow easily, but serving static resources through an instance and a database is an inefficient use of resources. Furthermore, it would require users from all around the world to query a single region that might be slow to reach.

It is vastly more efficient to use a dedicated service, together with a content delivery network (CDN), to host static resources. Amazon’s object storage service, S3, allows you to store files in buckets and make them available through direct HTTP access. An additional CDN service, CloudFront, allows you to distribute and cache the content in 70 locations worldwide. Naturally, CloudFront is pluggable in front of S3.

Before we begin, let’s remove the resources we created for Challenge 2 that we no longer need, using awless revert. We can use awless log to locate the IDs of the last two template executions, which created the RDS database and provisioned the EC2 instances:

>awless revert 01BM9DBTH1Q1579HXHVF377GF7 # Revert of
>awless revert 01BM9CYN3TAYGK5FYQMHWCH83Y # Revert of

Note that you can do the two reverts in parallel in two terminals—a handy option as the database deletion may take a while.

The infrastructure for Challenge 3 is slightly different than for Challenge 2. Note just a few changes:

  • A bucket on S3 to store the WordPress files
  • A CloudFront CDN distribution to deliver the objects stored in the S3 bucket
  • A role enabling the WordPress instances to write to the bucket
  • A plug-in for WordPress that uploads static resources to S3

Create an S3 bucket and CloudFront distribution

Using Awless, applying all of these changes is straightforward. Generally, one line per resource is all that is needed:

>awless create bucket name=awless-wordpress-bucket 
>awless create distribution

While waiting for the CloudFront distribution to propagate (awless check distribution state=Deployed timeout=600), let’s deploy a new database using the template from Challenge 2:

>PRIVATE_SUBNETS=$(awless show wordpress-private-subnet-1 —values-for ID),$(awless show wordpress-private-subnet-2 —values-for ID) 
>awless run private.subnets=$PRIVATE_SUBNETS dbpassword=mysqlpassword

Assign an IAM role to EC2 instances

The WordPress instances need to write to the S3 bucket. An AWS best practice recommends assigning an IAM role to EC2 resources to get privileges. However, our user John has insufficient permissions to assign a role to the instances. We use -p admin to temporarily use the admin profile to grant John sufficient permissions:

>awless -p admin create policy name=AllowCreateAttachPolicy effect=Allow resource=\* description=\”Authorize the creation of policies\” action = iam:CreatePolicy, iam:DeletePolicy, iam:AttachRolePolicy, iam:DetachRolePolicy, iam:CreateRole, iam:DeleteRole, iam:CreateInstanceProfile, iam:DeleteInstanceProfile, iam:AddRoleToInstanceProfile, iam:RemoveRoleFromInstanceProfile, iam:PassRole, iam:ListInstanceProfiles 
>POLICY_ARN=$(awless -p admin show AllowCreateAttachPolicy —values-for arn)
>awless -p admin attach policy arn=$POLICY_ARN user=john

Use an Awless template to deploy our application

The template for the production-ready deployment of WordPress with S3 is available from a public gist. We will grab the required parameters and run the template:

>DBHOST=$(awless show wordpress-database —values-for PublicDNS) 
>PRIVATE_SUBNETS=$(awless show wordpress-private-subnet-1 —values-for ID),$(awless show wordpress-private-subnet-2 —values-for ID)
>URL=$(awless show wordpress-loadbalancer —values-for PublicDNS)
>CLOUDFRONT_URL=$(awless list distributions —filter origins=wordpress —sort modified —format tsv |tail -n1 |cut -f2)
>awless run dbhost=$DBHOST private.subnets=$PRIVATE_SUBNETS wordpress.url=$URL cdn.URL=$CLOUDFRONT_URL

Please specify (Ctrl+C to quit, Tab for completion):
dbpassword? mysqlpassword
keypair? johnkey
wordpress.password? wordpresspassword

Congratulations, your highly available blog application is now ready to publish worldwide and draw visitors around the globe, while efficiently keeping up with the load. If you’re willing to go beyond the already advanced concepts that we applied in this tutorial, I’ll leave you with two more tasks to try on your own.

  1. If you own a domain name, you can easily use Awless to set up a DNS entry with AWS Route53. Try awless create record —help to learn about the creation of DNS records.
  2. Create CloudWatch alarms to automatically increase the number of instances in Auto Scaling groups. Hint: You just have to follow the template detailed here.

Our hands-on tour shows how Awless simplifies IT operations in the AWS cloud. The project has gained traction quickly, collecting more than 3,000 stars on GitHub in only a few months of existence. You can learn more about the project on GitHub and in my introductory blog post on Medium. Awless already supports more AWS services beyond those featured in this quick overview, as well as more features for each service.

The project exists thanks to sponsorship by Wallix, a publicly traded cybersecurity software vendor, and is fully open source under the liberal Apache license. As such, Awless is open to contributions from the community, be it in the form of code contributions, documentation improvements, or just spreading the word.

New Tech Forum provides a venue to explore and discuss emerging enterprise technology in unprecedented depth and breadth. The selection is subjective, based on our pick of the technologies we believe to be important and of greatest interest to InfoWorld readers. InfoWorld does not accept marketing collateral for publication and reserves the right to edit all contributed content. Send all inquiries to

1 2 Page 2
Page 2 of 2