Help us understand the problem. What is going on with this article?

LinuxからAWS Private Virtual Gateway接続してVPCへ接続

More than 3 years have passed since last update.

背景

AlibabaのIaaSであるAlibaba CloudのECSインスタンス(AWSでいうEC2,仮想サーバ)の性能自体は悪くはなさそうなので、AWSのVPCとの間にIPSec VPNによる閉域網接続したうえで使いたい。でもIPSecでVPC直結して経路交換は無理そう。そんなわけで、Linux(Alibaba cloudのinstance)をCustomer gatewayとしてVPCへ接続する方法のまとめ。NAT配下のオンプレLinuxでもほかのIaaSでも同様にいけるはず。
image

AWS側の準備

カスタマーゲートウェイの準備

CPE、今回はLinuxの情報を定義。Linuxはサポート対象外。静的ルーティングであればWndows Serverはサポート対象っぽいVPCのコンソールで操作。とりあえずBGP喋れるように、IPアドレスはNat後のグローバルIPアドレス。見た感じIPSecはNat traversalだけどMain modeのみっぽいのでグローバルアドレスが動的に変わる環境だとNGだと思われる。
image

cliならこんな感じ。

aws-cli
# cli
aws ec2 create-customer-gateway --type ipsec.1 --public-ip 47.91.xx.xx --bgp-asn 65000
# response
{
    "CustomerGateway": {
        "CustomerGatewayId": "cgw-0b7bxxxx",
        "IpAddress": "47.91.xx.xx",
        "State": "available",
        "Type": "ipsec.1",
        "BgpAsn": "65000"
    }
}

仮想プライベートゲートウエイ

次にAWS側の仮想プライベートゲートウエイを作成。
image

cliならこんなかんじ

aws-cli
# cli
aws ec2 create-vpn-gateway --type ipsec.1
# response
{
    "VpnGateway": {
        "State": "available",
        "Type": "ipsec.1",
        "VpnGatewayId": "vgw-328cxxxx",
        "VpcAttachments": []
    }
}

既存のVPCにアッタッチする
image

aws-cli
# cli
aws ec2 attach-vpn-gateway --vpn-gateway-id vgw-328cxxxx --vpc-id vpc-c9b0xxxx
# response
{
    "VpcAttachment": {
        "State": "attaching",
        "VpcId": "vpc-c9b0xxxx"
    }
}

VPN接続を作成

先ほど作成したカスタマーゲートウエイと仮想プライベートゲートウエイを使用してVPN接続を作成。
image

aws-cli
# cli
 aws ec2 create-vpn-connection --type ipsec.1 --customer-gateway-id cgw-0b7bcb0a --
# output
vpn-gateway-id vgw-328c3c33
{
    "VpnConnection": {
        "VpnConnectionId": "vpn-30a2xxxx",
        "CustomerGatewayConfiguration": "<?xml・・・ ", //XML文省略

        "State": "pending",
        "VpnGatewayId": "vgw-328cxxxx",
        "CustomerGatewayId": "cgw-0b7bxxxx"
    }
}

IPSecVPN 2本の接続情報が上のoutputの中でXMLで記載されている。

