aws搭建包含服务器和网络的虚拟基础设施(2)

1.EC2使用

  • 1.1启动虚拟服务器:即启动一个EC2实例
  • 1.2使用SSH连接到虚拟服务器
  • 1.3手动安装和运行软件
  • 1.4监控和调试虚拟服务器
  • 1.5关闭虚拟服务器
  • 1.6更改虚拟服务器的容量
  • 1.7在另一个数据中心开启虚拟服务器
  • 1.8分配一个固定的公有IP
  • 1.9向虚拟服务器添加额外的网络接口
  • 1.10优化虚拟服务器的开销

2.编写基础架构:CLI,SDK,CloudFormation

  • 2.1基础架构即代码
  • 2.2AWS CLI
  • 2.3使用SDK,Cloud9,CDK编程
  • 2.4AWS CloudFormation

3.自动化部署:CloudFormation,ElasticBeanstalk,OpsWorks

4.保护系统安全:IAM,安全组,VPC

  • 4.1AWS安全负责说明
  • 4.2保持软件最新
  • 4.3保护AWS账号安全
  • 4.4控制进出虚拟服务器的网络流量
    - 使用安全组控制虚拟服务器的流量
    - 允许ICMP流量
    - 允许SSH流量
    - 允许来自源IP地址的SSH流量
    - 允许来自源安全组的SSH流量:使用堡垒主机
  • 4.5在云中创建一个私有网络:虚拟私有云VPC




1.EC2使用

概念理解:
aws搭建包含服务器和网络的虚拟基础设施(2)_第1张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第2张图片



启动虚拟服务器:即启动一个EC2实例

  • 打开AWS console
  • 确保在【美国东部(弗吉尼亚北部)】-----书中示例代码所在的S3云存储桶的位置
  • 点击EC2服务
  • 点击【启动实例】:执行虚拟服务器向导
    该向导将有如下步骤:
    1. 选择OS
      第一步是为虚拟服务器选择OS和预装软件,称为Amazon AMI(Amazon Machine Image,Amazon系统映像)
      虚拟服务器是基于AMI启动的。AMI由AWS,第三方供应商机社区提供。
      AWS Marketplace提供预装了第三方软件的AMI。
      概念解释:虚拟设备AMI,AKI,Xen,HVM
      注意:如果要启动新的虚拟服务器,一定要保证自己使用的是HVM映像
      aws搭建包含服务器和网络的虚拟基础设施(2)_第3张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第4张图片

    2. 选择虚拟服务器的规格
      选择虚拟服务器的计算能力,在AWS中,计算能力(cpu,mem)被归类到所需的实例类型中。
      一个实例类型主要描述了计算能力:cpu的个数即内存memeory的大小。
      概念解释:实例类型,实例家族,代,尺寸
      aws搭建包含服务器和网络的虚拟基础设施(2)_第5张图片
      aws搭建包含服务器和网络的虚拟基础设施(2)_第6张图片

    3. 配置详细信息
      aws搭建包含服务器和网络的虚拟基础设施(2)_第7张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第8张图片
      aws搭建包含服务器和网络的虚拟基础设施(2)_第9张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第10张图片

    4. 检查输出并为SSH选择一个密钥对
      用户需要一个密钥来登录自己的虚拟服务器。
      用户使用一个密钥而不是密码来完成身份认证,进而登录到自己的虚拟服务器。
      密钥比密码更加安全,而且在AWS上运行Linux服务器强制SSH访问使用密钥方式。
      (此处的密钥认证方式类似于Github中的密钥认证方式,将生成的公钥上传至服务器,而在本地利用私钥作为访问服务器的凭据)

      创建个人密钥的方式:
      1.打开aws管理控制台:点击【服务】----【EC2服务】
      2.点击左侧【密钥对】
      3.点击【创建密钥对】
      4.输入密钥对的名字,点击【创建】,使用浏览器下载创建好的密钥对。
      5.打开一个终端,切换到下载目录
      6.Linux和Mac:在终端中运行chmod 400 密钥文件名.pem来修改密钥文件的权限仅自己可见
      7.WIndows:WIndows没有自带SSH客户端,所以需要安装PuTTY。
      PuTTY带有一个工具叫做PuTTYgen,它可以将【密钥名.pem】文件转换成【密钥名.ppk】。
      打开PuTTYgen,在【Type of key to generate】选择【rsa】,点击【load】,选择刚刚浏览器下载好的密钥文件。
      因为PuTTYgen只显示【*.pkk】文件,需将文件类型切换至【所有】文件类型才可显示刚刚下载好密钥文件。
      最后作为【Save private key】。忽略未使用密码保护保存密钥的警告。
      现在.pem文件已经被转换成了PuTTY所需的.pkk格式。

      aws搭建包含服务器和网络的虚拟基础设施(2)_第11张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第12张图片
      虚拟服务器启动后,点击【查看实例】打开概览界面,等待虚拟服务器变为【running】状态。
      要完全控制自己的虚拟服务器,用户需要远程登录自己的虚拟服务器。



使用SSH连接到虚拟服务器:
用户可以远程在虚拟服务器上安装额外的软件以及运行命令。
要登录到虚拟服务器,用户要找到虚拟服务器的共有IP地址。

    • 点击【服务】----【EC2服务】
    • 点击【实例】跳转到正在运行的虚拟服务器。
    • 点击【连接】按钮,打开连接到服务器的说明。
    • 找到虚拟服务器的共有IP,有了共有IP地址及用户的密钥,用户就能登录到虚拟服务器了。
      aws搭建包含服务器和网络的虚拟基础设施(2)_第13张图片
  • Linux和Mac
    https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstances.html?icmpid=docs_ec2_console
    打开终端,输入ssh -i $PathToToken/mykey.pem ubuntu@$PublicIp
    使用密钥文件的路径替换$PathToKoken,使用在控制台显示的链接对话框中的公有IP替换$PublicIp
    在关于新主机的认证的安全警告处回答【yes】
  • Windows
    https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/putty.html?icmpid=docs_ec2_console
    找到创建好的【mykey.pkk】文件,然后双击打开它。
    在PuTTY Pageant会在任务条中显示为一个图标。如果未显示需重装PuTTY。
    在这里插入图片描述
    启动PuTTY。填写AWS管理控制台的连接对话框中显示的公有IP地址,然后点击【Open】
    aws搭建包含服务器和网络的虚拟基础设施(2)_第14张图片
    在关于新主机的认证的安全警告处回答【是】,然后输入【ubuntu】作为登录名,按【Enter】键。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第15张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第16张图片
  • 登录信息
    不论是使用Windows,Linux还是Mac,当登录成功后都会显示如下信息。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第17张图片现在已经连接到虚拟服务器,为在虚拟服务器中运行命令做好了准备。


手动安装和运行软件
现已经启动了一台ubuntu OS的虚拟服务器。
安装一个名为linkchecker的工具,它能够让我们找到网站上断裂的连接
sudo apt-get install linkchecker -y
aws搭建包含服务器和网络的虚拟基础设施(2)_第18张图片
现在就可以检查那些指向已经不存在的网站的连接了。
现选择一个网站,然后运行:
linkchecker https://...
aws搭建包含服务器和网络的虚拟基础设施(2)_第19张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第20张图片
根据网页数量的不同,网页爬虫需要一些时间来检查所有的网页是否有断裂的连接。
最终它会列出所有断裂的连接,给用户机会找到并修复他们。



监控和调试虚拟服务器日志监控指标
AWS提供了工具让用户来监控和调试自己的虚拟服务器。

  • 显示虚拟服务器的日志
    AWS允许用户使用管理控制台显示服务器的日志(日志可以显示虚拟服务器在启动时和启动后做了什么)。
    使用如下步骤打开虚拟服务器的日志:

    1.点击【EC2】----【实例】
    2.选择一个正在运行的虚拟服务器
    3.点击【操作】----【实例设置】----【获取系统日志】
    此时会打开一个窗口,然后显示从虚拟服务器得到的日志,这些日志通常在启动期间显示在一台物理监视器上。
    这是一个简单有效的访问用户的服务器的日志系统,并且它不需要SSH连接。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第21张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第22张图片

  • 监控虚拟服务器的负载
    按如下步骤打开虚拟服务器的指标:

1.【EC2】----【实例】
2.选择一台正在运行的虚拟服务器
3.点击右下角【监控】标签页
aws搭建包含服务器和网络的虚拟基础设施(2)_第23张图片




关闭虚拟服务器
为了避免产生费用,用户总是应该关闭不用的虚拟服务器。
用户可以使用以下5个操作来控制一台虚拟服务器的状态:【操作】----【实例状态】
aws搭建包含服务器和网络的虚拟基础设施(2)_第24张图片

  • 开启:可以打开一台停止的服务器。
  • 停止:停止一台正在运行的虚拟服务器。
    停止的服务器可以被再次启动。
    一台已经停止了的虚拟服务器将不会产生任何费用,除了网络附加存储这样的附加资源除外。
    如果用户使用了网络附加存储,用户的数据将会被保存。
  • 重启:用户不会在重启时丢失任何数据,而且所有的软件在重启后任会保持被安装了的状态。
  • 终止:删除该虚拟服务器。
    用户不能在此开启一台已经终止了的虚拟服务器。
    终止一台服务器意味着删除这台虚拟服务器及其依赖项(如:网络附加存储)和公有及私有IP地址。
    被终止了的服务器将不会在产生任何费用。
  • 休眠Hibernate

资源清理:
1.【EC2】—【实例】
2.点击正在运行的虚拟服务器
3.【操作】—【实例状态】----【终止】



更改虚拟服务器的容量
用户总是可以更改一台虚拟服务器的容量:云计算的优势之一,它给了用户垂直扩展的能力。
如何更改一台正在运行的虚拟服务器的容量:

1.首先启动一个EC2实例
2.使用SSH连接到EC2实例
Linux或Mac:使用ssh -i连接
Windows:使用PuTTY工具连接
3.执行:
cat /proc/cpuinfo
free -m
来获取服务器的CPU和内存信息
4.如果用户需要更多的cpu,memory,网络容量,或是修改虚拟服务器的实例家族于版本。
首先【停止】该服务器
在服务器停止后,可以更改实例:【操作】----【实例设置】
aws搭建包含服务器和网络的虚拟基础设施(2)_第25张图片
更改完成后,公有及私有IP地址也发生了变化。
需要获取新的公有IP地址,通过SSH重新连接到新的IP地址。
5.资源清理:终止该台虚拟服务器



在另一个数据中心开启虚拟服务器
AWS为全球提供数据中心。
要使互联网获得**
**,为主要用户选择一个最近的数据中心十分重要。
更改数据中心:
aws搭建包含服务器和网络的虚拟基础设施(2)_第26张图片
用户可以为AWS服务指定区域。
各个区域之间完全独立,数据不在区域间进行传输。
典型情况下,一个区域有两个或更多位于同一地区的数据中心组成。
这些数据中心间有着很好的连接,他们能提供高可用的基础架构。
一些AWS服务:如内容分发网络CDN(Content Delivery Network)服务,域名系统DNS(Domian Name System)服务,是在这些区域之外的数据中心之上全球运行的。

由于各个区域之间相互独立,故在切换区域后需要再次创建新的密钥对用以访问EC2.
用户使用密钥对的形式访问自己创建的虚拟服务器EC2资源,将创建好的密钥对的私钥保存在本地中,当SSH连接到EC2实例时,使用刚刚保存到本地私钥进行认证,进而访问EC2.



分配一个固定的公有IP
前面创建的EC2实例都自动分配了一个公有的IP地址。
但是每次启动或是停止一台虚拟服务器EC2时,公有IP地址就改变了。
如果想用一个固定的IP地址运行一个应用程序,则需使用AWS提供的弹性IP地址服务:Elastic IP address。

使用以下步骤来分配并关联一个公有IP地址到一台虚拟服务器上:

1.点击【EC2】
2.【网络于安全】----【弹性IP】
aws搭建包含服务器和网络的虚拟基础设施(2)_第27张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第28张图片
3.点击【分配新地址】分配公有IP地址

在拥有了固定的IP地址:即弹性IP地址后,可以将该弹性IP关联到一个EC2实例上:
1.选择刚刚创建好的弹性IP,【操作】-----【关联地址】
2.在【实例】中点击右侧三角,选择需要关联的EC2实例
3.点击右下角【关联】完成EC2实例固定IP地址的设定。
aws搭建包含服务器和网络的虚拟基础设施(2)_第29张图片

如果用户需要确保自己的应用的端点不变化,就需要手动创建一个 弹性IP,并将该弹性IP地址关联到EC2实例。
利用弹性IP地址,可以在用户无知觉的情况下换掉后端关联的EC2实例,且可以保持服务的不中断运行。

用户也可以使用多个网络接口来关联多个公有IP地址到一台虚拟服务器。
适用情况:用户需要在同一个端口运行不同的应用或者不同的网站使用一个唯一的固定的公有IP地址。

注意:IPv4地址是稀缺资源。为了防止弹性IP地址浪费,AWS将对没有关联到任何服务器的弹性IP地址收费。



向虚拟服务器添加额外的网络接口
除了公有IP地址,用户还可以控制自己的虚拟服务器的网络接口。
用户可以向一台虚拟服务器添加多个网络接口,并且控制关联到这些网络接口的私有IP地址和公有IP地址。
用户可以使用额外的网络接口管来关联第二个公有IP地址到自己虚拟服务器。
用以下步骤来为自己的虚拟服务器EC2实例,创建一个额外的网络接口:

1.点击EC2服务左侧的【网络接口】
2.点击【创建网络接口】
3.输入该网络接口的描述信息
4.选择自己EC2实例的子网作为新的网络接口的子网。
aws搭建包含服务器和网络的虚拟基础设施(2)_第30张图片
5.让【私有IP地址】保持默认的自动分配
6.安全组选择一个即可
7.点击创建
aws搭建包含服务器和网络的虚拟基础设施(2)_第31张图片

当新的网络接口的状态变为Available,用户可以将他附加到自己的虚拟服务器。
1.选择新创建的网络接口,点击【附加】
2.选择正在运行的虚拟服务器的ID,点击【附加】
aws搭建包含服务器和网络的虚拟基础设施(2)_第32张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第33张图片

现在已经附加了一个额外的网络接口到自己的虚拟服务器,接下来关联一个额外的公有IP地址到这个额外的网络接口。
1.点击左侧的【弹性IP】
点击【分配新地址】来分配一个新的固定的弹性IP地址。
【操作】----【关联地址】,将它连接到刚刚创建的网络接口
aws搭建包含服务器和网络的虚拟基础设施(2)_第34张图片

现在虚拟服务器就可以通过两个不同的IP地址来访问了。
这样用户可以根据公有IP地址提供两个不同的网站服务,需要配置网络服务器来根据公有IP地址来应答请求。
在次使用SSH连接到虚拟服务器,并且在终端输入ifconfig后,就能看到自己的新网络接口附加到了虚拟服务器上。

每个网络接口都能连接到一个私有IP地址和一个公有IP地址。
我们需要配置网络服务器来根据IP地址提供不同的网站。
虚拟服务器不知道任何有关于他的公有IP地址的信息,但是我么可以根据私有IP地址来区分请求。

清理资源:
1.终止虚拟服务器
2.转到【网络接口】,选择并删除网络接口
3.转至【弹性IP】—【操作】----【释放IP地址】,释放两个公有弹性IP地址



优化虚拟服务器的开销

省钱的两个选项:

  • 竞价型实例
  • 预留实例
    这两个选项都能够帮助用户减少开销,但是这样会降低灵活性。
    对于竞价型实例,可以对AWS数据中心中未使用的容量出价,价格基于供给与需求。
    如果需要使用一台服务器超过一年,可以使用预留型实例,同一支付给定时间段的费用并提前获取折扣。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第35张图片



2.编写基础架构:CLI,SDK,CloudFormation

AWS提供通过接口来控制的基础架构,叫做应用编程接口API(application programming interface)。
用户能通过API控制AWS的每一部分,用户可以使用大多数编程语言,CLI,和其它工具的SDK调用这些API。
在AWS上,一切都可以通过API来控制,用户通过HTTPS协议调用REST API来与AWS交互。

例如:要列出S3对象存储里的所有文件,可以向API端点发送一个GET请求:
GET / HTTP/1.1
Host: BucketName.s3.amazonaws.com
Authorization: […]

使用底层的HTTPS请求直接调用API不太方便,另一种简单的方法时:使用CLI或SDK来和AWS
交互。



基础架构即代码
【基础架构即代码】:表达了使用高级编程语言来控制IT系统的思想。
在软件开发中,自动化测试,代码库和构建服务器提高了软件工程的质量。
如果用户的基础架构可以当作代码来对待,用户就能过关对自己的基础架构代码和应用程序代码使用相同的技术。
最终用户可以使用自动化测试,代码库和构建服务来改善基础架构的质量。

注意:区别【基础架构即代码】和【基础架构即服务IaaS】:IaaS指的是按照使用量进行付费的租用服务器,存储和网络的业务模式

自动化和DevOps(Development Operations)是软件开发驱动的一个方法,以便让开发和运维更加紧密的结合在一起:即自己开发的软件自己进行后续的运维工作。

基础架构语言:JIML(JSON Infrastructure Markup Language)JSON基础架构标记语言
JSON转为AWS API调用的过程:

  • 解析JSON输入
  • JIML解释器将资源和他们的依赖项连接起来,创建一张依赖图
  • JIML解释器从底层叶子节点到顶层根遍历依赖图中的书,然后产生一个线性的命令流。这些命令由一个伪语言来表达。
  • 然后JIML运行时环境将这些伪语言的命令翻译成AWS API调用该

注意:JIML解释器确定了资源的创建顺序,JIML解释器把依赖图变成一个现行的使用伪语言的命令流。这个伪语言代表了用正确的舒徐创建所有资源所需要的步骤。最后JIML运行时环境将伪语言命令翻译成AWS API调用。
即:基础代码即架构的所需的一切:都与依赖项相关。



2.使用AWS CLI
CLI官方文档:https://aws.amazon.com/cn/cli/
aws搭建包含服务器和网络的虚拟基础设施(2)_第36张图片
使用CLI创建基础架构:CLI是实现基础架构即代码的一种工具。
AWS CLI是一个从命令行使用AWS的便捷方法。它运行在linux,mac,Windows上,用python编写。
AWS CLI为所有的AWS服务提供了一个统一的访问接口。

安装AWS CLI

  • 1.Linux和Mac:
    CLI需要Python及pip。pip是安装python程序包的推荐工具。
python -version		//检查python版本
pip --version			//检查pip版本
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"		//若未安装pip,则执行该命令安装pip
sudo python get-pip.py
pip --version			//验证pip的安装
sudo pip install awscli		//安装AWS CLI
aws --version
  • 2.Windows
    在这里插入图片描述
    64位的安装程序网址:https://s3.amazonaws.com/aws-cli/AWSCLI64.msi
    下载AWS CLI(64位或32位)MSI安装程序
    运行下载好的安装程序,按照向导的提示安装CLI
    用管理员身份运行PowerShell,执行Set-ExecutionPolicy Unrestricted,按Enter键执行这一命令。这样就能执行示例中的未签名的PowerShell副本。
    关闭PowerShell窗口,不在需要以管理员身份工作了。
    通过【开始】菜单中的PowerShell项运行。
    在PowerShell中执行aws --version以验证AWS CLI是否正常工作。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第37张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第38张图片

