There is a limitation in the Microtik software and a workaround. These will be discussed at the end. Hopefully, Microtik will address this problem in a future software update. In the meantime, it isn't serious obstacle to using AWS VPN.
The network we created is very typical. It could be the "out of the box" default NAT private network behind a single public IP address. The existence of the NAT just makes it interesting.
The first step is to sign-up for AWS. You'll want to create a VPC, which is a prerequisite to using AWS VPN. You'll also want to launch an EC2 machine instance into your VPC so you have something that can respond to "ping" later. The free-tier micro-instance of AWS Linux does this nicely and you never really need to even login or configure it. Just launch it and note the private IP address for testing.
Create a customer gateway and VPN from the web console of AWS. You will supply the public address of your router (or one public address, if you have more than one). In the recipe that follows, I've used x.x.x.x to refer to this address. Use your own!
You also will supply a private AS-number during creation of the VPN and select dynamic routing using BGP. Static routing is another option. For BGP, select any number in the private AS range that doesn't conflict with something you already use. In the example, I selected 65222.
Once AWS has done its magic, your VPN will be "available" and attached to your customer gateway and your VPC. You will then be able to download a configuration file. Choose the generic format (unless you are configuring one of the listed and supported routers). The downloaded file will contain the specific IP-addresses, passwords, and AS-numbers for your VPN. These may differ in small way from what is outlined below. Be sure to substitute your private values for those in the example.
The AWS VPN is implemented as a pair of IPsec tunnels between their facility and your router. The purpose of using two tunnels is to keep traffic flowing during times that IPsec may be negotiating security between the endpoints. Unfortunately, Microtik's limitation partly defeats this goal, but even so, the performance of the resulting setup is quite respectable. More on the limitation and performance at the end.
Referring to the AWS configuration sheet, first assign the customer tunnel endpoints to the public interface of the router. The public address of the router should already be assigned to this interface too.
IP addresses (add):
3 169.254.249.30/30 169.254.249.28 ether1-gateway
4 169.254.249.26/30 169.254.249.24 ether1-gateway
Next, we make the default IPsec proposal correspond to AWS requirements. If you don't use these values, you are wasting your own time:
0 * name="default" auth-algorithms=sha1 enc-algorithms=aes-128-cbc lifetime=8m pfs-group=modp1024
0 ;;; AWS Tunnels
src-address=0.0.0.0/0 src-port=any dst-address=172.31.0.0/16 dst-port=any protocol=all action=encrypt level=require
ipsec-protocols=esp tunnel=yes sa-src-address=x.x.x.x sa-dst-address=205.251.233.120 proposal=default priority=0
1 src-address=169.254.249.26/32 src-port=any dst-address=169.254.249.25/32 dst-port=any protocol=all action=encrypt level=require
ipsec-protocols=esp tunnel=yes sa-src-address=x.x.x.x sa-dst-address=205.251.233.119 proposal=default priority=0
2 src-address=169.254.249.30/32 src-port=any dst-address=169.254.249.29/32 dst-port=any protocol=all action=encrypt level=require
ipsec-protocols=esp tunnel=yes sa-src-address=x.x.x.x sa-dst-address=205.251.233.120 proposal=default priority=0
3 src-address=169.254.249.25/32 src-port=any dst-address=169.254.249.26/32 dst-port=any protocol=all action=encrypt level=require
ipsec-protocols=esp tunnel=yes sa-src-address=205.251.233.119 sa-dst-address=x.x.x.x proposal=default priority=0
4 src-address=169.254.249.29/32 src-port=any dst-address=169.254.249.30/32 dst-port=any protocol=all action=encrypt level=require
ipsec-protocols=esp tunnel=yes sa-src-address=205.251.233.120 sa-dst-address=x.x.x.x proposal=default priority=0
Next, create the IPsec peers that support the Phase-1 handshake and password exchange. Be certain to use the AWS-supplied passwords and don't mix-up the pieces of tunnel #1 and tunnel #2. Use the two public IP-addresses supplied by AWS as a point of reference and keep all the parts for each tunnel together. If you mix them, it won't work.
0 ;;; AWS VPC Tunnel #2
address=205.251.233.120/32 local-address=x.x.x.x passive=no port=500 auth-method=pre-shared-key
secret="<aws-supplied secret>" generate-policy=no exchange-mode=main send-initial-contact=yes nat-traversal=no
proposal-check=obey hash-algorithm=sha1 enc-algorithm=aes-128 dh-group=modp1024 lifetime=8h lifebytes=0 dpd-interval=10s
dpd-maximum-failures=3
1 ;;; AWS VPC Tunnel #1
address=205.251.233.119/32 local-address=x.x.x.x passive=no port=500 auth-method=pre-shared-key
secret="<different aws-supplied secret>" generate-policy=no exchange-mode=main send-initial-contact=yes nat-traversal=no
proposal-check=obey hash-algorithm=sha1 enc-algorithm=aes-128 dh-group=modp1024 lifetime=8h lifebytes=0 dpd-interval=10s
dpd-maximum-failures=3
1 chain=input action=accept protocol=ipsec-esp src-address=205.251.233.119 dst-address=x.x.x.x in-interface=ether1-gateway
2 chain=input action=accept protocol=udp src-address=205.251.233.119 dst-address=x.x.x.x in-interface=ether1-gateway src-port=500
dst-port=500
3 chain=input action=accept protocol=ipsec-esp src-address=205.251.233.120 dst-address=x.x.x.x in-interface=ether1-gateway
4 chain=input action=accept protocol=udp src-address=205.251.233.120 dst-address=x.x.x.x in-interface=ether1-gateway src-port=500
dst-port=500
Next, you need a few rules so that BGP from the AWS can talk to your router:
6 chain=input action=accept protocol=tcp src-address=169.254.249.25 dst-address=169.254.249.26 dst-port=179
7 chain=input action=accept protocol=tcp src-address=169.254.249.29 dst-address=169.254.249.30 dst-port=179
23 ;;; VPC at AWS us-west-2x
chain=forward action=accept src-address=172.31.0.0/16 in-interface=ether1-gateway
24 chain=forward action=accept dst-address=172.31.0.0/16 in-interface=ether2-master-local
0 ;;; critically important to AWS connectivity that this rule be ahead of "masquerade".
chain=srcnat action=src-nat to-addresses=192.168.88.0/24 dst-address=172.31.0.0/16
The following firewall NAT filter rule is OPTIONAL and to be used only if the public address you supplied to AWS for your router is different from the public address used to masquerade your private NAT network. Don't use this unless you have two public addresses! And note the exclamation point!!!
1 chain=srcnat action=masquerade src-address=!x.x.x.x out-interface=ether1-gateway
You will need a destination nat rule to defeat any port-mapping rules that may be present in your existing dstnat chain. If none exist, this isn't needed, though it is harmless.
2 ;;; critically important to AWS connectivity that this rule be ahead of any NAT port-mapping
chain=dstnat action=accept src-address=172.31.0.0/16 in-interface=ether1-gateway
Next, you configure some BGP instances using the addresses from the AWS instructions:
1 name="vgw-1" as=65222 router-id=169.254.249.30 redistribute-connected=no redistribute-static=yes redistribute-rip=no
redistribute-ospf=no redistribute-other-bgp=no out-filter="" client-to-client-reflection=no ignore-as-path-len=no routing-table=""
2 name="vgw-2" as=65222 router-id=169.254.249.26 redistribute-connected=no redistribute-static=yes redistribute-rip=no
redistribute-ospf=no redistribute-other-bgp=no out-filter="" client-to-client-reflection=no ignore-as-path-len=no routing-table=""
Next, you define some BGP peers so that your BGP knows where to find AWS. The normal periodic behavior of BGP in connection with these peers will startup IPsec because of the handshake going to the far-end tunnel endpoint.
0 E name="awsvpc1" instance=vgw-1 remote-address=169.254.249.29 remote-as=7224 tcp-md5-key="" nexthop-choice=default multihop=no
route-reflect=yes hold-time=30s ttl=default in-filter="" out-filter="" address-families=ip update-source=169.254.249.30
default-originate=never remove-private-as=no as-override=no passive=no use-bfd=no
1 E name="awsvpc2" instance=vgw-2 remote-address=169.254.249.25 remote-as=7224 tcp-md5-key="" nexthop-choice=default multihop=no
route-reflect=yes hold-time=30s ttl=default in-filter="" out-filter="" address-families=ip update-source=169.254.249.26
default-originate=never remove-private-as=no as-override=no passive=no use-bfd=no
Next, you define what local networks you want BGP to advertise to AWS. At minimum, this would be your local private network block. And hopefully, that isn't a 172.31.0.0/16 range network, as these conflict with the monster VPC that AWS allocates to you!
0 network=192.168.88.0/24 synchronize=yes
0 E spi=0xF1A1CB0 src-address=205.251.233.120 dst-address=207.38.19.222 auth-algorithm=sha1 enc-algorithm=aes-cbc replay=4 state=mature
auth-key="7d08d47b8dd2c46dbc0f8df62b4b899f49bb6a96" enc-key="26e38b12f243133cd8700122443cbf2f" addtime=aug/06/2014 22:20:49
expires-in=17m19s add-lifetime=16m/20m current-bytes=2045874
1 E spi=0xF7B18F0 src-address=205.251.233.119 dst-address=207.38.19.222 auth-algorithm=sha1 enc-algorithm=aes-cbc replay=4 state=mature
auth-key="fd67f15352fae6598c37fa3965ad9990a5354443" enc-key="58c5a47403cb23a77a655135a4ef3263" addtime=aug/06/2014 22:22:10
expires-in=18m40s add-lifetime=16m/20m current-bytes=1770
2 E spi=0x57469D96 src-address=x.x.x.x dst-address=205.251.233.119 auth-algorithm=sha1 enc-algorithm=aes-cbc replay=4 state=mature
auth-key="e2d031639925eb74a270c24941eb70d84b039eaa" enc-key="1dbd99b3b843d62237fe6a2da88b8a17" addtime=aug/06/2014 22:22:10
expires-in=18m40s add-lifetime=16m/20m current-bytes=1178
3 E spi=0xA099C19C src-address=x.x.x.x dst-address=205.251.233.120 auth-algorithm=sha1 enc-algorithm=aes-cbc replay=4 state=mature
auth-key="cba17dab219c1494fe32f0ec034298a2e82274ec" enc-key="1ba56b9109f72a26057cfc5ff2e04afd" addtime=aug/06/2014 22:20:49
expires-in=17m19s add-lifetime=16m/20m current-bytes=113976118
Typical IPsec Remote Peers:
0 local-address=x.x.x.x remote-address=205.251.233.119 state=established side=initiator established=2m14s
1 local-address=x.x.x.x remote-address=205.251.233.120 state=established side=initiator established=3m26s
PEER PREFIX NEXTHOP AS-PATH ORIGIN LOCAL-PREF
awsvpc1 192.168.88.0/24 169.254.249.30 igp
awsvpc2 192.168.88.0/24 169.254.249.26 igp
With working BGP, you will also see some additional dynamic routes to AWS VPC in your route table as below. Only one such route is allowed to be active at any given instant. Also note that the gateway address for these routes is the far-end address of the IPsec tunnel, indicating that all the communication is secured.
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, B - blackhole, U - unreachable, P - prohibit
# DST-ADDRESS PREF-SRC GATEWAY DISTANCE
0 A S 0.0.0.0/0 x.x.x.w 1
1 ADC 192.168.88.0/24 192.168.88.1 ether2-master-l... 0
2 ADC 169.254.249.24/30 169.254.249.26 ether1-gateway 0
3 ADC 169.254.249.28/30 169.254.249.30 ether1-gateway 0
4 ADb 172.31.0.0/16 169.254.249.25 20
5 Db 172.31.0.0/16 169.254.249.29 20
6 ADC x.x.x.v/27 x.x.x.x ether1-gateway 0
If you got this far, you probably have it working.
Don't forget that AWS VPC is a paid service. You pay by the hour for the connection. However, the cost is about US$1 per day, so you're not going to go broke experimenting! If you actually use the tunnel, this is a bargain, especially if you can make it work with a low-cost, high-performance router!
In our case, a 750GL routerboard running v6.15 will see about 50 percent peak CPU utilization (400 MHz) handling sustained encrypted traffic on a 15 megabit/sec link. The effective throughput is about 1.6 Mbyte/sec for long file transfers. Latency is typically below 50 milliseconds between a host on our private network and an instance in our VPC.
The Microtik Limitation Explained
At last, Microtik should fix their little difficulty with IPsec. The problem is, their software does not allow two IPsec policies with identical src- and dst- addresses but different sa-dst-address to be configured. If you attempt to do this, the new policy is declared "invalid" and the whole IPsec policy list becomes unstable.
Following the example above, the missing policy is:
src-address=0.0.0.0/0 src-port=any dst-address=172.31.0.0/16 dst-port=any protocol=all action=encrypt level=require
ipsec-protocols=esp tunnel=yes sa-src-address=x.x.x.x sa-dst-address=205.251.233.119 proposal=default priority=0
The presence of this policy would allow the VPN to continue to carry traffic during Phase-2 PFS negotiation periods, which AWS recommends occur every 8 minutes. For our purposes, this is overkill and we've extended the lifetime of Phase-2 a bit so the "pause to refresh" is less frequent. When it happens, the pause is a matter of milliseconds, but even this can be a lot on a fast link or supporting streaming traffic.
It's pretty clear that if you examine the routing table above, only one tunnel is ever actually carrying traffic between your router and AWS. But when Phase-2 timer fires and the active tunnel stops working briefly, the switch to the idle tunnel should be nearly instantaneous and only initiated by the end seeking to transmit (without end-to-end negotiation). The IPsec policy selection employed by Microtik seems to prevent this.
Having said all this the performance of the VPN is not affected, except during the Phase-2 handshake, which is very brief.