整形vpn-connection
    <vpn_connection id=\"vpn-30a2xxxx\">
        <ipsec_tunnel>
            <customer_gateway>
                <tunnel_outside_address>
                    <ip_address>47.91.xx.xx</ip_address>
                </tunnel_outside_address>
                <tunnel_inside_address>
                    <ip_address>169.254.xx.xx</ip_address>
                    <network_mask>255.255.255.252</network_mask>
                    <network_cidr>30</network_cidr>
                </tunnel_inside_address>
                <bgp>
                    <asn>65000</asn>
                    <hold_time>30</hold_time>
                </bgp>
            </customer_gateway>
            <vpn_gateway>
                <tunnel_outside_address>
                    <ip_address>52.68.xx.xx</ip_address>
                </tunnel_outside_address>
                <tunnel_inside_address>
                    <ip_address>169.254.xx.xx</ip_address>
                    <network_mask>255.255.255.252</network_mask>
                    <network_cidr>30</network_cidr>
                </tunnel_inside_address>
                <bgp>
                    <asn>10124</asn>
                    <hold_time>30</hold_time>
                </bgp>
            </vpn_gateway>
            <ike>
                <authentication_protocol>sha1</authentication_protocol>
                <encryption_protocol>aes-128-cbc</encryption_protocol>
                <lifetime>28800</lifetime>
                <perfect_forward_secrecy>group2</perfect_forward_secrecy>
                <mode>main</mode>
                <pre_shared_key>xxxxxxxxxx</pre_shared_key>
            </ike>
            <ipsec>
                <protocol>esp</protocol>
                <authentication_protocol>hmac-sha1-96</authentication_protocol>
                <encryption_protocol>aes-128-cbc</encryption_protocol>
                <lifetime>3600</lifetime>
                <perfect_forward_secrecy>group2</perfect_forward_secrecy>
                <mode>tunnel</mode>
                <clear_df_bit>true</clear_df_bit>
                <fragmentation_before_encryption>true</fragmentation_before_encryption>
                <tcp_mss_adjustment>1387</tcp_mss_adjustment>
                <dead_peer_detection>
                <interval>10</interval>
                <retries>3</retries>
                </dead_peer_detection>
            </ipsec>
        </ipsec_tunnel>
        <ipsec_tunnel>
            <customer_gateway>
                <tunnel_outside_address>
                    <ip_address>47.91.xx.xx</ip_address>
                </tunnel_outside_address>
                <tunnel_inside_address>
                    <ip_address>169.254.xx.xx</ip_address>
                    <network_mask>255.255.255.252</network_mask>
                    <network_cidr>30</network_cidr>
                </tunnel_inside_address>
                <bgp>
                    <asn>65000</asn>
                    <hold_time>30</hold_time>
                </bgp>
            </customer_gateway>
            <vpn_gateway>
                <tunnel_outside_address>
                    <ip_address>54.64.xx.xx</ip_address>
                </tunnel_outside_address>
                <tunnel_inside_address>
                    <ip_address>169.254.xx.xx</ip_address>
                    <network_mask>255.255.255.252</network_mask>
                    <network_cidr>30</network_cidr>
                </tunnel_inside_address>
                <bgp>
                    <asn>10124</asn>
                <hold_time>30</hold_time>
                </bgp>
            </vpn_gateway>
            <ike>
                <authentication_protocol>sha1</authentication_protocol>
                <encryption_protocol>aes-128-cbc</encryption_protocol>
                <lifetime>28800</lifetime>
                <perfect_forward_secrecy>group2</perfect_forward_secrecy>
                <mode>main</mode>
                <pre_shared_key>xxxxxxxxx</pre_shared_key>
            </ike>
            <ipsec>
                <protocol>esp</protocol>
                <authentication_protocol>hmac-sha1-96</authentication_protocol>
                <encryption_protocol>aes-128-cbc</encryption_protocol>
                <lifetime>3600</lifetime>
                <perfect_forward_secrecy>group2</perfect_forward_secrecy>
                <mode>tunnel</mode>
                <clear_df_bit>true</clear_df_bit>
                <fragmentation_before_encryption>true</fragmentation_before_encryption>
                <tcp_mss_adjustment>1387</tcp_mss_adjustment>
                <dead_peer_detection>
                    <interval>10</interval>
                    <retries>3</retries>
                </dead_peer_detection>
            </ipsec>
        </ipsec_tunnel>
    </vpn_connection>

少なくとも変動値はひかえておく。

  • カスタマーゲートウエイ
    • IPsec外側のアドレス(自分のプライベートアドレス)
    • IPsec内側のアドレス(VPCから払い出し)
    • ASN(自分で指定)
  • 仮想プライベートゲートウエイ
    • IPsec外側のアドレス(VPCから払い出し)
    • IPsec内側のアドレス(VPCから払い出し)
    • ASN(10124固定?)
  • IKE
    • pre-shared key