配置AWS CLI
要使用AWS CLI需要验证用户的身份。目前为止,使用的是AWS根账号。根账号能做任何事情。
建议不用使用根账号,所以需要创建一个新用户:

  • 打开AWS console,点击【服务】----【IAM服务】----选择左边的【用户】
  • IAM(Identity and Access Management)文档:https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_users.html?icmpid=docs_iam_console
  • 点击【添加用户】
  • 输入用户名mycli,其他项保持空白,选择【编程访问】,点击下一步【权限】按钮
  • 直接点击下一步【审核】,然后点击【创建用户】按钮
  • 跳过其余步骤,点击【显示】来显示私有访问密钥:它只会显示一次!现在用户需要复制这一凭证到CLI配置中。
  • 在用户的计算机中打开一个终端(win上的powershell或linux上的bash shell),然后运行aws configure,用户会被问及4个信息:
    • AWS访问密钥ID:从访问密钥ID框(浏览器窗口)中复制这一值
    • AWS私有访问密钥:从私有访问密钥框(浏览器窗口)中复制这一值
    • 默认区域名称:输入us-east-1
    • 默认输出格式:输入json
  • 现在已经配置好了CLI,使用用户mycli进行身份认证。
  • 切换回浏览器窗口然后点击【关闭】结束用户创建向导
  • 接下来处理授权来确定允许用户mycli做些什么:目前这个用户不允许做任何事情(默认设定)
  • 点击用户mycli,在【权限】部分,点击【添加权限】—【直接附加现有策略】
  • 搜索【Admin】,选择策略【AdministratorAccess】,点击下一步【审核】,然后点击【添加权限】
  • 测试CLI是否工作:切换到终端窗口,输入aws ec2 describe-regions来获取所有可用区域的列表。
  • 测试成功后就可以开始使用CLI了。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第39张图片
    使用CLI
    使用文档:https://aws.amazon.com/cn/cli/#
    AWS CLI的使用形式:
    aws [--key value ...]
    aws help:显示所有可用的服务
    aws help:显示某一服务所有可用的操作
    aws help:显示特定服务操作所有可用的选项
    CLI的另一个重要功能:--query选项使用JMESPath(一种JSON的查询语言)从结果中提取数据,这个选项用于提取结果中的特定项。

    JSON中JMESPath的操作:
    aws ec2 describe-images:列出了可用的AMI。
    要启动一个EC2实例,需要ImageId,使用JMESPath可以提取到这一信息:
    最好不要运行上述命令,上述命令的输出时间较长,且输出十分多,可按【Ctrl+C】终止命令的输出
    运行aws ec2 describe-regions:显示所有的可用区
    aws搭建包含服务器和网络的虚拟基础设施(2)_第40张图片
    要提取第一个Endpoint,
    路径为Regions[0].Endpoint,
    查询语句为:aws ec2 describe-regions --query Regions[0].Endpoint
    查询结果为:ec2.eu-north-1.amazonaws.com
    在这里插入图片描述
    要提取所有的RegionName,
    路径为Regions[*].RegionName,
    查询语句为:aws ec2 describr-regions --query Regions[*].RegionName
    查询结果为:
    aws搭建包含服务器和网络的虚拟基础设施(2)_第41张图片



使用SDK,Cloud9,CDK编程:https://docs.aws.amazon.com/index.htmlaws搭建包含服务器和网络的虚拟基础设施(2)_第42张图片
AWS为许多编程语言提供软件开发套件(Software Development kits,SDK)

用于在 AWS 上进行构建的工具:用于在 AWS 上开发和管理应用程序的工具
https://aws.amazon.com/cn/tools/?id=docs_gateway

AWS Cloud9: 用于编写、运行和调试代码的云 IDE
概览: https://aws.amazon.com/cn/cloud9/
功能: https://aws.amazon.com/cn/cloud9/details/
定价: https://aws.amazon.com/cn/cloud9/pricing/
使用方法: https://aws.amazon.com/cn/cloud9/getting-started/
使用入口:https://us-east-1.console.aws.amazon.com/cloud9/home/product
FAQ(Frequent Ask Question): https://aws.amazon.com/cn/cloud9/faqs/
AWS Cloud9 是一种基于云的集成开发环境 (IDE),您只需要一个浏览器,即可编写、运行和调试代码。它包括一个代码编辑器、调试程序和终端。Cloud9 预封装了适用于 JavaScript、Python、PHP 等常见编程语言的基本工具,您无需安装文件或配置开发计算机,即可开始新的项目。Cloud9 IDE 基于云,因此您可以从办公室、家中或任何地方使用已连接互联网的计算机完成项目。Cloud9 还可以为开发无服务器应用程序提供无缝体验,使您能够轻松定义资源、进行调试,并在本地和远程执行无服务器应用程序之间来回切换。借助 Cloud9,您可以与团队快速共享开发环境,从而能够将程序配对,并实时跟踪彼此的输入。

AWS CDK:https://docs.aws.amazon.com/zh_cn/cdk/?id=docs_gateway
The AWS Cloud Development Kit (AWS CDK) is a software development framework for defining your cloud infrastructure in code and provisioning it through AWS CloudFormation.



AWS CloudFormation
CloudFormation文档:https://docs.aws.amazon.com/zh_cn/cloudformation/?id=docs_gateway
CloudFormation是一个比JIESML(JSON Infrastructure Expression Markup Langue)更好的,用于描述:基础架构即代码的工具。
CloudFormation基于模板来创建基础架构。
CloudFormation是AWS上管理基础架构最强的工具之一。

注意:使用蓝图(blueprint)这一术语来描述基础架构自动化。管理配置服务AWS CloudFormation使用的蓝图被称为模板。

模板使用JSON描述了用户的基础架构,CloudFormation能对其进行解析。
用户只需要使用声明的表述语言,而不是给出实现他的所有操作。
描述的方法意味着用户告诉CloudFormation需要什么样的基础架构以及组件之间时怎样相互连接的。
用户不需要告诉CloudFormation需要哪些操作来创建那样的基础架构,不需要定义操作被执行的顺序。

CloudFormation的概念:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第43张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第44张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第45张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第46张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第47张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第48张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第49张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第50张图片
ColudFormation的好处:

  • 他让用户在AWS平台上用统一的方式来描述基础架构:如果用户用脚本来创建自己的基础架构,每个人都会用不同的方式解决同样的问题,这对新开发人员与运维人员而言是个障碍,他们需要理解不同人的脚本代码。CloudFormation模板是一个定义基础架构的清晰的语言。
  • 能处理依赖关系:永远不要尝试使用脚本来创建一个复杂的基础架构,组件之间的关系会变得一团糟(例如:把网络服务器注册到一个还不可用的LB)
  • 可复制:使用CloudFormatiion用户能创建两个完全一样的基础架构并保持他们同步(例如可以使用户的生产环境和测试环境保持一致)
  • 可自定义:用户可以向CloudFormation插入自定义的参数来按期望自定义模板
  • 可测试:从模板创建的基础架构是可测试的,随时可以按需启动一个新的基础架构,运行测试,完成后在关掉它。
  • 可更新:ColudFormation能更新用户的基础架构。它将找出模板最终改变了的部分,然后将这些变化尽可能平滑的应用到现有的基础架构。
  • 最小化认为的误操作
  • 把基础架构文档化:AWS CloudFormation 模板是 JSON 或 YAML 格式的文本文件。您可以使用任何扩展名(如 .json、.yaml、.template 或 .txt)保存这些文件。AWS CloudFormation 将这些模板作为蓝图以构建 AWS 资源。用户可以把它当成代码,然后使用一个版本控制系统如Git来跟踪变更。
  • 免费:CloudFormation本身不会产生额外的费用

AWS CloudFormation 模板格式:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/template-formats.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第51张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第52张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第53张图片
yaml:http://www.yaml.org
json : http://www.json.org

AWS CloudFormation模板解析:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/template-anatomy.html
在这里插入图片描述aws搭建包含服务器和网络的虚拟基础设施(2)_第54张图片在这里插入图片描述在这里插入图片描述aws搭建包含服务器和网络的虚拟基础设施(2)_第55张图片

CloudFormation模板的组成部分:
模板包含几个主要部分。Resources 部分是唯一的必需部分。模板中的某些部分可以任何顺序显示。但是,在您构建模板时,使用以下列表中显示的逻辑顺序可能会很有用,因为一个部分中的值可能会引用上一个部分中的值。
1.AWSTemplateFormationVersion(可选):格式版本
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/format-version-structure.htmlaws搭建包含服务器和网络的虚拟基础设施(2)_第56张图片
2.Description(可选):这个模板是关于什么的
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/template-description-structure.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第57张图片
3.元数据(可选):提供模板的详细信息
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第58张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第59张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第60张图片
4.参数(可选):参数使用值来自定义模板。例如:域名,客户ID,DB密码
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
参数至少有一个名字和类型。建议用户同时添加一个描述
使用可选的 Parameters 部分来自定义模板。利用参数,您能够在每次创建或更新堆栈时将自定义值输入模板。

{
[...]
"Parameters": {
  "NameOfParameter": {		#参数名
     "Type": "",
     "Description": ""
     [...]
     }
  },
[...]
}

aws搭建包含服务器和网络的虚拟基础设施(2)_第61张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第62张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第63张图片
5.映像Mappings(可选):可选的 Mappings 部分将密钥与对应的一组命名值相匹配。
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第64张图片
6.条件Conditions(可选):可选的 Conditions 部分包含一些声明,以定义在哪些情况下创建或配置实体
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第65张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第66张图片
7.转换Transforma(可选):可选的 Transform 部分指定 AWS CloudFormation 用于处理您的模板的一个或多个宏。Transform 部分基于 AWS CloudFormation 的简单的声明性语言构建,并带有一个强大的宏系统。
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/transform-section-structure.html
8.资源Resources(必需):必需的 Resources 部分声明您要包含在堆栈中的 AWS 资源,例如 Amazon EC2 实例或 Amazon S3 存储桶。
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/resources-section-structure.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第67张图片
9.输出Outputs(可选):可选的 Outputs 部分声明输出值,您可以将这些值导入到其他堆栈中(以便创建跨堆栈引用)、在响应中返回这些值(以便描述堆栈调用)或者在 AWS CloudFormation 控制台中查看。例如,您可以输出堆栈的 S3 存储桶名称以使该存储桶更容易找到。
https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第68张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第69张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第70张图片

如果从模板创建一个 基础架构,则CloudFormation称为堆栈。模板只存在一次,而许多堆栈可以从同一个模板中被创建。

