《AWS云计算实战》6.保护系统安全:IAM、安全组和VPC

保护系统安全

检查安全更新

1⃣️ 在服务器启动时安装安全更新:在用户数据脚本中添加安全更新命令:

# 检查安全更新
yum -security check-update

# 安装所有更新
yum -y update

# 仅安装安全更新
yum -y -security update

2⃣️ 在服务器运行时安装安全更新:使用一个脚本获取所有服务器列表,然后在所有运行的 EC2 实例上安装安全更新:

update.sh 在所有服务器上安装安全更新的脚本文件

#!/bin/bash -ex

PUBLICNAMES=$(aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].PublicDnsName" --output text)

for PUBLICNAME in $PUBLICNAMES; do
    ssh -t -o StrictHostKeyChecking=no ec2-user@$PUBLICNAME "sudo yum -y --security update"
done

保护 AWS 账户安全

使用多重身份验证(MFA)来保护你的root用户。然后你将停止使用root用户,创建一个新用户用于日常操作,然后学会授予一个角色最小权限。

IAM 服务

root 用户、IAM 用户、IAM 角色的区别:

root 用户 IAM 用户 IAM 角色
可以有一个密码 总是
可以有一个访问密钥 是(不推荐)
可以属于一个组
可以与一个 EC2 实例关联
  • 密码:登录管理控制台;
  • 访问密钥:使用 AWS CLI 登录;
策略类型

IAM 用户和 IAM 角色通过策略进行授权。

最小授权原则。

创建用户组、IAM 用户、IAM 角色,并将 IAM 角色与 EC2 实例关联。

...

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

  • 防火墙设置原则:只打开必要的端口。
  • 默认情况下,所有的入站流量都被拒绝,而所有的出站流量都被允许。

💡💡💡 源和目的地

入站安全组规则筛选基于网络流量的源。源可以是一个IP地址也可以是一个安全组。这样就可以只允许从特定源IP地址范围来的入站流量。
出站安全组规则筛选基于网路流量的目的地。目的地可以是一个IP地址或安全组。可以只允许特定目的IP地址范围的出站流量。

源 IP 和 目的 IP 针对的都是 EC2 实例外部的 IP 地址。

设置安全组规则

    "Resources": {
        "SecurityGroup": { ## 安全组
            "Type": "AWS::EC2::SecurityGroup", ## 安全组资源类型
            "Properties": {  ## 安全组属性
                "GroupDescription": "My security group", ## 安全组描述
                "VpcId": {"Ref": "VPC"} ## 关联安全组与虚拟网络
            }
        },
        "AllowInboundICMP": { ## 允许 ICPM 规则描述
            "Type": "AWS::EC2::SecurityGroupIngress", ## 入站规则类型
            "Properties": { 
                "GroupId": {"Ref": "SecurityGroup"}, ## 关联入站规则与安全组
                "IpProtocol": "icmp", ## 指定协议
                "FromPort": "-1", ## -1,意味着所有端口
                "ToPort": "-1",
                "CidrIp": "0.0.0.0/0" ## 0.0.0.0/0 表示所有源IP地址都被允许
            }
        },
        "Server": {
            "Type": "AWS::EC2::Instance", ## EC2 实例描述
            "Properties": {
                "ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxAMIHVMEBSBacked64bit"]}, 
                "InstanceType": "t2.micro",
                "KeyName": {"Ref": "KeyName"},
                "SecurityGroupIds": [{"Ref": "SecurityGroup"}], ## 将安全组关联到 EC2 实例上
                "SubnetId": {"Ref": "Subnet"}
            }
        }

允许 ICMP 流量

        "AllowInboundICMP": { ## 允许 ICPM 规则描述
            "Type": "AWS::EC2::SecurityGroupIngress", ## 入站规则类型
            "Properties": {
                "GroupId": {"Ref": "SecurityGroup"}, ## 关联入站规则与安全组
                "IpProtocol": "icmp", ## 指定协议:ICPMP 协议
                "FromPort": "-1", ## -1,意味着所有端口
                "ToPort": "-1",
                "CidrIp": "0.0.0.0/0" ## 0.0.0.0/0 表示所有源IP地址都被允许
            }
        },

