DEV Community

Cover image for Introduction to the AWS CLI
Donald Sebastian Leung
Donald Sebastian Leung

Posted on

Introduction to the AWS CLI

This post will walk you through setting up AWS CLI, an IAM administrator account for use with AWS CLI, and creating an AWS EC2 Ubuntu instance plus associated resources from the CLI.

Prerequisites

It is assumed that you:

  • Possess a working familiarity with the Linux command line and able to perform troubleshooting tasks
  • Have an AWS account
  • Know the basics of AWS services. At the very least, you should be able to provision an AWS EC2 instance through the web interface and connect to it
  • Are aware that following this hands-on session may incur monetary costs and you are solely responsible for any such costs

Introductory knowledge of cloud computing and the underlying technology (hypervisors, hardware virtualization, OS virtualization) would be beneficial.

With the prerequisites addressed, let's get started!

Preparation

Reference: Prerequisites to use the AWS CLI version 2

Log in to your AWS account. To use the AWS CLI securely, we need to set up an IAM(1) administrator account and associated access key(s) which will be used for authenticating against AWS and performing tasks through the CLI. Technically, you could set up access key(s) for your root account(2) and configure AWS CLI to use them, but AWS strongly recommends against it, for reasons similar to why you shouldn't log in to a Linux system directly as root and perform everyday tasks that way.

(1) Identity Access Management
(2) This is the account with an associated email address and password that you likely used to log in to the AWS web console

Visit the IAM console at https://console.aws.amazon.com/iam/ which should bring you to the dashboard. To the left of the dashboard under "Access management", click "Users":

IAM users

This brings you to a page where you can view and manage IAM users. Near the top right hand corner is an "Add users" button:

Add IAM user

Now you should see a form with two sections, "Set user details" and "Select AWS access type" (in that order). Under the first section, fill in "Administrator" as the username:

IAM administrator

In the next section, make sure "Access key - Programmatic access" is checked. Depending on your preferences, you may also wish to enable password access for logging in (as the IAM administrator) through the web console:

Enable programmatic access

Now click "Next: Permissions" near the bottom right hand corner:

Next: Permissions

This brings you to a page where you can "Set permissions" and "Set permissions boundary". The latter can be used to fine-tune the permissions of the IAM user which we will not cover here. For the former, ensure "Add user to group" is selected:

Add user to group

If you have not dealt with IAM before, you should have no IAM groups. Click "Create group" under "Get started with groups":

Create group

Now name your group "Administrators":

Group name: Administrators

And ensure the "AdministratorAccess" policy is checked:

AdministratorAccess

Click "Create group":

Create group

Back in "Add user to group", ensure your newly created group is checked:

Administrators

If you can't see your created group, you may need to click "Refresh" until it appears. Now click "Next: Tags":

Next: Tags

The following page allows you to associate tags (key-value pairs) with your IAM user. Since the IAM administrator is a general-purpose account that can perform almost all AWS tasks, there probably isn't much point associating it with tags, though a full discussion of tagging AWS resources and their uses can be found in https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html .

Click "Next: Review":

Next: Review

Confirm that everything looks fine, then click "Create user" to confirm the action:

Create user

Now the IAM administrator is created. Notice that you have not yet returned to the dashboard. Instead, you are shown the access key ID and secret access key of the IAM administrator, and this is the only time they will be shown. Therefore, it is imperative that you take note of these values and store them in a safe place, such as by downloading the associated CSV file:

Download access key ID and secret access key as CSV file

Now click "Close":

Close

Congratulations! You have successfully created an IAM administrator account with access key ID and secret access key which can be used with AWS CLI in a later section.

At this point, if you weren't simply following the instructions blindly, you might be wondering what security benefits using an IAM administrator provides over using the root account directly, if the former has (almost) all of the permissions of the latter anyway. In fact, if an attacker gains access to your IAM administrator account, they can perform almost any action on your account, except for a few privileged actions restricted to the root account as documented in https://docs.aws.amazon.com/accounts/latest/reference/root-user-tasks.html , such as:

  • Changing your account settings
  • Allowing IAM users to view your billing details
  • Closing your AWS account