CloudFormation创建步骤:

  • 点击【CloudFormation】服务----【创建堆栈】
  • 步骤1:指定模板
    Amazon S3 URL:输入https://s3.amazonaws.com/awsinaction/chapter4/server.json
    aws搭建包含服务器和网络的虚拟基础设施(2)_第71张图片
    aws搭建包含服务器和网络的虚拟基础设施(2)_第72张图片
JSON格式的模板
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "AWS in Action: chapter 4",
    "Parameters": {
        "KeyName": {
            "Description": "Key Pair name",
            "Type": "AWS::EC2::KeyPair::KeyName",
            "Default": "mykey"
        },
        "VPC": {
            "Description": "Just select the one and only default VPC",
            "Type": "AWS::EC2::VPC::Id"
        },
        "Subnet": {
            "Description": "Just select one of the available subnets",
            "Type": "AWS::EC2::Subnet::Id"
        },
        "InstanceType": {
            "Description": "Select one of the possible instance types",
            "Type": "String",
            "Default": "t2.micro",
            "AllowedValues": [
                "t2.micro",
                "t2.small",
                "t2.medium"
            ]
        }
    },
    "Mappings": {
        "EC2RegionMap": {
            "ap-northeast-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-cbf90ecb"
            },
            "ap-southeast-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-68d8e93a"
            },
            "ap-southeast-2": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-fd9cecc7"
            },
            "eu-central-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-a8221fb5"
            },
            "eu-west-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-a10897d6"
            },
            "sa-east-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-b52890a8"
            },
            "us-east-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-1ecae776"
            },
            "us-west-1": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-d114f295"
            },
            "us-west-2": {
                "AmazonLinuxAMIHVMEBSBacked64bit": "ami-e7527ed7"
            }
        }
    },
    "Resources": {
        "SecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "My security group",
                "VpcId": {
                    "Ref": "VPC"
                },
                "SecurityGroupIngress": [
                    {
                        "CidrIp": "0.0.0.0/0",
                        "FromPort": 22,
                        "IpProtocol": "tcp",
                        "ToPort": 22
                    }
                ]
            }
        },
        "Server": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "EC2RegionMap",
                        {
                            "Ref": "AWS::Region"
                        },
                        "AmazonLinuxAMIHVMEBSBacked64bit"
                    ]
                },
                "InstanceType": {
                    "Ref": "InstanceType"
                },
                "KeyName": {
                    "Ref": "KeyName"
                },
                "SecurityGroupIds": [
                    {
                        "Ref": "SecurityGroup"
                    }
                ],
                "SubnetId": {
                    "Ref": "Subnet"
                }
            }
        }
    },
    "Outputs": {
        "PublicName": {
            "Value": {
                "Fn::GetAtt": [
                    "Server",
                    "PublicDnsName"
                ]
            },
            "Description": "Public name (connect via SSH as user ec2-user)"
        }
    }
}
YAML格式的模板
AWSTemplateFormatVersion: 2010-09-09
Description: 'AWS in Action: chapter 4'
Parameters:
  KeyName:
    Description: Key Pair name
    Type: 'AWS::EC2::KeyPair::KeyName'
    Default: mykey
  VPC:
    Description: Just select the one and only default VPC
    Type: 'AWS::EC2::VPC::Id'
  Subnet:
    Description: Just select one of the available subnets
    Type: 'AWS::EC2::Subnet::Id'
  InstanceType:
    Description: Select one of the possible instance types
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t2.small
      - t2.medium
Mappings:
  EC2RegionMap:
    ap-northeast-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-cbf90ecb
    ap-southeast-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-68d8e93a
    ap-southeast-2:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-fd9cecc7
    eu-central-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-a8221fb5
    eu-west-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-a10897d6
    sa-east-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-b52890a8
    us-east-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-1ecae776
    us-west-1:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-d114f295
    us-west-2:
      AmazonLinuxAMIHVMEBSBacked64bit: ami-e7527ed7
Resources:
  SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: My security group
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          FromPort: 22
          IpProtocol: tcp
          ToPort: 22
  Server:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !FindInMap 
        - EC2RegionMap
        - !Ref 'AWS::Region'
        - AmazonLinuxAMIHVMEBSBacked64bit
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      SecurityGroupIds:
        - !Ref SecurityGroup
      SubnetId: !Ref Subnet
Outputs:
  PublicName:
    Value: !GetAtt 
      - Server
      - PublicDnsName
    Description: Public name (connect via SSH as user ec2-user)

  • 步骤2:指定堆栈详细信息
    aws搭建包含服务器和网络的虚拟基础设施(2)_第73张图片
  • 步骤3:配置堆栈选项
    可以为堆栈定义标签。所有由堆栈创建的资源都会被自动打上这些标签。
  • 步骤4:审核
    显示这个堆栈的总结。最后点击右下角的【创建堆栈】

更新CloudFormation:

  • 选择需要更新的堆栈:【操作】-----【更新堆栈】

删除堆栈:

  • 选择需要删除的堆栈:【操作】-----【删除堆栈】

CloudFormation的替代方案
如果用户不想写JSON文本来为自己的基础架构创建模板,有几个替代CloudFormation的方案:

  • Troposphere:一个用python写的库,可以帮助用户创建CloudFormation模板,而不需要写JSON,它在CloudFormation上另外加一个抽象层来实现这一点。
  • Terraform和Ansible:这些工具能让用户使用基础架构即代码,而不需要CloudFormation。



3.自动化部署:CloudFormation,ElasticBeanstalk,OpsWorks

部署: 不论想用自主开发的,开源项目的,还是商业厂商的软件,都需要安装,更新和配置应用程序及其依赖的组件,这一过程称为部署。

AWS上用于部署的工具:
AWS提供不同的工具帮助用户将应用部署到虚拟服务器上。
在虚拟服务器启动时插入bash或powershell脚本,可以让用户有区别的初始化服务器,如:安装不同的软件或配置服务。

  • CloudFormation:在用户部署自己负责的应用时给其最多的控制能力
  • ElasticBeanstalk:适合部署普通网站应用
  • OpsWorks:在Chef的帮助下部署多层应用架构



4.保护系统安全:IAM,安全组,VPC

在AWS上保护用户系统安全的几个重要方面:

  • 安装软件更新
    每天都有新的软件安全漏洞被发现。软件制造商发布更新来修补这些漏洞,用户的任务就是在这些更新发布后及时安装它们,否则用户的系统很容易成为黑客攻击的受害者。
  • 限制访问AWS账户
    最小权限原则。
  • 控制进出用户的EC2实例的网络传输
    采用白名单原则。
    用户只想要那些必需的端口能够被访问到,例如运行一个网络服务器,对外部世界只打开HTTP的80端口,为HTTPS流量打开443端口,关闭所有的其它端口。
  • 在AWS内创建一个私有网络
    用户可以创建从互联网不可达的子网:即只有自己可以访问该子网,而别人却不可以。
  • 保护用户自己开发的应用的安全
    检查使用者的输入并只允许必需的字符,不要使用明文存储密码,使用SSL来加密自己的服务器与使用者之间的数据传输等


AWS安全负责说明
AWS是一个责任共担的环境:安全责任由AWS和用户共同承担。
AWS承担的责任:

  • 通过自动监控系统和健壮的互联网访问来保护网络避免DDoS(Distributed Denial of Service)攻击。
  • 对能访问敏感区域的雇员进行背景调查
  • 存储设备退役时会在它们的生命周期结束后通过物理方式进行破坏
  • 确保数据中心的物理和环境安全
    用户承担的责任:
  • 加密网络数据传输来防止攻击者读取或操纵数据(如HTTPS)
  • 使用安全组和ACL来为自己的虚拟私有网络配置防火墙,以控制流量流入和流出的数据
  • 管理虚拟服务器上的OS及其它软件的补丁
  • 使用IAM实现访问还礼来尽可能的限制对如S3或EC2这样的AWS资源的访问


保持软件最新
如果一个安全更新发布了,用户必须快速安装它,因为如何利用这一漏洞可能与更新一同发布了,或者说每个人都能通过查看源代码来重建漏洞。

如果用户SSH登录到一台EC2实例,可能会看到显示相关更新的说明,AWS不会替用户在其EC2实例上应用在这些补丁,更新补丁是用户的责任。
用户可以使用包管理工具更新补丁:
Debian系的OS(如ubuntu,kali,debian):apt get update
RHEL系的OS(如RHEL,fedora,centos):yum --security check-update来查看哪些程序包需要安全更新

处理安全更新的两种情况:

  • 当服务器第一次启动时
    如果用户使用CloudFormation模板来创建自己的EC2实例,用户有三种选项在启动时安装安全更新:
    - 在服务器启动时安装所有更新:在自己的用户数据脚本中加入:yum -y update
    安装所有更新的问题在于用户的系统变得难以预料,例如,如果用户的服务器是上一周启动的,所有应用的更新是是上一周发布的,然而当新的更新发布时,用户启动服务器并安装所欲的更新,南无用户将得到一台与上一周完全不同的服务器,不同意味着因为某些原因它可能不在工作。
    这就是为什么用户需要明确定义自己想安装的安全更新的版本的原因。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第74张图片
    - 在服务器启动时仅安装安全更新:在自己的用户数据脚本中加入:yum -y --security update
    aws搭建包含服务器和网络的虚拟基础设施(2)_第75张图片
    - 明确指定程序包版本:安装指定版本号的更新
    yum update-to使用明确的版本来更新程序,而不是使用最新的
    aws搭建包含服务器和网络的虚拟基础设施(2)_第76张图片
  • 新的安全更新发布时用户的服务器正在运行
    用户可以手动使用SSH登录到自己的服务器,然后运行yum -y --security updateyum update-to [...],若用户有许多服务器,则可以使用一个脚本来获取所有的服务器列表,然后在所有的服务器上运行yum来使这个任务自动化。
			在所有正在运行的EC2实例上安装安全更新

			//获得所欲正在运行的EC2实例的公共DNS名
			PUBLICNAMES=$(aws ec2 describe-instances \
			--filters "Name=instance-state-name,Values=running" \
			--query "Reservations[].Instances[].PublicDnsName" \
			--output text)

			for PUBLICNAME in $PUBLICNAMES; do
				//通过SSH连接
				ssh -t -o StrictHostKeyChecking=no ec2-user@$PUBLICNAME \
				"sudo yum -y --security update"
			done


