VOYAGE GROUP エンジニアブログ

voyagegroup_techのブログ
VOYAGE GROUPエンジニアブログです。

インフラ

Amazon VPC と仮想プライベートゲートウェイを使わずに繋いでみたかったのでやってみた

こんにちは、adingo で Fluct という広告配信まわりのインフラやってる あわいいしま (@katz_arc) です。
月間200億超のインプレッションを捌くSSP である Fluct を支えるべく、日夜頑張っております。

今回はタイトルの通り、Amazon VPC で使える仮想プライベートゲートウェイを使わずにオンプレのデータセンター (以下 IDC) と VPC の間を VPN 接続したお話です。

前提

過去には仮想プライベートゲートウェイを利用して VPN 接続を構築したこともあります。
それが何故、その VPN 接続を使わずに自前で構築しようと考えたか、そこには2つほど理由がありました。

1. ゲートウェイを作成するたびに Global IP アドレスが変更されてしまうのが困る

VPN  接続を行うために重要なパラメータとなる IP アドレスが変更されると、それに伴い IDC 側 L3 スイッチの ACL を修正する必要があります。
これは何度もやりたい (やるべき) 作業ではありません。

2. 自分で1から設定する事により AWS  のネットワーク的挙動を確認したかった

VPN 接続を行おうとすると、通常の EC2 インスタンスを利用するだけであれば知らなくても困らない設定を行う必要がでてきます。
それにより AWS 独特な挙動、特にネットワークまわりをより知ることができるかもしれないという期待がありました。

材料

今回 VPN 接続に利用するのは VyOS です。
VyOS は Vyatta という OSS なソフトウェアルータが Brocade に買収され、無償版である Vyatta Core の新規開発が終わってしまった際に無償版からフォークして生まれました。
詳細は wikipedia の VyattaVyOS の頁を見てください。

IDC 側は専用のサーバは準備せず、KVM を利用して VyOS を立ち上げました。
自分の環境では bridge インタフェースを作るにあたり、bonding インターフェース直から VLAN インタフェースへの切り替えなど、いくつかホスト側の設定変更が必要になりました。

AWS 側は Community AMIs に VyOS 1.0.4 があるのでそれを利用しています。(作業時は ami-ad590eac on apne)
Community AMI ですし、利用にあたってはご自身の責任の元でお願いします。

レシピ図

VPN 接続の構成を簡単に図で、今回は vti (仮想トンネルインタフェース) は利用していません。
IDC_VPN_AWS

手順

1. IDC 側 VyOS の準備

KVM を使っての OS インストールは本題ではないので割愛します。
設定に必要な情報はレシピの図を参考にしてください。

1つ補足すると、VyOS は debian ベースであるものの、ソフトウェアルータですのでネットワークの設定などすべて専用コマンドで設定していきます。例として、console に繋いで IP アドレス、default gateway、ssh のサービスを設定するのであれば以下のようにします。
configure
set interfaces ethernet eth0 address 172.16.100.1/24
set interfaces ethernet eth1 address 192.168.100.1/24
set system gateway-address 192.168.100.254
set service ssh listen-address 172.16.100.1
commit
save
ここから VPN の設定を入れ込んでいきます
set vpn ipsec ipsec-interfaces interface eth1
set vpn ipsec ike-group to_AWS lifetime 28800
set vpn ipsec ike-group to_AWS proposal 1 encryption aes128
set vpn ipsec ike-group to_AWS proposal 1 hash sha1
set vpn ipsec esp-group to_AWS lifetime 3600
set vpn ipsec esp-group to_AWS proposal 1 encryption aes128
set vpn ipsec esp-group to_AWS proposal 1 hash sha1
set vpn ipsec site-to-site peer 192.168.200.1 authentication mode pre-shared-secret
set vpn ipsec site-to-site peer 192.168.200.1 authentication pre-shared-secret vpnsecret
set vpn ipsec site-to-site peer 192.168.200.1 authentication id @idc01
set vpn ipsec site-to-site peer 192.168.200.1 authentication remote-id @aws01
set vpn ipsec site-to-site peer 192.168.200.1 default-esp-group to_AWS
set vpn ipsec site-to-site peer 192.168.200.1 ike-group to_AWS
set vpn ipsec site-to-site peer 192.168.200.1 local-address 192.168.100.1
set vpn ipsec site-to-site peer 192.168.200.1 tunnel 1 local prefix 172.16.100.0/24
set vpn ipsec site-to-site peer 192.168.200.1 tunnel 1 remote prefix 10.0.200.0/24
commit
save
これで IDC 側の設定は完了です