允许 SSH 流量

        "IpForSSH": { ## 公有 IP 地址参数
            "Description": "Your public IP address to allow SSH access",
            "Type": "String"
        }
        ...
        "AllowInboundSSH": { ## 允许 SSH 规则描述
            "Type": "AWS::EC2::SecurityGroupIngress", ## 入站规则类型
            "Properties": {
                "GroupId": {"Ref": "SecurityGroup"}, ## 关联入站规则与安全组
                "IpProtocol": "tcp", ## SSH 基于 TCP 协议
                "FromPort": "22", ## 默认的 SSH 端口号:22
                "ToPort": "22",
                "CidrIp": {"Fn::Join": ["", [{"Ref": "IpForSSH"}, "/32"]]} ## 指定源IP
            }
        },

查看你的公有IP地址:http://api.ipify.org

在云中创建一个私有网络:虚拟私有云(VPC)

公有子网&私有子网

💡

用户应该至少有两个子网,即公有子网和私有子网。公有子网能够路由到互联网,私有子网则不能。

公有子网:用户的网站服务器。

私有子网:用户的数据库服务器。

公有子网和私有子网到唯一区别是,私有子网不能路由到互联网网关( IGW)。


私有子网如何访问互联网?如何下载安装应用源码?

在公有子网中使用一个 NAT 服务器,并且创建一条从用户的私有子网到 NAT 服务器的路由。一台 NAT 服务器就是一台用来处理网络地址转换的虚拟服务器。来自用户的私有子网的互联网流量将从 NAT 服务器的公有 IP 地址访问互联网。

网络安全组 & 网络访问控制列表 ACL

安全组与网络 ACL 的比较

安全组与ACL有一个重要的区别:安全组是有状态的,而 ACL 则没有。

如果用户允许在安全组上的一个入站端口,那么该入站端口上的请求对应的出站响应也是被允许的。安全组规则将按用户所期望的方式工作。如果用户在安全组上打开端口22,就能通过SSH连接。

ACL 则不同。如果用户仅仅为子网的 ACL 打开入站端口22,仍然不能通过 SSH 访问。除此之外,用户还需要允许出站临时端口,因为 sshd(SSH守护进程)在端口22上接受连接,但却使用临时端口与客户端通信。临时端口从范围1024至65535中选择。
如果用户想从自己的子网发起一个 SSH 连接,就需要打开出站端口22且同时打开入站临时端口。如果对这些都不熟悉,应该使用安全组且在ACL层允许所有。

AWS 示例

上图含义:来自 Internet 网关的数据流会通过路由表中的路径被路由到合适的子网。与子网相关的网络 ACL 规则控制允许进入子网的数据流。与实例相关的安全组规则控制允许进入实例的数据流。

互联网网关 IGW

IGW (Internet Gateway):互联网网关,会使用网络地址转换(network address translation, NAT)把虚拟服务器的公有IP地址转换成它们的私有IP地址。

附:CIDR (无类域间路由)的概念

一个示例:计算 192.168.23.35/21 计算子网的网络 ID、子网掩码、起止 IP 地址?

CIDR 表示法:192.168.23.35/21

IP 地址: 11000000.10101000.00010111.00100011 (192.168.23.35)

子网掩码:11111111.11111111.11111000.00000000 (255.255.248.0)即21个1

网络 ID: 11000000.10101000.00010000.00000000 (192.168.16.0)

起始 IP 地址: 11000000.10101000.00010000.00000001 (192.168.16.1)

结束 IP 地址:11000000.10101000.00010111.11111110 (192.168.23.254)

广播 IP 地址:11000000.10101000.00010111.11111111 (192.168.23.255)主机 ID 全1。

附:有4个子网来保护网站应用安全的VPC