保护AWS账号安全
每个AWS账号默认有一个root用户,root用户具有最高权限。
可以有多个普通用户,新创建的普通用户默认没有任何权限,需要根据用户的职责进行授权,遵照最小权限原则。

若攻击者想要访问你的AWS账户,攻击者必须能使用你的账户认证,由三种方法:

  • 使用root用户:攻击者需要密码或访问密钥
  • 使用一个普通用户:攻击者需要密码或访问密钥
  • 被认证为一个AWS资源:攻击记者需要从那个EC2实例发送API/CLI请求

使用MFA(Multi-Factor Authentication,多重身份认证)来保护root用户,然后停止root用户的使用,创建一个新用户用于日常操作,并授予一个角色最小权限。

保护AWS账户的root用户安全
为root用户开启多重身份验证MFA,在MFA被激活后,你需要一个密码和一个临时令牌来作为root用户登录。这样攻击者不仅需要你的密码还需要你的MFA设备。
启用MFA步骤:

  • 在管理控制台点击你的名字
  • 点击【安全凭证】
  • 第一次会弹出一个弹出框,选择【继续安全凭证】
  • 在智能手机上安装一个MFA应用(如Google Authenticator)
  • 展开MFA
  • 点击激活MFA
  • 跟随向导中的指令,使用智能手机上的MFA应用扫描所显示的QR码
    aws搭建包含服务器和网络的虚拟基础设施(2)_第77张图片
    如果使用自己的智能手机作为一个MFA设备:不用自己的智能手机登录AWS console或者在手机上存储root的用户和密码,确保MFA令牌与自己的密码分离。

IAM(Indentity and Access Management)服务
IAM文档:https://docs.aws.amazon.com/zh_cn/iam/?id=docs_gateway

IAM服务通过AWS API提供身份认证与授权所需的一切。
你通过AWS API发送的每个请求都会通过IAM来检查这个请求是否允许。

IAM控制在你的AWS账户里,谁(身份认证)能做什么(授权)。
使用IAM身份认证是通过用户和角色完成的,授权是通过策略完成的。
角色认证一个EC2实例,而用户可以用于其它一切。

注意:IAM用户和IAM角色使用策略进行授权,用户和角色不能做任何事情直到你在策略中允许特定的操作。

root用户(人) IAM用户(其它一切) IAM角色(EC2实例)
可以有一个密码 总是
可以有一个访问密码 是(不推荐)
可以属于一个组
可以与一个EC2实例相关联

用于授权的策略
每个策略在JSON中定义且包含一个或多个声明。一个声明可以允许或拒绝在特定资源上做特定的操作。通配符*可以用来创建通用的声明。
策略和权限:https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/access_policies.html
Amazon 资源名称 (ARN) 和 AWS 服务命名空间:https://docs.aws.amazon.com/zh_cn/general/latest/gr/aws-arns-and-namespaces.html

AWS的策略类型:一共有6种。
aws搭建包含服务器和网络的虚拟基础设施(2)_第78张图片
最常用的是第一个:基于身份的策略。
aws搭建包含服务器和网络的虚拟基础设施(2)_第79张图片
托管策略与内联策略:https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/access_policies_managed-vs-inline.html

策略三要素:对什么资源(Resource),采取什么动作(Action),产生什么效果(Effect)
下面的策略声明允许对EC2服务中所有资源进行任意操作:

{
  "Version": "2012-10-17"		//指定2012-10-17来锁定版本
  "Statement": [{
    "Sid": "1",
    "Effect": "Allow",		//允许Allow或拒绝Deny
    "Action": ["ec2:*"],		//所有EC2操作(通配符*)
    "Resource": ["*"]
    }]
}

如果在同一个操作上有多个声明,拒绝将覆盖允许。
下面的策略允许除了终止实例以外的所有EC2操作:

{
  "Version": "2012-10-17"		//指定2012-10-17来锁定版本
  "Statement": [{
    "Sid": "1",
    "Effect": "Allow",		//允许Allow或拒绝Deny
    "Action": ["ec2:*"],		//所有EC2操作(通配符*)
    "Resource": ["*"]
    },{
     "Sid": "2",
     "Effect": "Deny",			//拒绝
     "Action": "["ec2:TerminateInstances"],		//终止EC2实例
     "Resurce": ["*"]
    }]
}

下面的策略拒绝所有的EC2操作。声明ec2:TerminateInstances不是关键性的,因为Deny覆盖Allow。当你拒绝一个操作时,是无法通过在另一个声明中允许它的。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "1",
    "Effect": "Deny",
    "Action": "["ec2:*"],
    "Resource": ["*"]
    },{
    "Sid": "2",
    "Effect": "Allow",
    "Action": "["ec2:terminateInstances"],
    "Resource": ["*"]
    }]
 }

Resource部分使用通配符["*"]来表示所有资源,在AWS中,资源通过ARN(Amazon Resource Name)来标识。
Amazon 资源名称 (ARN) 和 AWS 服务命名空间:https://docs.aws.amazon.com/zh_cn/general/latest/gr/aws-arns-and-namespaces.html

aws搭建包含服务器和网络的虚拟基础设施(2)_第80张图片aws搭建包含服务器和网络的虚拟基础设施(2)_第81张图片要找出账户ID,可以使用CLI:
Linux或Mac:打开一个Terminal
Windows:打开一个PowerShell
运行:aws iam get-user --query "User.Arn" --output text
在这里插入图片描述

用于身份认证的用户和用于组织用户认证的组
一个用户可以被密码或访问密钥所认证:

  • 当用户登录到管理控制台,用户是通过密码认证的
  • 如果使用CLI,则可以使用一个访问密钥来认证登录的用户。
    当用户第一次使用CLI登录时,输入的访问账户ID即密钥信息,会在当前用户的主目录下生成一个.aws的隐藏文件,点击查看该文件,发现该文件中保存了你刚刚配置的账户ID即访问密钥,存放在credentials文件中,这样第二次即以后登录就直接使用该文件中保存的信息,而不用手动再次输入账户ID及登录密钥了,此后也可以手动修改该文件。
    aws搭建包含服务器和网络的虚拟基础设施(2)_第82张图片
    使用CLI很容易创建用户和组:例如,创建一个管理员组用于集中管理员的权限
    使用一个安全的密码替换$Password。
$aws iam create-group --group-name "admin" 
$aws iam attach-group-policy --group-name "admin" --policy-arn "arn:aws:iam::asw:policy/AdministratorAccess"
$aws iam create-user --user-name "myuser"
$aws iam add-user-to-group --group-name "admin" --user-name "myuser"
$aws iam create-login-profile --user-nsme "myuser" --password "$Password"

用户myuser已经准备好开始使用了,但是,如果不是使用root用户的话,则必须使用一个不同的URL来访问管理控制台,即:https://$accountId.sigin.aws.amazon.com/console
直接登录aws管理控制台:https://console.aws.amazon.com,使用的是root账户,需要root账户的密码。

为IAM(Identity and Access Control)用户启用MFA(Multi-Factor Authentication)
建议为所有用户启用MFA。
最好不要为自己的root用户和日常用户使用同样的MFA设备。
用户可以从AWS合作伙伴,如Gemalto那里以13美元购买硬件MFA设备。
按以下步骤为自己的IAM用户开启MFA:
1.在管理控制台打开【IAM服务】
2.在左侧选择用户
3.选择一个用户
4.在页面底部的【Sign-In Credientials】部分点击【Manage MFA Device】按钮

现在起停止使用root用户,总是使用新创建的用户myuser即管理控制台的新链接。
https://$accountId.sigin.aws.amazon.com/console
用户永远不应该把一个用户访问密钥复制到一个EC2实例上,要使用IAM角色,不要在自己的源代码中存储安全凭证,并且永远不要把它们提交到自己的Git或SVN资源库中,而是尽可能的使用IAM角色。

用于认证AWS的角色
IAM用户(root,普通)用于认证:人
IAM角色用于认证:AWS资源
如果AWS资源附加了一个或多个角色,IAM会检查这些角色附加的所有策略(权限)来确定请求是否被允许。
默认情况下一个新创建的AWS资源没有任何权限,所以就不被允许调用任何AWS API。

IAM 角色:https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_roles.html?icmpid=docs_iam_console
AWS IAM 常见问题:https://aws.amazon.com/cn/iam/faqs/
IAM JSON 策略元素参考:https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/reference_policies_elements.html
aws搭建包含服务器和网络的虚拟基础设施(2)_第83张图片例如:创建一个过一会自己终止EC2实例:这个EC2实例需要停止自己的授权,可以使用内联策略进行授权。
以下示例为:如何在CloudFormation中把角色定义成一个资源:
实例代码资源:https://s3.amazonaws.com/awsinaction/chapter6/server.json

"Role": {
  "Type": "AWS::IAM::Role",
  "Properties": {
    "AssumeRolePolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Principal": {
          "service": ["ec2.amazonaws.com"]
        },
        "Action": ["sts:AssumeRole"]
      }]
    },
    "Path": "/",
    "Policies": [{
      "PolicyName": "ec2",
      "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [{
          "Sid": "Stmt1425388787800",
          "Effect": "Allow",
          "Action": ["ec2:StopInstances"],
          "Resource": ["*"],
          "Condition": {
            "StringEquals": {"ec2:resourceTag/aws:cloudformation:stack-id":{"Ref": "AWS::StackId"}}
          }
        }]
      }
    }]
  }
}

要附加一个角色给实例,必须首先创建一个实例配置文件:

"InstanceProfile": {
  "Type": "AWS::IAM::InstanceProfile",
  "Properties": {
    "Path": "/",
    "Roles": "[{"Ref": "Role"}]
  }
}

现在可以把角色(策略,一组权限的定义)和EC2实例(资源)关联起来(即授权):

"Server": {
  "Type": "AWS::EC2::Instance",
  "Properties": {
    "IamInstanceProfile": {"Ref": "InstanceProfile"},
    [...],
    "UserData": {"Fn::BAse64": {"Fn::Join": ["",[
      "#!/bin/bash -ex\n",
      "INSTANCEID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`\n",
      "echo \"aws --region us-east-1 ec2 stop-instances --instance-ids $INSTANCEID\" | at now + 5 minutes\n"
    ]]}}
  }
}