So it's nearly as bad as having your root account compromised, but not quite. Either way, you should take great care not to leak your IAM administrator credentials, and definitely not your root account credentials! If it happens anyway, you should delete and recreate your IAM administrator account ASAP, with a new set of credentials.

Of course, if you know precisely what permissions are required for accessing a particular AWS service through the AWS CLI, you could (should) create a new IAM user with just those permissions to minimize the potential impact of leaking your IAM credentials to an attacker, but that is beyond the scope of this article.

Installing AWS CLI

Reference: Installing or updating the latest version of the AWS CLI

At the time of writing (December 2021), the latest version of AWS CLI is 2.x.x, though AWS CLI 1.x.x is still supported, with the former containing breaking changes that are not backward compatible with the latter. Here, we will install the newer version 2.x.x, and subsequent mentions of AWS CLI should be taken to imply 2.x.x unless otherwise noted.

AWS CLI is available on Linux, macOS and Windows. We'll assume here that you are installing AWS CLI onto a Linux environment:

  • Linux: just follow the instructions directly in the terminal
  • macOS: Spin up a Linux VM using your hypervisor of choice, e.g. VirtualBox, VMware Fusion or Parallels, and follow the instructions in the VM
  • Windows: use WSL2, or follow a similar approach as on macOS

If you plan to follow this article in another environment, you may have to adapt the instructions accordingly.

On Linux, you can install AWS CLI by following the instructions on the official website, or on most mainstream distributions through the system package manager. However, depending on the nature of your distribution, the version of AWS CLI provided by your system package manager may be outdated, possibly up to a full major version behind. For example, running apt-cache show awscli | grep -i version on Ubuntu 20.04 LTS gives:

Version: 1.18.69-1ubuntu0.20.04.1
Version: 1.17.14-1
Enter fullscreen mode Exit fullscreen mode

Therefore, in order to access the latest features of AWS CLI, it is highly recommended to install directly from the official website.

The installation is a simple 3-step process: fetching the zip archive from upstream, unpacking it, and executing the install script as root:

$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
Enter fullscreen mode Exit fullscreen mode

If your machine uses ARM architecture, simply replace x86_64 in the first command with aarch64.

Updating AWS CLI is equally simple: follow the instructions above as with first install, but pass the --update flag to the last command, as follows:

$ sudo ./aws/install --update
Enter fullscreen mode Exit fullscreen mode

Unfortunately, there is no uninstall script so if you wish to uninstall AWS CLI (assuming you did so through the official website) and know exactly what you are doing, you'll have to manually find and remove the aws binary and associated resources. By default, the binary is located under /usr/local/bin and resources under /usr/local/aws-cli.

Check which version of AWS CLI is installed:

$ aws --version
aws-cli/2.4.7 Python/3.8.8 Linux/5.11.0-43-generic exe/x86_64.ubuntu.20 prompt/off
Enter fullscreen mode Exit fullscreen mode

In my case, AWS CLI v2.4.7 is installed.

Print a help message (not very useful, unfortunately):

$ aws --help
usage: aws [-h] [--profile PROFILE] [--debug]

optional arguments:
  -h, --help         show this help message and exit
  --profile PROFILE
  --debug
Enter fullscreen mode Exit fullscreen mode

To learn more about the subcommands provided by AWS CLI, refer to the online documentation: https://awscli.amazonaws.com/v2/documentation/api/latest/index.html . Alternatively, as mentioned in online documentation, the proper way of obtaining useful help information directly from the AWS CLI is aws help or aws <command> help, which opens the top-level man page and an appropriate man page for the AWS command respectively.

Configuring AWS CLI to use our IAM administrator