2. AWS 側 VyOS の準備


インスタンス作成にあたり幾つか注意点を
  • VPN を利用するために SecurityGroup の設定で IDC 側 VyOS からの IKE(UDP:500)/ESP(IP:50) を開放する必要があります。
  • VyOS はともかく、その先の本来接続したいサーバ (今回であれば AWS Manager) にとっては IDC 宛はプライベート IP アドレス同士での接続となるため、ルーティングテーブルをなんらかの方法で設定する必要があります。これは subnet に付与する rtb で対応します。
インスタンス起動については割愛します。IKE/ESP 以外の SG は環境に合わせて設定してください。
IDC 側プライベートアドレスへのルーティング設定は Management Console で設定できなかったため、以下の様にして設定しました。(awscli 利用)
aws ec2 create-route --route-table-id rtb-(public subnet の rtb-id) --destination-cidr-block 172.16.100.0/24 --network-interface-id eni-(VyOS インスタンスの eth0 に attach された eni-id)
上記以外は特に難しいところはありません。
configure
set interface eth0 address dhcp

set vpn ipsec ipsec-interfaces interface eth0
set vpn ipsec ike-group to_IDC lifetime  28800
set vpn ipsec ike-group to_IDC proposal 1 encryption aes128
set vpn ipsec ike-group to_IDC proposal 1 hash sha1
set vpn ipsec esp-group to_IDC lifetime  3600
set vpn ipsec esp-group to_IDC proposal 1 encryption aes128
set vpn ipsec esp-group to_IDC proposal 1 hash sha1
set vpn ipsec site-to-site peer 192.168.100.1 authentication mode pre-shared-secret
set vpn ipsec site-to-site peer 192.168.100.1 authentication pre-shared-secret vpnsecret
set vpn ipsec site-to-site peer 192.168.100.1 authentication id @aws01
set vpn ipsec site-to-site peer 192.168.100.1 authentication remote-id @idc01
set vpn ipsec site-to-site peer 192.168.100.1 default-esp-group to_IDC
set vpn ipsec site-to-site peer 192.168.100.1 ike-group to_IDC
set vpn ipsec site-to-site peer 192.168.100.1 local-address 10.0.200.1
set vpn ipsec site-to-site peer 192.168.100.1 tunnel 1 local prefix 10.0.200.0/24
set vpn ipsec site-to-site peer 192.168.100.1 tunnel 1 remote prefix  172.16.100.0/24
commit
save
これで AWS 側の設定は完了です

3. 接続確認

両方の設定が完了したので接続の確認をしてみます。

まず IPSec の接続性を確認してみます

on IDC
vyos@vyos:~$ show vpn ipsec sa
Peer ID / IP                            Local ID / IP
------------                            -------------
192.168.200.1                            192.168.100.1

    Tunnel  State  Bytes Out/In   Encrypt  Hash  NAT-T  A-Time  L-Time  Proto
    ------  -----  -------------  -------  ----  -----  ------  ------  -----
    1       up     0.0/0.0        aes128   sha1  no     3098    3600    all
on AWS
vyos@vyos:~$ show vpn ipsec sa
Peer ID / IP                            Local ID / IP
------------                            -------------
192.168.100.1                         10.0.200.1

    Tunnel  State  Bytes Out/In   Encrypt  Hash  NAT-T  A-Time  L-Time  Proto
    ------  -----  -------------  -------  ----  -----  ------  ------  -----
    1       up     1.3K/1.3K      aes128   sha1  no     449     3600    all
IDC からみた時の Peer ID/IP と AWS 側の Local ID/IP に差がある (EIP or Private IP) ことがわかります

VyOS 同士での ICMP 疎通を確認します (ping のオプション設定が通常の Linux 違います)

on IDC
vyos@vyos:~$ ping 10.0.200.1 count 5
PING 10.0.200.1 (10.0.200.1) 56(84) bytes of data.
64 bytes from 10.0.200.1: icmp_req=1 ttl=64 time=7.61 ms
64 bytes from 10.0.200.1: icmp_req=2 ttl=64 time=7.74 ms
64 bytes from 10.0.200.1: icmp_req=3 ttl=64 time=7.71 ms
64 bytes from 10.0.200.1: icmp_req=4 ttl=64 time=7.75 ms
64 bytes from 10.0.200.1: icmp_req=5 ttl=64 time=7.83 ms