控制进出虚拟服务器的网络流量

用户只希望必要的网络流量进出自己的EC2实例。
使用防火墙,用户可以控制进入(ingress|inbound)和出去(egress|outbound)的数据流量。
如果用户运行一台网站服务器,则对外打开的端口只有HTTP流量使用的80端口和HTTPS流量使用的443端口,所有其它的端口都应该被关闭,只打开必要的端口,就关闭了许多可能的安全漏洞。

在网络流量进入或离开用户的EC2实例之前,它将穿过AWS提供的防火墙,这个防火墙审查网络流量并使用规则来确定流量是被允许还是被拒绝。

AWS对防火墙负责,你对防火墙规则负责。
默认情况下:所有入站流量都被拒绝,而所有出站流量都被允许。
你可以添加入站流量规则:将默认的拒绝所有转换为你添加的入站流量规则。



使用安全组控制虚拟服务器的流量
一个安全组可以被关联到AWS资源。
一个安全组遵循一组规则,一个规则可以基于以下内容允许网络流量:

  • 方向:入站或出站
  • IP协议(TCP,UDP,ICMP)
  • 源IP地址/目的IP地址
  • 端口
  • 源安全组/目的安全组(仅在AWS上有效)

在CloudFormation里一个安全组资源类型是AWS::EC2::SecurityGroup



允许ICMP流量
如果用户要从自己的计算机ping一台EC2实例,就必须允许来自因特网的控制报文协议ICMP(Internet Control Message Protocol)
默认情况下,所有的入站流量都被拒绝,尝试ping $PublicName来确认ping访问不被允许。

用户需要在安全组中添加一条规则来允许入站流量,其中协议是ICMP。
示例代码:https://s3.amazonaws.com/awsinaction/chapter6/firewall1.json

允许ICMP的安全组
{
  [...]
  "Resources": {
    "SecurityGroup": {
      [..]
    },
    "AllowInboundICMP": {			//允许ICMP的描述规则
      "Type": "AWS::EC2::SecurityGroupIngress",		//入站规则类型
      "Properties": {
        "GroupId": {"Ref": "SecurityGroup"},		//将规则与安全组联系起来
        "IpProtocol": "icmp",			//指定协议类型
        "FromPort": "-1",				//-1代表所有端口
        "ToPort": "-1",
        "CirdIp": "0.0.0.0/0"		//无类别域间路由的0.0.0.0/0意味着所有的源IP地址都被允许
      }
    },
    "Server": {
      [...]
    }
  }
}

使用位于 https://s3.amazonaws.com/awsinaction/chapter6/firewall2.json 的模板更新CloudFormation的堆栈。



允许SSH流量
当能够ping自己的EC2实例后,用户会想要通过SSH登录到自己的EC2实例。
要想通过SSH登录到自己的EC2实例,必须创建一条规则,允许端口22上的入站TCP请求。

允许SSH的安全组
[...]
"AllowInboundSSH": {
  "Type": "AWS::EC2::SecurityGroupIngress",			//允许SSH规则描述
  "Properties": {
    "GroupId": {"Ref": "SecurityGroup"},			//将安全组与规则联系起来
    "IpProtocol": "tcp",			//SSH基于TCP协议
    "FromPort": "22",				//默认的SSH端口是22
    "ToPort": "22",					//允许一个范围的端口,或者将出站后到达的端口设为与入站时达到的端口相同
    "CidrIp": "0.0.0.0/0"			//0.0.0.0/0的无类别域间路由意味着所有的源IP地址都被允许
  }
},
[...]

使用位于 https://s3.amazonaws.com/awsinaction/chapter6/firewall3.json 的模板更新CloudFormation的堆栈。

现在我们可以使用SSH登录自己的虚拟服务器了,注意:我们还需正确的私钥。
防火墙知识控制网络层,它不能替代基于密码或密钥的身份认证。



允许来自源IP地址的SSH流量
在模板中硬编码进公有IP地址存在问题:公有IP地址会变化,解决方法:使用参数Parameters。
添加一个参数来保存自己当前的公有IP地址,然后修改AllowInboundSSH规则。

