AWS EC2 VPC CLI

作者:Kyle Rankin

新工作带来的全新开始总是令人兴奋。我的前一份工作和新工作都始于从零开始构建新基础设施的机会。在这两种情况下,正如初创公司基础设施的早期阶段常见的那样,一切都将使用亚马逊网络服务(AWS)构建,特别是使用其弹性云计算(EC2)基础设施。在两份工作之间的几年里,发生了两件重大的变化,使我对基础设施有了全新的方法,而这些正是我将在本文中探讨的内容:亚马逊的虚拟私有云(VPC)和AWS命令行工具。

VPC已经存在一段时间了,当我开始前一个基础设施的工作时它就存在了,但它只是一个额外的功能。当时,您默认使用亚马逊现在称之为“EC2 Classic”的服务,这意味着您实际上与EC2上的所有其他人共享一个内部IP空间。使用VPC,您可以定义不同的子网,包括那些只有不可通过互联网路由的RFC1918 IP地址的子网。您可以选择哪些主机获得外部IP,哪些不获得,并且您可以定义主机所在的子网,甚至可以在需要时为其分配特定的内部IP。此外,您可以更好地控制安全组(允许您为主机组分配防火墙规则),并且您可以过滤传入(入口)流量和传出(出口)流量。您甚至可以在主机生成后添加或删除安全组,这在EC2 Classic中是不可能实现的。

今天,新的亚马逊账户仅限VPC。很明显,亚马逊正在逐步淘汰EC2 Classic,不仅通过将其称为“Classic”并将VPC作为默认设置,还通过创建仅在VPC上可用的新型低成本实例类型。即使默认情况下,VPC附带的子网的行为方式与EC2 Classic上的公共和私有IP非常相似,但一旦您考虑私有子网,仍然存在足够的差异和潜力,这迫使您对构建事物的方式采取全新的方法。

亚马逊命令行界面

对于我的经常阅读的读者来说,当我最初开始使用亚马逊基础设施时,我尽可能避免使用Web界面,而是坚持使用命令行工具,这可能不会感到惊讶。虽然那时有许多不同的库(例如Python的boto库)可用于通过软件与亚马逊的API进行交互,但亚马逊EC2的主要命令行界面被称为EC2 API Tools(或Ubuntu中的ec2-api-tools包)。它是基于Java的,并提供了一种通过名为ec2-<some function>的命令执行您可能在Web界面上执行的所有常见功能的方法。一旦您习惯了它,它还不错。我对EC2 API工具的主要抱怨是发出命令和获得响应之间的速度太慢了。

大约一年前,我发现亚马逊开发了一个新的基于Python的命令行工具,名为AWS CLI,并记下有机会时尝试一下。由于我已经有利用EC2 API工具的脚本,并且它们运行良好,因此当时我没有任何令人信服的理由进行切换。然而,现在我面临着为新基础设施构建新脚本的任务,现在似乎是尝试它的好时机。

使用 AWS CLI

我将跳过如何安装和配置AWS CLI的详细信息,因为这已经在Amazon CLI的主页上得到了很好的文档记录,并且它可能已经为您的Linux发行版打包(如果不是,您可以执行pip install awscli来获取它)。虽然您可以将AWS CLI用于许多不同的AWS API,但我将坚持它与EC2 API工具的比较方式。与每个命令都以ec2-开头不同,每个命令都以aws ec2开头,后跟命令。幸运的是,大多数命令在两种环境中都匹配,因此在以前您可能输入


$ ec2-describe-instances

现在您输入


$ aws ec2 describe-instances

不幸的是,相似之处几乎到此为止。在使用ec2-describe-instances时,您可以直接附加ID列表,但在AWS CLI中,您需要首先使用--instance-ids参数


$ aws ec2 describe-instances --instance-ids i-someid

这两个工具之间的另一个区别是输出。您可以使用AWS CLI在表格、文本和JSON输出之间进行选择;但是,文本输出最终与EC2 API工具中的格式非常不同。这意味着,如果像我一样,您有工具可以解析该输出,则需要重新设计它们。

检查主机是否存在

例如,我编写了一个包装脚本来生成新的EC2主机,该脚本捕获了所有我可能根据主机名在命令行中传递的常用选项。但是,在我生成主机之前执行的一项检查是测试我是否已经有一个标记了该主机名的实例。所以像这样


ec2-describe-tags --region $REGION | cut -f5 | 
 ↪egrep -q "^$MYHOST$"

变成这样


aws ec2 describe-tags --region $REGION | grep Name | 
 ↪grep instance | cut -f5 | egrep -q "^$MYHOST$"
通过名称查找安全组 ID

当涉及到分配安全组时,我不得不对我的脚本进行另一个更改。使用EC2 Classic,您可以在生成主机时通过将多个-g选项传递给ec2-run-instances来按名称引用安全组。但是,一旦您使用VPC,您必须在生成主机时按其ID引用安全组。我所做的是将属于主机的安全组都分配给一个变量,如下所示


SEC_GROUPS='default foo'

然后我遍历该列表以提取ID


for g in ${SEC_GROUPS}; do
  SGID=$(aws ec2 describe-security-groups --filters 
   ↪"Name=group-name,Values=$g" |
grep ^SECURITYGROUPS | cut -f3)                                            
  SGIDS="$SGIDS $SGID"
done

然后我可以将--security-group-ids $SGIDS传递给我的aws ec2 run-instances命令。

通过名称查找子网 ID

我遇到的另一个区别是在处理VPC子网时。使用EC2 Classic,您根本不必担心子网,虽然您可以在VPC中使用名称标记子网,但当您生成主机时,它希望您指定ID。同样,我将子网标签放入一个变量中,并使用AWS CLI提取ID


SUBNETID=$(aws ec2 describe-subnets --filters 
 ↪"Name=tag:Name,Values=${SUBNET}" | grep ^SUBNETS | cut -f8)
拉取关于特定主机的数据

回到EC2 API工具,很容易获得关于特定主机的信息


$ ec2-describe-instances | grep myhostname

或简写形式


$ ec2din | grep myhostname

不幸的是,由于文本输出的格式,使用AWS CLI时事情并没有那么容易。相反,您应该使用--filters选项将搜索限制为仅限具有与您的主机名匹配的Name标签的实例


$ aws ec2 describe-instances --filters 
 ↪"Name=tag:Name,Values=myhostname"

我最终将之前的命令变成了一个名为ec2dingrep的快速脚本


#!/bin/bash

HOSTNAME=$1
aws ec2 describe-instances --filters 
 ↪"Name=tag:Name,Values=${HOSTNAME}"
~

总而言之,我只花了一天中的一部分时间来攀登使用AWS CLI与VPC交互的学习曲线,并重写了我用来生成服务器的脚本。虽然到目前为止,将命令串联在一起确实花了我更长的时间,但其中大部分是肌肉记忆,并且AWS CLI比EC2 API工具快得多的速度使其值得。

资源

Amazon CLI 文档: https://aws.amazon.com/cli

Kyle Rankin 是 Linux Journal 的技术编辑和专栏作家,以及 Purism 的首席安全官。他是 Linux Hardening in Hostile Networks, DevOps Troubleshooting, The Official Ubuntu Server Book, Knoppix Hacks, Knoppix Pocket Reference, Linux Multimedia HacksUbuntu Hacks 的作者,也是许多其他 O'Reilly 书籍的贡献者。Rankin 经常在安全和开源软件方面发表演讲,包括在 BsidesLV、O'Reilly Security Conference、OSCON、SCALE、CactusCon、Linux World Expo 和 Penguicon 上。您可以在 @kylerankin 上关注他。

加载 Disqus 评论