Reference: Configuration basics - AWS Command Line Interface

The command to configure AWS CLI is (unsurprisingly) configure:

$ aws configure
Enter fullscreen mode Exit fullscreen mode

This prompts you to enter 4 pieces of information:

  • AWS Access Key ID: this is the access key ID of your IAM administrator. You should have saved this information in a CSV file when creating your IAM user
  • AWS Secret Access Key: this is the secret access key of your IAM administrator. Again, refer to the CSV file you downloaded
  • Default region name: recall that AWS resources are divided into regions and availability zones. Enter the name of the region you would like to use by default, if no region is explicitly specified. For example, I live in Hong Kong so I might set it to ap-east-1. You can get a list of region names through the web interface, and later through the aws ec2 describe-regions command
  • Default output format: what type of output the AWS CLI should generate by default when most commands are run. For example, setting this to json or yaml causes AWS CLI to generate JSON and YAML output by default respectively which could be piped to another program or redirected to an output file for further processing. In this tutorial we will be using the AWS CLI interactively so we could set it to table for human-friendly output, though you can set it to whatever value you see fit

When the command completes, the information is saved in a default profile that AWS CLI uses for authentication, if no profile is explicitly specified. You can think of a profile as a particular named account, though there is nothing stopping you from creating two different named profiles with the same user credentials.

The information you entered is saved in two separate files, $HOME/.aws/config and $HOME/.aws/credentials, where the former stores non-sensitive values and the latter sensitive ones:

$ cat $HOME/.aws/config
[default]
region = ap-east-1
output = table
$ cat $HOME/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Enter fullscreen mode Exit fullscreen mode

To configure a profile other than default, pass the --profile flag followed by the profile name, as follows:

$ aws configure --profile <profile>
Enter fullscreen mode Exit fullscreen mode

To learn more about the configure command, run:

$ aws configure help
Enter fullscreen mode Exit fullscreen mode

or refer to the online documentation.

Provisioning an AWS EC2 Ubuntu instance with AWS CLI

Reference: Using Amazon EC2 with the AWS CLI

The command for managing EC2-related services is ec2. Skim through the man page:

$ aws ec2 help
Enter fullscreen mode Exit fullscreen mode

For example, we can view a list of available regions and their associated information:

$ aws ec2 describe-regions
Enter fullscreen mode Exit fullscreen mode

View the output in YAML:

$ aws ec2 describe-regions --output yaml
Enter fullscreen mode Exit fullscreen mode

Get the output in JSON and redirect to an output file, for use with another program at a later date:

$ aws ec2 describe-regions --output json > regions.json
Enter fullscreen mode Exit fullscreen mode

View the availability zones in the default region:

$ aws ec2 describe-availability-zones
Enter fullscreen mode Exit fullscreen mode

View the availability zones in the us-west-1 region:

$ aws ec2 describe-availability-zones --region us-west-1
Enter fullscreen mode Exit fullscreen mode

View information on EC2 instances in the default region:

$ aws ec2 describe-instances
Enter fullscreen mode Exit fullscreen mode

View information on security groups in the default region:

$ aws ec2 describe-security-groups
Enter fullscreen mode Exit fullscreen mode

View information on key pairs in the default region:

$ aws ec2 describe-key-pairs
Enter fullscreen mode Exit fullscreen mode

View information on instance types available in the default region:

$ aws ec2 describe-instance-types
Enter fullscreen mode Exit fullscreen mode

Now that we've taken a look at the man page and tried out some commands for viewing EC2-related information, let's move on and provision a new instance with the AWS CLI. But before we continue, I've realized that I actually find table output difficult to parse and would prefer reading JSON output instead. Let's also change our default region to us-west-1 for performing experiments, as I have a production web server running in the ap-east-1 region (actually just my personal website) and want to minimize the chances of messing that up by accident.

To change the settings in the default profile, we just have to run configure again:

$ aws configure
Enter fullscreen mode Exit fullscreen mode

For fields that you do not intend to change, simply leave it blank and press Enter. Here, I skip through access key ID and secret access key since they haven't changed, but enter us-west-1 for the default region name and json for the output format when prompted.

Now let's see what Ubuntu AMIs are available in our new default region. With the web interface, we can just search for the term "Ubuntu" and look at the results, and we can usually expect the first few results to contain what we are looking for. However, with the AWS CLI, if we just list all images without filtering them beforehand, it will take at least a few dozen seconds fetching all of the detailed information on all types of images (not just AMIs) and it would be infeasible to skim through the entire list to find what we are looking for. Therefore, take a look at the associated man page and I encourage you to try out various filtering options on your own:

$ aws ec2 describe-images help
Enter fullscreen mode Exit fullscreen mode

After some experimentation on my own, here's what worked for me:

  • The name of the AMI should contain "ubuntu" (with lowercase "u")
  • The description should contain "20.04 LTS", so Ubuntu Bionic (18.04 LTS) images are not returned
  • The image architecture should be x86_64
  • The image type should be machine, so I don't get results for other non-AMI image types such as kernel and ramdisk images

Here's the command I used:

$ aws ec2 describe-images --filters \
  "Name=name,Values=*ubuntu*" \
  "Name=description,Values=*20.04 LTS*" \
  "Name=architecture,Values=x86_64" \
  "Name=image-type,Values=machine"
Enter fullscreen mode Exit fullscreen mode

And here's the first result that I get:

{
    "Architecture": "x86_64",
    "CreationDate": "2021-04-16T06:48:46.000Z",
    "ImageId": "ami-000773770ac55efb2",
    "ImageLocation": "aws-marketplace/ubuntu-minimal/images/hvm-ssd/ubuntu-focal-20.04-amd64-minimal-20210416-d5944ad4-5199-4cf3-ab4c-c2c4598f880b",
    "ImageType": "machine",
    "Public": true,
    "OwnerId": "679593333241",
    "PlatformDetails": "Linux/UNIX",
    "UsageOperation": "RunInstances",
    "ProductCodes": [
        {
            "ProductCodeId": "cn75kij0iclp333uyrx6uqp6z",
            "ProductCodeType": "marketplace"
        }
    ],
    "State": "available",
    "BlockDeviceMappings": [
        {
            "DeviceName": "/dev/sda1",
            "Ebs": {
                "DeleteOnTermination": true,
                "SnapshotId": "snap-01325cd2ee26537f0",
                "VolumeSize": 8,
                "VolumeType": "gp2",
                "Encrypted": false
            }
        },
        {
            "DeviceName": "/dev/sdb",
            "VirtualName": "ephemeral0"
        },
        {
            "DeviceName": "/dev/sdc",
            "VirtualName": "ephemeral1"
        }
    ],
    "Description": "Canonical, Ubuntu Minimal, 20.04 LTS, amd64 focal image build on 2021-04-16",
    "EnaSupport": true,
    "Hypervisor": "xen",
    "ImageOwnerAlias": "aws-marketplace",
    "Name": "ubuntu-minimal/images/hvm-ssd/ubuntu-focal-20.04-amd64-minimal-20210416-d5944ad4-5199-4cf3-ab4c-c2c4598f880b",
    "RootDeviceName": "/dev/sda1",
    "RootDeviceType": "ebs",
    "SriovNetSupport": "simple",
    "VirtualizationType": "hvm"
}
Enter fullscreen mode Exit fullscreen mode

This looks about right. Take a note of the image ID, that is, ami-000773770ac55efb2.

Now let's see what VPCs we have. This will be useful for creating an appropriate security group to be attached to our instance later.

$ aws ec2 describe-vpcs
Enter fullscreen mode Exit fullscreen mode

In my case, I only have a default VPC with ID vpc-6d7aaf0b.

