AWS at the command line

Amazon Web Services (AWS) at the command line with AWS CLI

Amazon Web Services (AWS) is the biggest public cloud provider and has released a set of tools to help out sysadmins and developers for integrating with their infrastructure.

The three tools we are going to discuss in this article are three of AWS’s most-used and well-known tools:

  • botocore: Low-level Python library
  • boto3: High level Python library
  • awscli: Command-line interface written in Python

All those tools are currently available in Fedora (22+) and EPEL (7).

Getting started with AWS CLI

Let’s start to analyze this CLI application that allows you to do everything you can from the Amazon Dashboard (and more).

To install it, run the following command in a terminal.

$ sudo dnf install awscli

Since this program installs bash and zsh shell completion, you’ll have to restart your shell to see it working, since both shells check for auto-completion scripts only when they are started.

At this point you’ll need to set up your account. If you don’t have an AWS account, you can set one up easily following the official guide (they do have a pretty big free tier for new users).

If you log in to your account from the dashboard and go to the IAM page, you can see your AWS Access Key ID and your AWS Secret Access Key. You will also need to associate a permission set for the user.

Once you have found the keys and associate a permission set, you can move to your terminal and proceed with configuring your AWS CLI.

$ aws configure
AWS Access Key ID [None]: copy-and-paste-your-access-key
AWS Secret Access Key [None]: copy-and-paste-your-secret-access-key-here
Default region name [None]:
Default output format [None]: 

For example, mine is:

aws configure
AWS Access Key ID [None]: XXXXXXXXXXXXXXXXXXXX
AWS Secret Access Key [None]: XXXXXXX/XXXXXXXXXXXXXXXXXXXX/XXXXXXX
Default region name [None]: eu-central-1
Default output format [None]

We can check if everything worked by running this command.

$ aws ec2 describe-instances --region eu-west-1

If something went wrong, you’ll receive an error something like:

A client error (UnauthorizedOperation) occurred when calling the DescribeInstances operation: You are not authorized to perform this operation.

This means the credentials you provided to the AWS CLI do not have the permissions for the required resource (in this case, list the EC2 instances in use for the region

eu-west-1

).

If everything worked as expected, you should receive something like:

{
    "Reservations": []
}

This is because you don’t have any instances yet.

Amazon Web Service Networking

Unlike the case with other providers, when you create a new AWS account, you receive an account with a lot of configurations already in place. This should help minimize the number of things you have to do before you are able to start using their services. We are going to query the AWS CLI interface to find out the ones we need to create for our first instance.

To be able to get your feet wet in the AWS world, it’s important to know a couple of things about AWS data centers and networking.

Data centers in the AWS world are not shown to the user. The user can only see Availability Zones (AZ) and Regions. You can think of AZs as if they were single data centers. It’s not actually known if they are individual data centers (some are probably single data centers and others are not), but they behave in a very similar way. Each AZ should behave independently from the others to achieve High Availability, but they are connected with other AZs in the same Region using low-latency private connections. Each Region is a geographic area and is completely independent from the other Regions. Regions are not connected directly among themselves and use (semi-)public connections.

As for networking, in the AWS world, there are Virtual Private Networks (VPC) that can be compared to physical networks. You can have multiple VPCs in each Region, even with conflicting IPs, because every VPC is a completely disconnected network (unless you configure them that way). Every VPC can have one or more sub-networks. Every VPC will not span among regions, while sub-networks are limited to single Availability Zones.

To map your current VPC, you can run:

$ aws ec2 describe-vpcs --region eu-west-1

and you will receive in response something like the following:

{
    "Vpcs": [
        {
            "VpcId": "vpc-f295b597",
            "CidrBlock": "172.31.0.0/16",
            "IsDefault": true,
            "State": "available",
            "DhcpOptionsId": "dopt-4700ee22",
            "InstanceTenancy": "default"
        }
    ]
}

There is already a VPC created in the Region, and it uses the IPs in the class 172.31.0.0/16. Also you can notice that this VPC has an ID (vpc-xxxxxxxx). In AWS, everything has an ID and usually you will need to reference objects (in AWS, the objects are not named, so the only way to reference an object is by using its ID). IDs are composed in a semi-consistent way, usually by [type]-[8 characters].

To see the sub-networks you have in the region, you have to run:

$ aws ec2 describe-subnets --region eu-west-1

You will receive something like the following message in response.

{
    "Subnets": [
        {
            "State": "available",
            "AvailabilityZone": "eu-west-1c",
            "CidrBlock": "172.31.32.0/20",
            "VpcId": "vpc-f295b597",
            "SubnetId": "subnet-66301d5c",
            "MapPublicIpOnLaunch": true,
            "DefaultForAz": true,
            "AvailableIpAddressCount": 4091
        },
        {
            "State": "available",
            "AvailabilityZone": "eu-west-1b",
            "CidrBlock": "172.31.16.0/20",
            "VpcId": "vpc-f295b597",
            "SubnetId": "subnet-f37eeeaa",
            "MapPublicIpOnLaunch": true,
            "DefaultForAz": true,
            "AvailableIpAddressCount": 4091
        },
        {
            "State": "available",
            "AvailabilityZone": "eu-west-1a",
            "CidrBlock": "172.31.0.0/20",
            "VpcId": "vpc-f295b597",
            "SubnetId": "subnet-ba89f4cd",
            "MapPublicIpOnLaunch": true,
            "DefaultForAz": true,
            "AvailableIpAddressCount": 4091
        }
    ]
}