允许SSH的安全组
[...]
"Parameters": "{
  [...],
  "IpForSSH": {
    "Description": "Your Public IP address to allow SSH access",
    "Type": "String"
  }
},
"Resources":{
 "AllowInboundSSH": {
  "Type": "AWS::EC2::SecurityGroupIngress",			//允许SSH规则描述
  "Properties": {
    "GroupId": {"Ref": "SecurityGroup"},			//将安全组与规则联系起来
    "IpProtocol": "tcp",			//SSH基于TCP协议
    "FromPort": "22",				//默认的SSH端口是22
    "ToPort": "22",					//允许一个范围的端口,或者将出站后到达的端口设为与入站时达到的端口相同
    "CidrIp": {"Fn::Join": ["", [{"Ref": "IpForSSH"}, "/32"]]}			//使用$IpForSSH/32作为值
  }
},
[...]

公有IP地址和私有IP地址的区别:
在自己的本地网络中使用私有IP地址,而当连接到互联网时,使用的是互联网的网关IP地址,所有的请求都被重定向到互联网网关。而你的本地网络并不知道这个公有IP地址。
要找出自己的公有IP地址,访问 http://api.ipify.org
对于大多数人来说,通常当我们重新连接到互联网时,公有IP地址会时不时的发生变化。

使用位于 https://s3.amazonaws.com/awsinaction/chapter6/firewall4.json 的模板更新CloudFormation堆栈。当要求输入参数时,输入你的公有IP地址$IpForSSH,现在只有你的IP地址能够建立到你的EC2实例的SSH连接。

无类别域间路由CIDR:Classless Inter Domian Route
CIDR用于指定源IP地址的范围。



允许来自源安全组的SSH流量:使用堡垒主机
如果要控制一个AWS资源到另一个AWS资源的的流量,可以使用安全组。
可以根据源与目的地是否属于一个特定的安全组来控制网络的流量。
因为云的弹性性质,用户很可能处理动态数量的服务器,所以基于源IP地址的规则难以维护,如果用户的规则是基于安全组的,则易于维护。

用于SSH访问的堡垒主机(跳转盒)
其中的技巧在于:只有一台服务器----堡垒主机,能通过SSH被互联网访问(应该被限制到一个特定的源IP地址)。所有其它服务器只能从堡垒主机使用SSH访问。
优势:
1.用户的系统只有一个入口,且这一入口除了SSH不做其他事。这个盒子被攻破的机会很小
2.如果用户的某台网站服务器,邮件服务器,FTP服务器被攻破了,攻击者无法从这台服务器跳转到所有其它服务器
要实现堡垒主机的概念,必须做到以下两点:
1.允许从0.0.0.0/0或一个指定的IP地址使用SSH访问堡垒主机
2.只有当流量来源于堡垒主机时才允许使用SSH连接到所有其它服务器

例:一台堡垒主机加两台服务器的体系:这两台服务器仅仅接受来自堡垒主机的入站SSH访问。
aws搭建包含服务器和网络的虚拟基础设施(2)_第84张图片
aws搭建包含服务器和网络的虚拟基础设施(2)_第85张图片

AWSTemplateFormatVersion: 2010-09-09
Description: 'AWS in Action: chapter 6 (firewall 5)'
Parameters:
 KeyName:
   Description: Key Pair name
   Type: 'AWS::EC2::KeyPair::KeyName'
   Default: mykey
 VPC:
   Description: Just select the one and only default VPC
   Type: 'AWS::EC2::VPC::Id'
 Subnet:
   Description: Just select one of the available subnets
   Type: 'AWS::EC2::Subnet::Id'
 IpForSSH:
   Description: Your public IP address to allow SSH access
   Type: String
Mappings:
 EC2RegionMap:
   ap-northeast-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-cbf90ecb
   ap-southeast-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-68d8e93a
   ap-southeast-2:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-fd9cecc7
   eu-central-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-a8221fb5
   eu-west-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-a10897d6
   sa-east-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-b52890a8
   us-east-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-1ecae776
   us-west-1:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-d114f295
   us-west-2:
     AmazonLinuxAMIHVMEBSBacked64bit: ami-e7527ed7
Resources:
 SecurityGroup:
   Type: 'AWS::EC2::SecurityGroup'
   Properties:
     GroupDescription: My security group
     VpcId: !Ref VPC
 AllowInboundICMP:
   Type: 'AWS::EC2::SecurityGroupIngress'
   Properties:
     GroupId: !Ref SecurityGroup
     IpProtocol: icmp
     FromPort: '-1'
     ToPort: '-1'
     CidrIp: 0.0.0.0/0
 AllowInboundSSH:
   Type: 'AWS::EC2::SecurityGroupIngress'
   Properties:
     GroupId: !Ref SecurityGroup
     IpProtocol: tcp
     FromPort: '22'
     ToPort: '22'
     CidrIp: !Join 
       - ''
       - - !Ref IpForSSH
         - /32
 SecurityGroupPrivate:
   Type: 'AWS::EC2::SecurityGroup'
   Properties:
     GroupDescription: My security group
     VpcId: !Ref VPC
 AllowPrivateInboundSSH:
   Type: 'AWS::EC2::SecurityGroupIngress'
   Properties:
     GroupId: !Ref SecurityGroupPrivate
     IpProtocol: tcp
     FromPort: '22'
     ToPort: '22'
     SourceSecurityGroupId: !Ref SecurityGroup
 BastionHost:
   Type: 'AWS::EC2::Instance'
   Properties:
     ImageId: !FindInMap 
       - EC2RegionMap
       - !Ref 'AWS::Region'
       - AmazonLinuxAMIHVMEBSBacked64bit
     InstanceType: t2.micro
     KeyName: !Ref KeyName
     SecurityGroupIds:
       - !Ref SecurityGroup
     SubnetId: !Ref Subnet
 Server1:
   Type: 'AWS::EC2::Instance'
   Properties:
     ImageId: !FindInMap 
       - EC2RegionMap
       - !Ref 'AWS::Region'
       - AmazonLinuxAMIHVMEBSBacked64bit
     InstanceType: t2.micro
     KeyName: !Ref KeyName
     SecurityGroupIds:
       - !Ref SecurityGroupPrivate
     SubnetId: !Ref Subnet
 Server2:
   Type: 'AWS::EC2::Instance'
   Properties:
     ImageId: !FindInMap 
       - EC2RegionMap
       - !Ref 'AWS::Region'
       - AmazonLinuxAMIHVMEBSBacked64bit
     InstanceType: t2.micro
     KeyName: !Ref KeyName
     SecurityGroupIds:
       - !Ref SecurityGroupPrivate
     SubnetId: !Ref Subnet
Outputs:
 BastionHostPublicName:
   Value: !GetAtt 
     - BastionHost
     - PublicDnsName
   Description: Bastion host public name (connect via SSH as user ec2-user)
 Server1PublicName:
   Value: !GetAtt 
     - Server1
     - PublicDnsName
   Description: Server1 public name
 Server2PublicName:
   Value: !GetAtt 
     - Server2
     - PublicDnsName
   Description: Server2 public name

使用:https://s3.amazonaws.com/awsinaction/chapter6/firewall5.json 的模板更新CloudFormation堆栈。
若更新完成,堆栈会显示以下三个输出:

  • BastionHostPublicName:从你的计算机通过SSH使用堡垒主机连接
  • Server1PublicName:你只能从堡垒主机连接这台服务器
  • Server2PublicName:你只能从堡垒主机连接这台服务器

现通过SSH命令:ssh -I $PathToKey/mykey.pem -A ec2-user@$BastionHostPublicName连接到堡垒主机BastionHostName。
$PathToKey替换为你的SSH密钥路径,$BastionHostPublicName替换为你的堡垒主机的公开名称。
-A选项用于启用AgentForwarding,代理转发让你可以使用登录堡垒主机的同一密钥来进一步的从堡垒主机发起的SSH登录进行身份认证。
执行下面的命令把你的密钥加到SSH代理:
ssh-add $PathToKey/mykey.pem

使用PuTTY进行代理转发:
要使用PuTTY进行代理转发,需要确保已经双击私钥文件将密钥装载到PuTTY Pageant。
同时必须启用【Connection-----SSH-----Auth-----Allow Agent Forwarding】
通过PuTTY允许代理转发
aws搭建包含服务器和网络的虚拟基础设施(2)_第86张图片
先登陆到堡垒主机,进而通过堡垒主机登录到其它服务器。
堡垒主机可以用来为系统增加一层安全保护,如果其中的一台服务器被攻陷了,攻击者无法跳转到系统中的其它服务器上。这样减少了一个攻击者能够造成的潜在的危害。堡垒主机只做SSH,不做其他事情,这样能减少它成为安全风险的机会。
经常使用堡垒主机模式保护客户安全。



在云中创建一个私有网络:虚拟私有云VPC
通过创建VPC(Virtual Private Cloud),用户将在AWS上得到自己的私有网络。
用户可以创建子网,路由表,访问控制列表ACL,访问互联网的网关或VPN端点(Virtual Private Network)。

子网能让用户分离关注点:为用户的DB,网站服务器,缓存服务器或应用服务器,或任何能分离的两个系统创建新的子网。
另一个经验是:用户应该至少有两个子网,即共有子网和私有子网。公有子网能够路由到互联网,私有子网则不能。用户的网站服务器应该位于公有子网中,用户的DB应位于私有子网中。

利用 https://s3.amazonaws.com/awsinaction/chapter6/vpc.json 的模板创建CloudFormation。
创建完成后,复制VarnishServerPublicName输出并在浏览器中打开,将看见一个Varnish缓存的Apache测试页面。

资源清理:最后通过删除堆栈来清除所有用过的资源以避免收取费用。


{
	"AWSTemplateFormatVersion": "2010-09-09",
	"Description": "AWS in Action: chapter 6 (VPC)",
	"Parameters": {
		"KeyName": {
			"Description": "Key Pair name",
			"Type": "AWS::EC2::KeyPair::KeyName",
			"Default": "mykey"
		}
	},
	"Mappings": {
		"EC2RegionMap": {
			"ap-northeast-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-cbf90ecb", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-03cf3903"},
			"ap-southeast-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-68d8e93a", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-b49dace6"},
			"ap-southeast-2": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-fd9cecc7", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-e7ee9edd"},
			"eu-central-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-a8221fb5", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-46073a5b"},
			"eu-west-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-a10897d6", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-6975eb1e"},
			"sa-east-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-b52890a8", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-fbfa41e6"},
			"us-east-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-1ecae776", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-303b1458"},
			"us-west-1": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-d114f295", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-7da94839"},
			"us-west-2": {"AmazonLinuxAMIHVMEBSBacked64bit": "ami-e7527ed7", "AmazonLinuxNATAMIHVMEBSBacked64bit": "ami-69ae8259"}
		}
	},
	"Resources": {
		"SecurityGroup": {
			"Type": "AWS::EC2::SecurityGroup",
			"Properties": {
				"GroupDescription": "My security group",
				"VpcId": {"Ref": "VPC"}
			}
		},
		"SecurityGroupIngress": {
			"Type": "AWS::EC2::SecurityGroupIngress",
			"Properties":{
				"IpProtocol": "-1",
				"FromPort": "-1",
				"ToPort": "-1",
				"CidrIp": "0.0.0.0/0",
				"GroupId": {"Ref": "SecurityGroup"}
			}
		},
		"SecurityGroupEgress": {
			"Type": "AWS::EC2::SecurityGroupEgress",
			"Properties":{
				"IpProtocol": "-1",
				"FromPort": "-1",
				"ToPort": "-1",
				"CidrIp": "0.0.0.0/0",
				"GroupId": {"Ref": "SecurityGroup"}
			}
		},
		"VPC": {
			"Type": "AWS::EC2::VPC",
			"Properties": {
				"CidrBlock": "10.0.0.0/16",
				"EnableDnsHostnames": "true"
			}
		},
		"InternetGateway": {
			"Type": "AWS::EC2::InternetGateway",
			"Properties": {
			}
		},
		"VPCGatewayAttachment": {
			"Type": "AWS::EC2::VPCGatewayAttachment",
			"Properties": {
				"VpcId": {"Ref": "VPC"},
				"InternetGatewayId": {"Ref": "InternetGateway"}
			}
		},
		"SubnetPublicNAT": {
			"Type": "AWS::EC2::Subnet",
			"Properties": {
				"AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]},
				"CidrBlock": "10.0.0.0/24",
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTablePublicNAT": {
			"Type": "AWS::EC2::RouteTable",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTableAssociationPublicNAT": {
			"Type": "AWS::EC2::SubnetRouteTableAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPublicNAT"},
				"RouteTableId": {"Ref": "RouteTablePublicNAT"}
			}
		},
		"RoutePublicNATToInternet": {
			"Type": "AWS::EC2::Route",
			"Properties": {
				"RouteTableId": {"Ref": "RouteTablePublicNAT"},
				"DestinationCidrBlock": "0.0.0.0/0",
				"GatewayId": {"Ref": "InternetGateway"}
			},
			"DependsOn": "VPCGatewayAttachment"
		},
		"NetworkAclPublicNAT": {
			"Type": "AWS::EC2::NetworkAcl",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"SubnetNetworkAclAssociationPublicNAT": {
			"Type": "AWS::EC2::SubnetNetworkAclAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPublicNAT"},
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"}
			}
		},
		"NetworkAclEntryInPublicNATHTTP": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "80",
					"To": "80"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "10.0.0.0/16"
			}
		},
		"NetworkAclEntryInPublicNATHTTPS": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"},
				"RuleNumber": "110",
				"Protocol": "6",
				"PortRange": {
					"From": "443",
					"To": "443"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "10.0.0.0/16"
			}
		},
		"NetworkAclEntryInPublicNATEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPublicNATHTTP": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "80",
					"To": "80"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPublicNATHTTPS": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"},
				"RuleNumber": "110",
				"Protocol": "6",
				"PortRange": {
					"From": "443",
					"To": "443"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPublicNATEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicNAT"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"SubnetPublicSSHBastion": {
			"Type": "AWS::EC2::Subnet",
			"Properties": {
				"AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]},
				"CidrBlock": "10.0.1.0/24",
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTablePublicSSHBastion": {
			"Type": "AWS::EC2::RouteTable",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTableAssociationPublicSSHBastion": {
			"Type": "AWS::EC2::SubnetRouteTableAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPublicSSHBastion"},
				"RouteTableId": {"Ref": "RouteTablePublicSSHBastion"}
			}
		},
		"RoutePublicSSHBastionToInternet": {
			"Type": "AWS::EC2::Route",
			"Properties": {
				"RouteTableId": {"Ref": "RouteTablePublicSSHBastion"},
				"DestinationCidrBlock": "0.0.0.0/0",
				"GatewayId": {"Ref": "InternetGateway"}
			},
			"DependsOn": "VPCGatewayAttachment"
		},
		"NetworkAclPublicSSHBastion": {
			"Type": "AWS::EC2::NetworkAcl",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"SubnetNetworkAclAssociationPublicSSHBastion": {
			"Type": "AWS::EC2::SubnetNetworkAclAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPublicSSHBastion"},
				"NetworkAclId": {"Ref": "NetworkAclPublicSSHBastion"}
			}
		},
		"NetworkAclEntryInPublicSSHBastionSSH": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicSSHBastion"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "22",
					"To": "22"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryInPublicSSHBastionEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicSSHBastion"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "10.0.0.0/16"
			}
		},
		"NetworkAclEntryOutPublicSSHBastionSSH": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicSSHBastion"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "22",
					"To": "22"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "10.0.0.0/16"
			}
		},
		"NetworkAclEntryOutPublicSSHBastionEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicSSHBastion"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"SubnetPublicVarnish": {
			"Type": "AWS::EC2::Subnet",
			"Properties": {
				"AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]},
				"CidrBlock": "10.0.2.0/24",
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTablePublicVarnish": {
			"Type": "AWS::EC2::RouteTable",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTableAssociationPublicVarnish": {
			"Type": "AWS::EC2::SubnetRouteTableAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPublicVarnish"},
				"RouteTableId": {"Ref": "RouteTablePublicVarnish"}
			}
		},
		"RoutePublicVarnishToInternet": {
			"Type": "AWS::EC2::Route",
			"Properties": {
				"RouteTableId": {"Ref": "RouteTablePublicVarnish"},
				"DestinationCidrBlock": "0.0.0.0/0",
				"GatewayId": {"Ref": "InternetGateway"}
			},
			"DependsOn": "VPCGatewayAttachment"
		},
		"NetworkAclPublicVarnish": {
			"Type": "AWS::EC2::NetworkAcl",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"SubnetNetworkAclAssociationPublicVarnish": {
			"Type": "AWS::EC2::SubnetNetworkAclAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPublicVarnish"},
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"}
			}
		},
		"NetworkAclEntryInPublicVarnishSSH": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "22",
					"To": "22"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "10.0.1.0/24"
			}
		},
		"NetworkAclEntryInPublicVarnishHTTP": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"},
				"RuleNumber": "110",
				"Protocol": "6",
				"PortRange": {
					"From": "80",
					"To": "80"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryInPublicVarnishEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPublicVarnishHTTP": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "80",
					"To": "80"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPublicVarnishHTTPS": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"},
				"RuleNumber": "110",
				"Protocol": "6",
				"PortRange": {
					"From": "443",
					"To": "443"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPublicVarnishEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPublicVarnish"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"SubnetPrivateApache": {
			"Type": "AWS::EC2::Subnet",
			"Properties": {
				"AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]},
				"CidrBlock": "10.0.3.0/24",
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTablePrivateApache": {
			"Type": "AWS::EC2::RouteTable",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"RouteTableAssociationPrivateApache": {
			"Type": "AWS::EC2::SubnetRouteTableAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPrivateApache"},
				"RouteTableId": {"Ref": "RouteTablePrivateApache"}
			}
		},
		"RoutePrivateApacheToInternet": {
			"Type": "AWS::EC2::Route",
			"Properties": {
				"RouteTableId": {"Ref": "RouteTablePrivateApache"},
				"DestinationCidrBlock": "0.0.0.0/0",
				"InstanceId": {"Ref": "NatServer"}
			}
		},
		"NetworkAclPrivateApache": {
			"Type": "AWS::EC2::NetworkAcl",
			"Properties": {
				"VpcId": {"Ref": "VPC"}
			}
		},
		"SubnetNetworkAclAssociationPrivateApache": {
			"Type": "AWS::EC2::SubnetNetworkAclAssociation",
			"Properties": {
				"SubnetId": {"Ref": "SubnetPrivateApache"},
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"}
			}
		},
		"NetworkAclEntryInPrivateApacheSSH": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "22",
					"To": "22"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "10.0.1.0/24"
			}
		},
		"NetworkAclEntryInPrivateApacheHTTP": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"},
				"RuleNumber": "110",
				"Protocol": "6",
				"PortRange": {
					"From": "80",
					"To": "80"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "10.0.2.0/24"
			}
		},
		"NetworkAclEntryInPrivateApacheEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "false",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPrivateApacheHTTP": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"},
				"RuleNumber": "100",
				"Protocol": "6",
				"PortRange": {
					"From": "80",
					"To": "80"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPrivateApacheHTTPS": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"},
				"RuleNumber": "110",
				"Protocol": "6",
				"PortRange": {
					"From": "443",
					"To": "443"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "0.0.0.0/0"
			}
		},
		"NetworkAclEntryOutPrivateApacheEphemeralPorts": {
			"Type": "AWS::EC2::NetworkAclEntry",
			"Properties": {
				"NetworkAclId": {"Ref": "NetworkAclPrivateApache"},
				"RuleNumber": "200",
				"Protocol": "6",
				"PortRange": {
					"From": "1024",
					"To": "65535"
				},
				"RuleAction": "allow",
				"Egress": "true",
				"CidrBlock": "10.0.0.0/16"
			}
		},
		"NatServer": {
			"Type": "AWS::EC2::Instance",
			"Properties": {
				"ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxNATAMIHVMEBSBacked64bit"]},
				"InstanceType": "t2.micro",
				"KeyName": {"Ref": "KeyName"},
				"NetworkInterfaces": [{
					"AssociatePublicIpAddress": "true",
					"DeleteOnTermination": "true",
					"SubnetId": {"Ref": "SubnetPublicNAT"},
					"DeviceIndex": "0",
					"GroupSet": [{"Ref": "SecurityGroup"}]
				}],
				"SourceDestCheck": "false",
				"UserData": {"Fn::Base64": {"Fn::Join": ["", [
					"#!/bin/bash -ex\n",
					"/opt/aws/bin/cfn-signal --stack ", {"Ref": "AWS::StackName"}, " --resource NatServer --region ", {"Ref": "AWS::Region"}, "\n"
				]]}}
			},
			"CreationPolicy": {
				"ResourceSignal": {
					"Timeout": "PT5M"
				}
			},
			"DependsOn": "VPCGatewayAttachment"
		},
		"BastionHost": {
			"Type": "AWS::EC2::Instance",
			"Properties": {
				"ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxAMIHVMEBSBacked64bit"]},
				"InstanceType": "t2.micro",
				"KeyName": {"Ref": "KeyName"},
				"NetworkInterfaces": [{
					"AssociatePublicIpAddress": "true",
					"DeleteOnTermination": "true",
					"SubnetId": {"Ref": "SubnetPublicSSHBastion"},
					"DeviceIndex": "0",
					"GroupSet": [{"Ref": "SecurityGroup"}]
				}]
			},
			"DependsOn": "VPCGatewayAttachment"
		},
		"VarnishServer": {
			"Type": "AWS::EC2::Instance",
			"Properties": {
				"ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxAMIHVMEBSBacked64bit"]},
				"InstanceType": "t2.micro",
				"KeyName": {"Ref": "KeyName"},
				"NetworkInterfaces": [{
					"AssociatePublicIpAddress": "true",
					"DeleteOnTermination": "true",
					"SubnetId": {"Ref": "SubnetPublicVarnish"},
					"DeviceIndex": "0",
					"GroupSet": [{"Ref": "SecurityGroup"}]
				}],
				"UserData": {"Fn::Base64": {"Fn::Join": ["", [
					"#!/bin/bash -ex\n",
					"yum -y install varnish-3.0.7\n",
					"cat > /etc/varnish/default.vcl << EOF\n",
					"backend default {\n",
					"  .host = \"", {"Fn::GetAtt": ["ApacheServer", "PrivateIp"]} ,"\";\n",
					"  .port = \"80\";\n",
					"}\n",
					"EOF\n",
					"sed -i.bak \"s/^VARNISH_LISTEN_PORT=.*/VARNISH_LISTEN_PORT=80/\" /etc/sysconfig/varnish\n",
					"service varnish start\n",
					"/opt/aws/bin/cfn-signal --stack ", {"Ref": "AWS::StackName"}, " --resource VarnishServer --region ", {"Ref": "AWS::Region"}, "\n"
				]]}}
			},
			"CreationPolicy": {
				"ResourceSignal": {
					"Timeout": "PT5M"
				}
			},
			"DependsOn": "VPCGatewayAttachment"
		},
		"ApacheServer": {
			"Type": "AWS::EC2::Instance",
			"Properties": {
				"ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxAMIHVMEBSBacked64bit"]},
				"InstanceType": "t2.micro",
				"KeyName": {"Ref": "KeyName"},
				"NetworkInterfaces": [{
					"AssociatePublicIpAddress": "false",
					"DeleteOnTermination": "true",
					"SubnetId": {"Ref": "SubnetPrivateApache"},
					"DeviceIndex": "0",
					"GroupSet": [{"Ref": "SecurityGroup"}]
				}],
				"UserData": {"Fn::Base64": {"Fn::Join": ["", [
					"#!/bin/bash -ex\n",
					"yum -y install httpd\n",
					"service httpd start\n",
					"/opt/aws/bin/cfn-signal --stack ", {"Ref": "AWS::StackName"}, " --resource ApacheServer --region ", {"Ref": "AWS::Region"}, "\n"
				]]}}
			},
			"CreationPolicy": {
				"ResourceSignal": {
					"Timeout": "PT10M"
				}
			},
			"DependsOn": "NatServer"
		}
	},
	"Outputs": {
		"BastionHostPublicName": {
			"Value": {"Fn::GetAtt": ["BastionHost", "PublicDnsName"]},
			"Description": "connect via SSH as user ec2-user"
		},
		"VarnishServerPublicName": {
			"Value": {"Fn::GetAtt": ["VarnishServer", "PublicDnsName"]},
			"Description": "handles HTTP requests"
		},
		"VarnishServerPrivateIp": {
			"Value": {"Fn::GetAtt": ["VarnishServer", "PrivateIp"]},
			"Description": "connect via SSH from bastion host"
		},
		"ApacheServerPrivateIp": {
			"Value": {"Fn::GetAtt": ["ApacheServer", "PrivateIp"]},
			"Description": "connect via SSH from bastion host"
		}
	}
}

AWS CloudFormation 文档:https://docs.aws.amazon.com/zh_cn/cloudformation/?id=docs_gateway

AWS CloudFormation 概念:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/cfn-whatis-concepts.html
模板剖析:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/template-anatomy.html
AWS 资源和属性类型参考:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html
使用 AWS CloudFormation Designer 设计您自己的模板:https://console.aws.amazon.com/cloudformation/designer/home?region=us-east-1

AWS CloudFormation Designer 界面概述:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/working-with-templates-cfn-designer-overview.html

集成的 JSON 和 YAML 编辑器:https://docs.aws.amazon.com/zh_cn/AWSCloudFormation/latest/UserGuide/working-with-templates-cfn-designer-json-editor.html?icmpid=docs_cfn_console_designer
aws搭建包含服务器和网络的虚拟基础设施(2)_第87张图片

你可能感兴趣的:(aws,aws)