建立 AWS 到 IDC 的VPN

由于我们的很多运维工具都部署在自己的 IDC 里面,比如 Puppet、YUM 源、NTP 服务器、Nginx 日志分析工具 等,如果不打通 AWS 到 IDC 的内网,这些工具都要在 AWS 搭建一份,太麻烦,so do it .

一开始我想使用 AWS 的「VPN连接」服务(文档在 这里 )来做,但是要求 IDC 端是 cisco 路由器等硬件设备,我们 IDC 没有这些设备,所以只能找机器来做了。

 

1.机器是 Centos6,改一下脚本,在两台机器上执行。

#!/bin/bash
#L_PUBLIC=$(curl -s ip.cn | grep -Po ‘\d+\.\d+\.\d+\.\d+’)
L_PUBLIC=$L_PUBLIC
R_PUBLIC=$R_PUBLIC
L_PRIVATE=$L_PRIVATE
R_PRIVATE=$R_PRIVATE
TUNL=tunl-aws
TTL=255

echo "Loading kernel modules…"
modprobe -av ipip
echo "Setting up tunnel…"
ip tunnel del $TUNL &>/dev/null || true # delete old tunnel first
ip tunnel add $TUNL mode ipip local $L_PUBLIC remote $R_PUBLIC ttl $TTL
ip link set $TUNL up
ip addr add $L_PRIVATE peer $R_PRIVATE dev $TUNL
ip route add $R_PRIVATE dev $TUNL
echo "Testing tunnel: pinging from $L_PRIVATE to $R_PRIVATE …"
ping -c1 $R_PRIVATE
[[ $? = 0 ]] && echo "Tunnel is set up successfully."

L_PUBLIC 是 本地机器公网IP,R_PUBLIC 是对方机器公网IP,L_PRIVATE 是 本地私有IP,R_PRIVATE 是对方私有IP,L_PRIVATE 和 R_PRIVATE 在一个网段(两个 PRIVATE IP 用于两端通信,因为是两个IP,所以划一个 /30 的网段就行了)。

要注意两点:

1). AWS 端机器的 L_PUBLIC 要写内网IP,而不是弹性IP(这点应该和 AWS 的网络结构有关),否则执行脚本之后也无法 ping 对方的 PRIVATE IP.

2). 两台机器 net.ipv4.ip_forward 要设置为 1 .

 

2.配置好隧道之后,还要在 两台机器上添加路由,比如我在 IDC 机器上增加:

route add -net 172.30.0.0/16 gw 10.0.20.34

在 AWS 机器上增加:

route add -net 10.0.0.0/8 gw 10.0.20.33

172.30.0.0/16 是 AWS 的网段,10.0.0.0/8 是 IDC 的网段。

 

3.需要在两端所有的机器上增加路由表,在 IDC 可以通过 Puppet 增加,更好的方式是通过 ospf 发布路由,还可以向公司的网络工程师帮忙。

在 AWS 可以修改 「VPC 的路由表」,增加一条到 IDC 网段的路由,我这里是把 10.0.0.0/8 网段的路由指向 AWS 机器 内网的接口上,如图:

S488C0Q)5W$QUW0@E[E`SNY

另外要注意的是,增加路由表之后,在 ec2 机器上 用 route -n 是看不到增加的路由的,但是确实已经生效;当 ec2 机器重启之后,此时用 route -n 可以看到增加的路由。

 

理论上说,完成上面的步骤之后,VPN 就已经 OK 了,但是这里是 AWS,不是自己的网络架构,所以我又遇到了坑。。。。

上面说了要把两方的机器的 net.ipv4.ip_forward 打开,但是在 ec2 机器上打开之后,还需要关闭 ec2 的 「源/目标检查」,如图:

bbbb

源/目标检查 的解释如下:

Changing the Source/Destination Checking of a Network Interface The Source/Destination Check attribute controls whether source/destination checking is enabled on the instance. Disabling this attribute enables an instance to handle network traffic that isn’t specifically destined for the instance. For example, instances running services such as network address translation, routing, or a firewall should set this value to disabled. The default value is enabled.

最后放张图,看下成果。。。。

aaaa

 

aws 如何在创建实例的时候不自动生成公网IP,同时实例能够访问公网

一开始我的需求是如何在创建实例的时候不自动生成公网IP(为了安全),但是实例也能访问外网(有访问外网的需求,可以通过NAT),因为对aws的网络架构不了解,所以准备从头开始。

 

aws 提供四种网络架构,分别是

VPC with a Single Public Subnet

VPC with Public and Private Subnets

VPC with Public and Private Subnets and Hardware VPN Access

VPC with a Private Subnet Only and Hardware VPN Access

看了很多资料之后发现 aws提供这四种网络架构是为了方面配置,我们可以完全不管这四种网络架构,可以自定义适合自己需求的网络架构,比如我不止需要公有子网和私有子网,还同时需要NAT和VPN,这四种架构都满足不了,这时候可以自定义来解决。

先说下 公网 和 私网,公网可以直接访问外网,私网需要有NAT。一般在AWS里建立一个VPC,再在VPC里面建立多个子网,每个子网可以被指定为 公网 或者 私网,公网和私网的区别在于创建实例的时候是否自动分配公网IP,那么 是否分配公网IP 可以在子网页面的 Modify Auto-Assign Public IP 配置里修改,第一个问题解决了,很简单。

 

我准备说说 VPC with Public and Private Subnets 这种架构,同时证明我们可以自定义出这种网络架构。

aws的官方说明:

762b05ceb5a37091e9f523bd213813d0

此架构会 创建/16网段的VPC,然后在里面建立/24 的两个子网,一个是公有子网,另一个是私有子网,这两个子网默认都不创建公有IP。

公有子网里的实例可以绑定EIP并连接(如果无法连接可能是安全组问题);私有子网里的实例也可以绑定EIP,但是从外网没法连接(已实验)。

另外,创建此VPC架构的时候会在公有子网创建一个NAT实例,并会给这个NAT实例自动绑定EIP(可以连接),私有子网的实例通过此NAT连接外网,我们来看看。

我登陆我测试时的NAT实例,看了一下,也就是普通的 iptables 转发,所以NAT实例本身的配置我们可以自己搞定。
route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.0.1        0.0.0.0         UG    0      0        0 eth0
10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
169.254.169.254 0.0.0.0         255.255.255.255 UH    0      0        0 eth0

# iptables -vnL -t nat
Chain PREROUTING (policy ACCEPT 15 packets, 1081 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 7 packets, 417 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 22 packets, 2157 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
   30  2821 MASQUERADE  all  —  *      eth0    10.0.0.0/16          0.0.0.0/0

另外,在私有网络创建的实例可以通过NAT访问外网:
ping www.baidu.com
PING www.a.shifen.com (180.76.3.151) 56(84) bytes of data.
64 bytes from 180.76.3.151: icmp_seq=1 ttl=49 time=79.7 ms
64 bytes from 180.76.3.151: icmp_seq=2 ttl=49 time=79.5 ms

route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         10.0.1.1        0.0.0.0         UG    0      0        0 eth0

这里可以看到,私有子网里的实例的默认网关是 XXX.XXX.XXX.1 这种格式,我们不用指定为NAT实例的内网IP。

最后,私有子网的路由表的默认路由会指向此NAT实例(i-e310e3c8),如图:
1111

那么参考上面,我们可以自己建立一个 VPC with Public and Private Subnets ,大概步骤如下:

1. 创建一个VPC,再创建两个子网,一个公有子网,一个私有子网(私有子网不分配公网IP,通过Modify Auto-Assign Public IP 修改。)

2. 在公有子网里创建一台NAT实例,配置iptables转发,同时把NAT实例的Change Source/Dest. Check 关掉 (此为一坑)。

3. 为私有子网创建一个Route Tables,把0.0.0.0/0 指向NAT实例的ID,比如下图。

2222

4. 在Route Tables 配置里,配置公有子网的Route Table,把它的Subnet (内网段)关联上,同时配置私有子网的Route Table,把它的Subnet (内网段) 关联上(此为另一坑,花费我很长时间排查)。

5. 在Subnet 配置里,把私有子网的Route Table 修改成 第3步添加的 Route Table

NAT实例配置正确之后,创建在私有子网中的机器就没有公网IP,而且能访问外网了。

AWS 的几个”坑”

这篇文章简单说说最近搭建 aws 基础环境遇到的几个”坑”,有兴趣的可以参考下呃。

1. 默认公网IP 在机器重启之后会变化,如果想保持固定,可以申请一个 弹性IP 与实例绑定。

2. Classic 网络里 内网IP 在重启之后是有可能变化的,VPC 则不会。

3. /etc/resolv.conf 文件里面的 nameserver 重启之后会被重置(重置成aws内部的DNS IP),如果想固定,可以修改 /etc/rc.d/rc.local

4. 用aws的AMI创建出来的实例,assign 一个新的内网IP 给实例,实例里会自动生成这个IP 的网卡配置,这个是 ec2-net-utils 包 实现的;而 如果你用 redhat 或者 centos 创建的实例,默认不装 ec2-net-utils,所以你得手动配置新的地址了,当然你也可以给 redhat  或者 centos  装上  ec2-net-utils (这个包我有,可以找我要:| )

5. 如果想在aws ec2 里面实现 可以在实例之间移动的虚拟IP,比如 两台实例A 和 B,可以先给A assign 一个新的内网IP,然后A 和 B 互相检测,假如B 发现A 挂了,可以把 之前 assign 给A 的内网IP reassign 给 B 。

    命令类似:

     /opt/aws/bin/ec2-assign-private-ip-addresses -n $ENI_ID –secondary-private-ip-address $VIP –allow-reassignment –region $REGION –aws-access-key ${aws_access_key} –aws-secret-key ${aws_secret_key}

    如果需要公网的虚拟IP,那么再创建一个弹性IP 和 这个内网IP 绑定。

6. 实例不要创建在Classic 网络里,要自己建立VPC,实例都放在VPC里,VPC 比 Classic 有几个好处(不止):

   1). 支持实例有多个私有IP

   2). 实例停止后,弹性IP会依然保持与实例的关联

   3). 实例创建的时候可以不创建公网IP

7. 如果 VPC 的子网是私有子网(创建机器不自动分配公网IP),在这个子网创建的实例即使手动分配了弹性IP 也是无效的(从外面也连不上),所以想创建能从外部连上的实例,需要在公网子网(自动分配外网IP)。

8. 建立 LB 选取子网的时候要选择「公有子网」,LB 的实例会建在 「公网子网」内,所以如果选择了私有子网会连不上。

36751CB1-44B8-42BF-803D-5C241132B71A

9. 对于建立在 VPC 的 RDS,如果想从外网访问,除了选择「公开访问」 ,对于子网组,要选择「公网子网」,因为分配的 RDS 实例在选择的子网中,如果是私有子网,从外网连不上,和 EC2 LB 的子网选择类似。

F0D0795D-59A1-4B84-86C0-14BF892E2D75