As you can see, we have multiple sub-networks (one per Availability Zone). Just like for the VPC, the sub-networks also have IDs (subnet-xxxxxxxx). The sub-network IDs are very important to create an EC2 instance, because when you create an EC2, you have to tell Amazon in which sub-network you want to place the instance.

Running your first instance via AWS CLI

If you want to run an Amazon EC2 instance (a computing node), you can do it for free, thanks to the AWS Free Tier.

To do so from the CLI interface, you can simply execute:

$ aws ec2 run-instances --image-id ami-cf0cd3bc --count 1 --instance-type t1.micro --region eu-west-1 --subnet-id subnet-ba89f4cd

The APIs will give you a long, verbose response that will look similar to the following format.

{
    "OwnerId": "205092332101",
    "ReservationId": "r-020a8fbfb1f03e6d5",
    "Groups": [],
    "Instances": [
        {
            …
        }
    ]
}

The full output was trimmed from the article, but you will see the full output when you run the command.

The APIs provide you a lot of information about the instance that is being created. One interesting value it provides — close to the end of the response — is the State. In the example, it is pending. This is because the response to the command is immediate, but the instance will not be created instantaneously.

Listing active instances

Now that you have an instance running, you can re-run the first command we used in the article:

$ aws ec2 describe-instances --region eu-west-1

and you should receive something like this:

{
    "Reservations": [
        {
            "ReservationId": "r-020a8fbfb1f03e6d5",
            "Groups": [],
            "Instances": [
                 …
            ],
            "OwnerId": "205092332101"
        }
    ]
}

Again, the output was trimmed but yours will look much longer.

This response may be somewhat confusing, because it seems like it’s listing reservations instead of instances. This is because of the way Amazon Web Services manages invoicing of instances.

An important thing to notice is the Instance has an ID in a different format from the standard we have seen so far. It will look something like

i-xxxxxxxxxxxxxxxxx

.

Terminating an instance with AWS CLI

As the final task of this tutorial, we are going to terminate (delete) the instance we created. To do so, run the following command.

$ aws ec2 terminate-instances --instance-ids i-02ea0ea7852a2ae86 --region eu-west-1

The APIs should respond as follows.

{
    "TerminatingInstances": [
        {
            "PreviousState": {
                "Code": 16,
                "Name": "running"
            },
            "CurrentState": {
                "Code": 32,
                "Name": "shutting-down"
            },
            "InstanceId": "i-02ea0ea7852a2ae86"
        }
    ]
}

Now that we have terminated the instance, we can re-execute the first command we used in the article once more.

$ aws ec2 describe-instances --region eu-west-1

We should receive something like this.

{
    "Reservations": [
        {
            "ReservationId": "r-020a8fbfb1f03e6d5",
            "Groups": [],
            "OwnerId": "205092332101",
            "Instances": [
                {
                    "StateTransitionReason": "User initiated (2016-02-25 16:01:23 GMT)",
                    "PrivateDnsName": "",
                    "ImageId": "ami-cf0cd3bc",
                    "LaunchTime": "2016-02-25T14:34:22.000Z",
                    "State": {
                        "Code": 48,
                        "Name": "terminated"
                    },
                    "VirtualizationType": "paravirtual",
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "AmiLaunchIndex": 0,
                    "NetworkInterfaces": [],
                    "RootDeviceName": "/dev/sda",
                    "Architecture": "x86_64",
                    "SecurityGroups": [],
                    "ClientToken": "",
                    "RootDeviceType": "ebs",
                    "Placement": {
                        "AvailabilityZone": "eu-west-1a",
                        "Tenancy": "default",
                        "GroupName": ""
                    },
                    "EbsOptimized": false,
                    "KernelId": "aki-52a34525",
                    "InstanceType": "t1.micro",
                    "PublicDnsName": "",
                    "ProductCodes": [],
                    "StateReason": {
                        "Message": "Client.UserInitiatedShutdown: User initiated shutdown",
                        "Code": "Client.UserInitiatedShutdown"
                    },
                    "BlockDeviceMappings": [],
                    "Hypervisor": "xen",
                    "InstanceId": "i-02ea0ea7852a2ae86"
                }
            ]
        }
    ]
}

You will notice that the instance is not in a “terminated” state (so it’s in the process of dying) and you are not paying it. After a while, the terminated instances will disappear and you’ll be back where we first started.


Image courtesy Nicolas Raymond – originally posted to Flickr as Sunset Clouds – HDR

Using Software

1 Comment

  1. I may finally be well informed enough to give AWS a spin. Thanks for the informative article..

Comments are Closed

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. Fedora Magazine aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. The Fedora logo is a trademark of Red Hat, Inc. Terms and Conditions