--- 10.0.200.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4008ms
rtt min/avg/max/mdev = 7.611/7.731/7.834/0.071 ms
on AWS
vyos@vyos:~$ ping 172.16.100.1 count 5
PING 172.16.100.1 (172.16.10.40) 56(84) bytes of data.
64 bytes from 172.16.100.1: icmp_req=1 ttl=64 time=7.74 ms
64 bytes from 172.16.100.1: icmp_req=2 ttl=64 time=7.90 ms
64 bytes from 172.16.100.1: icmp_req=3 ttl=64 time=7.57 ms
64 bytes from 172.16.100.1: icmp_req=4 ttl=64 time=7.63 ms
64 bytes from 172.16.100.1: icmp_req=5 ttl=64 time=7.87 ms

--- 172.16.100.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 7.574/7.748/7.905/0.130 ms
ネットワーク的な疎通は問題なさそうです。
それでは本来の目的である VyOS の先にあるサーバ (インスタンス) 同士の接続を確認します
(IDC Manager には事前に 10.0.200.0/24 へのルートを 172.16.100.1 で設定してあります)
[root@IDC_Manager ~]# traceroute 10.0.200.2
traceroute to 10.0.200.2 (10.0.200.2), 30 hops max, 60 byte packets
 1  172.16.100.1 (172.16.100.1)  0.380 ms  0.492 ms  0.583 ms
 2  10.0.200.1 (10.0.200.1)  8.565 ms  8.817 ms  8.904 ms
 3  10.0.200.2 (10.0.200.2)  9.095 ms !X  9.274 ms !X  9.395 ms !X
traceroute に global ip address (今回であれば 192.168.100.x or 192.168.200.x) が出てこないことがわかります

最後に ssh です (SG の設定で 172.16.100.0/24 からの ssh を許可してあります)
[root@IDC_Manager ~]# slogin -i (aws の鍵) 10.0.200.2
[root@AWS_Manager ~]#
できました

まとめ

出来上がってしまえば一般的な LAN 間 VPN と同様な感覚で利用可能な環境ができました。

実際の利用環境では VyOS を設置した public subnet の裏に private subnet があり、その接続のために VyOS インスタンスへの ENI 追加、private subnet で利用する rtb に IDC 宛の接続設定なども行っており、環境によっては少し手間がかかることもあるかもしれません。

とは言え、VyOS を稼働させるのに必要なインスタンスもそれほどスペックは必要ありませんし、一度試してみては如何でしょうか。自分は次に VyOS のような専用 OS ではなく、汎用 Linux 上の OpenVPN での接続も試してみようと企んでいます。

お知らせ