Even though we will create a new security group, let's see what security groups we already have anyway:

$ aws ec2 describe-security-groups
Enter fullscreen mode Exit fullscreen mode

In my case, I only have a default security group, as follows:

{
    "Description": "default VPC security group",
    "GroupName": "default",
    "IpPermissions": [
        {
            "IpProtocol": "-1",
            "IpRanges": [],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "UserIdGroupPairs": [
                {
                    "GroupId": "sg-bc3d9df5",
                    "UserId": "477657529190"
                }
            ]
        }
    ],
    "OwnerId": "477657529190",
    "GroupId": "sg-bc3d9df5",
    "IpPermissionsEgress": [
        {
            "IpProtocol": "-1",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "UserIdGroupPairs": []
        }
    ],
    "VpcId": "vpc-6d7aaf0b"
}
Enter fullscreen mode Exit fullscreen mode

This security group blocks all inbound traffic (IpPermissions), so we won't be able to connect to our instance if we attach this security group to it, hence the need to create a new security group.

Skim through the man page:

$ aws ec2 create-security-group help
Enter fullscreen mode Exit fullscreen mode

Now let's create a new security group "UbuntuSG", with the VPC ID we obtained earlier:

$ aws ec2 create-security-group \
  --group-name UbuntuSG \
  --description "Security group for Ubuntu 20.04" \
  --vpc-id vpc-6d7aaf0b
Enter fullscreen mode Exit fullscreen mode

This prints a group ID on success. Take note of the group ID:

{
    "GroupId": "sg-047de2bb619edd924"
}
Enter fullscreen mode Exit fullscreen mode

If we obtain information on our newly created security group with ec2 describe-security-groups, we notice that no inbound traffic is allowed:

{
    "Description": "Security group for Ubuntu 20.04",
    "GroupName": "UbuntuSG",
    "IpPermissions": [],
    "OwnerId": "477657529190",
    "GroupId": "sg-047de2bb619edd924",
    "IpPermissionsEgress": [
        {
            "IpProtocol": "-1",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "UserIdGroupPairs": []
        }
    ],
    "VpcId": "vpc-6d7aaf0b"
}
Enter fullscreen mode Exit fullscreen mode

So we need to add inbound rules with ec2 authorize-security-group-ingress. Skim through the man page:

$ aws ec2 authorize-security-group-ingress help
Enter fullscreen mode Exit fullscreen mode

Now add an inbound rule for SSH (22/tcp) from anywhere. For optimal security, you can discover your public IP address and only allow SSH from that IP instead:

$ aws ec2 authorize-security-group-ingress \
  --group-id sg-047de2bb619edd924 \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-04c28eddbcd8b598a",
            "GroupId": "sg-047de2bb619edd924",
            "GroupOwnerId": "477657529190",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 22,
            "ToPort": 22,
            "CidrIpv4": "0.0.0.0/0"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Note that we used the group ID here. You can also specify the group name instead if that's easier.

Now our security group looks like this:

{
    "Description": "Security group for Ubuntu 20.04",
    "GroupName": "UbuntuSG",
    "IpPermissions": [
        {
            "FromPort": 22,
            "IpProtocol": "tcp",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "ToPort": 22,
            "UserIdGroupPairs": []
        }
    ],
    "OwnerId": "477657529190",
    "GroupId": "sg-047de2bb619edd924",
    "IpPermissionsEgress": [
        {
            "IpProtocol": "-1",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "UserIdGroupPairs": []
        }
    ],
    "VpcId": "vpc-6d7aaf0b"
}
Enter fullscreen mode Exit fullscreen mode

Another thing we need to connect to an instance is a key pair. Currently, I do not have any key pairs:

$ aws ec2 describe-key-pairs
{
    "KeyPairs": []
}
Enter fullscreen mode Exit fullscreen mode