WebUIから確認する方法は、VPN接続>設定のダウンロードでConfigurationの読めるタイプの機器の設定をダウンロードして分析する以外にないのかな?

ルート伝播

最後にルーティングテーブルで仮想プライベートゲートウエイからのルート伝播をオンに。これをしないと受け取ったPrefixがVPC側のルーティングテーブルに反映されない。
image

aws-cli
aws ec2 enable-vgw-route-propagation --route-table-id rtb-1836xxxx --gateway-id vgw-328cxxxx

memo

業務用途ならたいした金額ではないけど、個人的に遊ぶらなVPN接続が有効な間ずっと課金され続けるから、使う時だけ作成して対向のIPSec接続を抜くようにScript作っておくのがいいかも。そんなわけでcli大事。

ubuntu側準備

IPSec設定

必要なパッケージインストール
apt-get install ipsec-tools racoon quagga

特定のトラフィックをIPsecトンネルの中へ。トンネルはLinuxのNAT前のプライベートIPと接続先のVPC仮想プライベートゲートウエイのグローバルIPアドレスのペアで指定。当然両端のプライベートアドレス空間だけでなく、IPSecの内側のアドレスも暗号化する必要あり。

/etc/ipsec-tools.conf
#!/usr/sbin/setkey -f
flush;
spdflush;

# Tunnel1
spdadd 169.254.xx.xx/30 169.254.xx.xx/30 any -P out ipsec esp/tunnel/172.24.x.x-52.68.xx.xx/require;
spdadd 169.254.xx.xx/30 169.254.xx.xx/30 any -P in  ipsec esp/tunnel/52.68.xx.xx-172.24.x.x/require;
spdadd 169.254.xx.xx/30 172.31.0.0/16    any -P out ipsec esp/tunnel/172.24.x.x-52.68.xx.xx/require;
spdadd 172.31.0.0/16 169.254.xx.xx/30    any -P in  ipsec esp/tunnel/52.68.xx.xx-172.24.0.1/require;
spdadd 172.24.0.0/16 172.31.0.0/16    any -P out ipsec esp/tunnel/172.24.x.x-52.68.xx.xx/require;
spdadd 172.31.0.0/16 172.24.0.0/16    any -P in  ipsec esp/tunnel/52.68.xx.xx-172.24.0.1/require;

# Tunnel2 残念ながら2本目のトンネルは意味がないことが判明
#spdadd 169.254.xx.xx/30 169.254.xx.xx/30 any -P out ipsec esp/tunnel/172.24.0.1-54.64.xx.xx/require;
#spdadd 169.254.xx.xx/30 169.254.xx.xx/30 any -P in  ipsec esp/tunnel/54.64.xx.xx-172.24.0.1/require;
#spdadd 169.254.xx.xx/30 172.31.0.0/16    any -P out ipsec esp/tunnel/172.24.0.1-54.64.xx.xx/require;
#spdadd 172.31.0.0/16 169.254.xx.xx/30    any -P in  ipsec esp/tunnel/54.64.xx.xx-172.24.0.1/require;
#spdadd 172.24.0.0/16 172.31.0.0/16     any -P out ipsec esp/tunnel/172.24.0.1-54.64.xx.xx/require;
#spdadd 172.31.0.0/16 172.24.0.0/16     any -P in  ipsec esp/tunnel/54.64.xx.xx-172.24.0.1/require;

対向のpre-shared keyを指定

/etc/racoon/psk.txt
# 仮想プライベートゲートウエイの外側のアドレスとpre-shared keyのペア
52.68.xxx.xxx sDei_5KCLDC20CMf1tgSAbSEpeO8jVGM
# 2本目は意味がなさそう
#54.64.xxx.xxx r77N2jG.CYnvIIr836.lk2ZBxp5CMH8g