最後にお約束となりますが、弊社には ajito という社内バーがあり、エンジニアが夜な夜な出現してビールを飲んだり技術的な話をしたりと楽しい場になっています(#ajiting といいます)。弊社エンジニアに一声掛けてくださると、無料でビールを飲みつつ歓談できるかと思います。また、勉強会の場としても提供していたりするので、アドテクに興味ある方もそれほど興味ない方もどんどんお声掛けください

アラートをXymonからチーム開発向けのめっちゃグレートなグループチャットidobataにpostする

Zucksの技術環境整備係 @bash0C7 です。

さて、我々は今のところシステム監視にXymonという統合監視ツールを使っています。基本のXymon Client連携の他、カスタムスクリプトで定期的にAWSのリソースの状態を監視したり、Fluentdからfluent-plugin-xymon経由でXymonにメトリクスを取り込んだりという手を加えながら、より高いサービスレベルの達成に力を注いでいます。

Zucks Ad NetworkではXymonが問題を感知したときの通知として、これまでは伝統的なメール発報を行ってきました。利用実績の多さに加え、最近だと携帯にプッシュを受けれたり、ルールに基いてメールを転送したり、フィルタリングしたりと、伝統的とはいえまだまだ使い手のある手段ではあります。
ただ、21世紀の今日、もっとカジュアルかつ即時性が高く、送られてきた通知を契機に迅速かつスムーズにコミュニケーションが取れる手段を使いたいなあと思っていました。

そこで我々は"チーム開発にフォーカスした快適なグループチャット"idobataとXymonを組み合わせることで上記を実現しました。

Xymonからidobataに通知


idobataはグループチャットとして動作がスムーズで謳い文句の通り快適に使うことができる他、WebHook機能によってGithub、PivotalTracker、Jenkinsなど日常的に使っているポピュラーな開発支援ツールからの通知をかんたんに取り込むことができます。
Xymonからidobataの連携は、汎用のGeneric WebHookに、Xymonサーバからアクセスする方法をとっています。

下記2ステップをXymon側に設定するだけでかんたんに実現できるので、Xymonを使っている方は是非速攻でお試しください。
他の監視ツールを使っている場合も考え方は同じなのでかんたんに適用できるでしょう。 また、Fluentdにはfluent-plugin-idobataというプラグインがあるので、こちらも利用すると捗るかと思います。

■ステップ1

alerts.cfgに、条件に合致したらスクリプトをキックするように設定を追加します。
例えばいずれかのホストでCOLORがredの場合に/path/to/xymon2idobata.shをキックしてidobataに通知する場合、下記の様に記述します。
$ZGOK_IDOBATA_WEBHOOK_URL=https://idobata.io/WEBHOOK_URL

HOST=* COLOR=red
  SCRIPT /path/to/xymon2idobata.sh $ZGOK_IDOBATA_WEBHOOK_URL  
idobataのWebHook URLはidobataのルームごとにユニークなものが発行されるので、idobataのROOM SETTINGSをご覧ください。
alerts.cfgの詳細な書き方は、http://xymon.sourceforge.net/xymon/help/xymon-alerts.html#scripts をご参照ください

■ステップ2

idobataに通知するためのxymon2idobata.shを実装します。
スクリプトの中では、エラーの状況やメッセージなどが環境変数で渡されるので、それを元にhttpリクエストを作ってidobataにpostします。
#!/bin/bash

WEB_HOOK_URL=$RCPT

IDOBATA_STATUS="<span class='label label-info'>${BBCOLORLEVEL}</span>"
test ${BBCOLORLEVEL} = "red" && IDOBATA_STATUS="<span class='label label-important'>FAILURE</span>"
test ${BBCOLORLEVEL} = "yellow" && IDOBATA_STATUS="<span class='label label-warning'>WARNING</span>"

curl -s $WEB_HOOK_URL --data-urlencode "body=${IDOBATA_STATUS}<pre>${BBALPHAMSG}</pre>`echo $BBALPHAMSG | sed 's/.*See http/http/g'`" -d format=html
スクリプト中で使えるXymonの環境変数についても、http://xymon.sourceforge.net/xymon/help/xymon-alerts.html#scripts をご覧ください。
ちょっとしたハマりどころとしては、alerts.cfgで渡したrecipient情報(ステップ1では$ZGOK_IDOBATA_WEBHOOK_URL)は、コマンドライン引数ではなくRCPT環境変数に格納されます。

このスクリプトではidobata.ioでGeneric HookでFAILUREとかSUCCESSを出すを大いに参考にして、エラーレベルごとにわかりやすくidobataに表示するようにしています。
BBCOLORLEVELにredだのyellowだの、Xymonのエラーレベルのカラーが渡ってくるので、これでどのようなラベルにするか判断しています。

また、Xymonからのメッセージをpreタグで囲むようにしましたが、これだとメッセージの最後についているURLがidobata上でクリッカブルになりません。`echo $BBALPHAMSG | sed 's/.*See http/http/g'` でURL部分をpre外にも出して、idobataに送り込んでいます。


どうですか、かんたんだったでしょう?
上記スニペットはMIT Licenseとしますので、ご自由にお使いください。


また他にも様々な技術的なアーキテクチャや工夫を行っています。
PHPカンファレンス2013やad:tech Tokyo 2013 AWSブースで講演した時の資料を公開していますので、こちらも是非ご参照ください。

■PHPカンファレンス2013講演資料

■ad:tech Tokyo 2013 AWSブース講演資料

そして、VOYAGE GROUPや広告配信に興味を持ちましたら、是非こちらもご検討ください。
VOYAGE GROUP キャリア採用 広告配信システムエンジニア

記事検索
QRコード
QRコード