In my case, I have to create or import a key pair. If you do not already have a key pair, generate one with ssh-keygen. Since I already have a key pair, with my public key at $HOME/.ssh/id_rsa.pub, I can import it into AWS using ec2 import-key-pair. Skim through the man page:

$ aws ec2 import-key-pair help
Enter fullscreen mode Exit fullscreen mode

Now let's actually import the key:

$ aws ec2 import-key-pair \
  --key-name "MacBook Air Ubuntu 20.04" \
  --public-key-material fileb://$HOME/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode

Remember the key name.

With a security group and key pair, we can finally provision our AWS EC2 Ubuntu instance and connect to it. The subcommand for creating and starting an instance is ec2 run-instances:

$ aws ec2 run-instances help
Enter fullscreen mode Exit fullscreen mode

Let's use the following information:

  • AMI ID: ami-000773770ac55efb2
  • Instance type: t2.micro
  • Security group ID: sg-047de2bb619edd924
  • Key name: MacBook Air Ubuntu 20.04
$ aws ec2 run-instances \
  --image-id ami-000773770ac55efb2 \
  --instance-type t2.micro \
  --security-group-ids sg-047de2bb619edd924 \
  --key-name "MacBook Air Ubuntu 20.04"
Enter fullscreen mode Exit fullscreen mode

Chances are you will receive an OptInRequired error like I did:

An error occurred (OptInRequired) when calling the RunInstances operation: In order to use this AWS Marketplace product you need to accept terms and subscribe. To do so please visit https://aws.amazon.com/marketplace/pp?sku=cn75kij0iclp333uyrx6uqp6z

To the best of my knowledge, it is not possible to subscribe to an AWS Marketplace product programmatically, possibly to force the user to read the terms and conditions properly before accepting it. Follow the link shown in the error message, subscribe to the product and retry the same command.

On success, you should see relevant JSON info printed to the console, such as the instance ID.

Now check that the instance is running:

$ aws ec2 describe-instances
Enter fullscreen mode Exit fullscreen mode

For example, the state of my instance is:

{
    "Code": 16,
    "Name": "running"
}
Enter fullscreen mode Exit fullscreen mode

I also learn that the public IP address of my instance is 52.53.151.210, from the PublicIpAddress field.

Now connect to the instance via SSH (replace 52.53.151.210 with the public IP of your instance):

$ ssh ubuntu@52.53.151.210
Enter fullscreen mode Exit fullscreen mode

Congratulations! You have successfully provisioned an EC2 instance through the AWS CLI and connected to it.

Some additional subcommands for managing EC2 instances:

  • ec2 stop-instances for stopping instances
  • ec2 start-instances for starting existing instances that have been stopped
  • ec2 reboot-instances for requesting a reboot on existing instances

Cleaning up

Unless you plan to continue using the instance, terminate it, replacing the instance ID below as appropriate:

$ aws ec2 terminate-instances --instance-ids i-02eb9bb3b0989c57e
Enter fullscreen mode Exit fullscreen mode

Remember that we also created a security group and imported a key pair. You might want to keep them for use with future instances, but in my case, I will delete them as well:

$ aws ec2 delete-security-group --group-id sg-047de2bb619edd924
$ aws ec2 delete-key-pair --key-name "MacBook Air Ubuntu 20.04"
Enter fullscreen mode Exit fullscreen mode

Conclusion

We learned what the AWS CLI is, how to install it on Linux, how to configure an IAM administrator for use with the AWS CLI (and why it is important to do so), how to get help with the AWS CLI, the ec2 command and its various subcommands, and how we can combine those commands to manage EC2 instances almost entirely from the CLI. But that is just the tip of the iceberg. AWS is so much more than just EC2, and I encourage you to take the time to explore other AWS services and how they can be manipulated through the AWS CLI.

I hope you enjoyed this hands-on session and found it useful. Stay tuned ;-) Until then, happy holidays!

References

Discussion (0)