有4个子网来保护网站应用安全的VPC
CloudFormation 模版文件示例:
{
    "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": { ## 1.虚拟网络 VPC
            "Type": "AWS::EC2::VPC",
            "Properties": {
                "CidrBlock": "10.0.0.0/16", ## 地址空间
                "EnableDnsHostnames": "true"
            }
        },
        "InternetGateway": {  ## 互联网网关 IGW
            "Type": "AWS::EC2::InternetGateway",
            "Properties": {
            }
        },
        "VPCGatewayAttachment": { ## 将网关关联到VPC
            "Type": "AWS::EC2::VPCGatewayAttachment",
            "Properties": {
                "VpcId": {"Ref": "VPC"},
                "InternetGatewayId": {"Ref": "InternetGateway"}
            }
        },
        "SubnetPublicNAT": { ## 1.1 公有 NAT 子网
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]},
                "CidrBlock": "10.0.0.0/24", ## NAT 子网的地址空间
                "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": { ## NAT 子网是公有的能路由到互联网
            "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": { ## 1.2 公有堡垒主机子网
            "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", ## 将任何地址路由至 IGW
                "GatewayId": {"Ref": "InternetGateway"}
            },
            "DependsOn": "VPCGatewayAttachment"
        },
        "NetworkAclPublicSSHBastion": { ## 公有子网访问控制列表 ACL
            "Type": "AWS::EC2::NetworkAcl",
            "Properties": {
                "VpcId": {"Ref": "VPC"}
            }
        },
        "SubnetNetworkAclAssociationPublicSSHBastion": { ## 关联
            "Type": "AWS::EC2::SubnetNetworkAclAssociation",
            "Properties": {
                "SubnetId": {"Ref": "SubnetPublicSSHBastion"},
                "NetworkAclId": {"Ref": "NetworkAclPublicSSHBastion"}
            }
        },
        "NetworkAclEntryInPublicSSHBastionSSH": { ## 允许来自任何地方的入站 SSH 流量
            "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": { ## 用于短 TCP/IP 连接的入站临时端口
            "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": { ## 允许从 VPC 出站的 SSH 流量
            "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": {  ## 出站临时端口,用于 SSH 出站连接
            "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": {  ## 1.3 Varnish 网络缓存子网,公有子网
            "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": { ## 1.4 Apache 网站服务器私有子网
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "AvailabilityZone": {"Fn::Select": ["0", {"Fn::GetAZs": ""}]},
                "CidrBlock": "10.0.3.0/24", ## 私有子网地址空间
                "VpcId": {"Ref": "VPC"}
            }
        },
        # 公有子网和私有子网到唯一区别是,私有子网不能路由到互联网网关( IGW)。
        "RouteTablePrivateApache": { ## Apache 私有子网路由表。没有路由到 IGW。
            "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"} ## 从 Apache 子网路由到 NAT 实例
            }
        },
        "NetworkAclPrivateApache": { ## Apache 私有子网 ACL 
            "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": { ## NAT 服务器,私有子网的互联网流量将从 NAT 服务器的公有 IP 地址访问互联网。
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxNATAMIHVMEBSBacked64bit"]}, ## AWS 提供了配置好的 NAT 实例映像
                "InstanceType": "t2.micro",
                "KeyName": {"Ref": "KeyName"},
                "NetworkInterfaces": [{
                    "AssociatePublicIpAddress": "true", ## 分配公有 IP 地址,所有私有子网到互联网流量的源地址
                    "DeleteOnTermination": "true",
                    "SubnetId": {"Ref": "SubnetPublicNAT"},
                    "DeviceIndex": "0",
                    "GroupSet": [{"Ref": "SecurityGroup"}]
                }],
                "SourceDestCheck": "false", ## 默认情况下,一个实例必须是它发送的网络流量的源或者目的地。 对 NAT 实例禁用此检查。
                "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", ## 分配一个公有 IP 地址
                    "DeleteOnTermination": "true",
                    "SubnetId": {"Ref": "SubnetPublicSSHBastion"}, ## 在堡垒主机子网中启动
                    "DeviceIndex": "0",
                    "GroupSet": [{"Ref": "SecurityGroup"}] ## 安全组允许所有流量
                }]
            },
            "DependsOn": "VPCGatewayAttachment"
        },
        "VarnishServer": { ## Varnish 服务器
            "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": { ## Apache 服务器
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {"Fn::FindInMap": ["EC2RegionMap", {"Ref": "AWS::Region"}, "AmazonLinuxAMIHVMEBSBacked64bit"]},
                "InstanceType": "t2.micro",
                "KeyName": {"Ref": "KeyName"},
                "NetworkInterfaces": [{
                    "AssociatePublicIpAddress": "false", ## 不分配公有 IP 地址。
                    "DeleteOnTermination": "true",
                    "SubnetId": {"Ref": "SubnetPrivateApache"}, ## 在私有子网中启动
                    "DeviceIndex": "0",
                    "GroupSet": [{"Ref": "SecurityGroup"}]
                }],
                "UserData": {"Fn::Base64": {"Fn::Join": ["", [
                    "#!/bin/bash -ex\n",
                    "yum -y install httpd\n", ## 从互联网安装 Apache
                    "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"
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容