IKEフェーズ1、2の情報。

/etc/racoon/racoon.conf
path pre_shared_key "/etc/racoon/psk.txt";
path certificate "/etc/racoon/certs";

remote 52.68.xx.xx {
        exchange_mode main;
        lifetime time 28800 seconds;
        generate_policy off;
        nat_traversal force;
        exchange_mode main;
        proposal {
                encryption_algorithm aes128;
                hash_algorithm sha1;
                authentication_method pre_shared_key;
                dh_group 2;
        }
}

#remote 54.64.xx.xx {
#        exchange_mode main;
#        lifetime time 28800 seconds;
#        nat_traversal force;
#        generate_policy off;
#        exchange_mode main;
#        proposal {
#                encryption_algorithm aes128;
#                hash_algorithm sha1;
#                authentication_method pre_shared_key;
#                dh_group 2;
#       }
#}
sainfo address 169.254.xx.xx/30 any address 169.254.xx.xx/30 any {
        pfs_group 2;
        lifetime time 3600 seconds;
        encryption_algorithm aes128;
        authentication_algorithm hmac_sha1;
        compression_algorithm deflate;
}

# sainfo address 169.254.xx.xx/30 any address 169.254.xx.xx/30 any {
#        pfs_group 2;
#        lifetime time 3600 seconds;
#        encryption_algorithm aes128;
#        authentication_algorithm hmac_sha1;
#        compression_algorithm deflate;
#}

Linuxのネットワーク設定

# 経路がほしいだけでインターフェースは何でもよい。
# 実際にトンネルインターフェースとして使うわけではないのでRemoteのIPはなんでもいい
iptunnel add ipsec0 mode ipip remote xx.xx.xx.xx
# IPSec内側IPを指定
ip addr add 169.254.26.190/30  dev ipsec0
ip link set ipsec0 mtu 1427
ip link set ipsec0 up
# ルーティング有効可
echo 1 > /proc/sys/net/ipv4/ip_forward

Quagga設定

/etc/quagga/daemons
zebra=yes
bgpd=yes
/etc/quagga/zebra.conf
hostname VR1
password zebra
enable password zebra

log file /var/log/quagga/zebra.log
/etc/quagga/bgpd.conf
hostname VR1
password zebra
router bgp 65000
network 172.24.0.0/16 
 neighbor 169.254.xx.xx remote-as 10124
log file /var/log/quagga/bgpd.log

接続

service start setkey
service start racoon
service start quagga

これでquaggaでpeer上がればOK。AWSのVPCルーティングテーブルにローカルのPrefixも現れるはず。

問題

AWS側にできる仮想プライベートゲートウエイの2つのIPSec接続先アドレスを冗長化目的では利用できない。動的にSAを選べないから。BGPのPeerはあがる。でもパケット送信時に経路判断前にBGPの経路と関係なく静的なipsec-tools.confの設定によるSAの判定でどちらか一つのIP宛てのトンネルに確定される。さらに悪いことにこの宛先とBGPベストパスが不一致だと通信できない。
bgpdがVPCからもらうprefixに対してIPSecのトンネルに乗せるかどうかを判断できない。意味static routeと同じ。でもbgpdがprefixをVPCへアナウンスできる点は意味があるかも。
・・・・という若き頃通った行き止まりに再度気づかず再度到達。

未検証だけど考えられるソリューションは

  • 同じグローバルIPでNATされるubuntuサーバをもう1個立てる。冗長化目的ならこれかも
  • QUAGGAじゃなくてサポートされてるVyatta/vyosならもう少し上手にIPSecとルーティング扱えるかも
  • ちょっと複雑になるけどAWS側は仮想プライベートゲートウエイじゃなくてC社仮想ルータ使ってIPsec tunnel modeより柔軟性高いトンネル使うともう少しキレイに行くかも
makotaka
alieaters
Alibaba Cloudを上手に使うためのノウハウの共有を目的としたコミュニティ
https://www.alieaters.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away