Amazon VPC との間に確立した VPN の状態は、マネジメントコンソールから確認することができるほか、EC2 API Tools からも確認することができます。

amazonvpn

ec2-describe-vpn-connections コマンドまたは  ec2dvpn コマンド使って、リージョンと VPN ID を指定してやると以下のような出力が得られ、VPN がリンクアップしているかを確認できます。

$ ec2dvpn --region ap-northeast-1 vpn-7axxxxxx
VPNCONNECTION   vpn-7axxxxxx    available       ipsec.1 cgw-1984xxxx    vgw-d885xxxx    false
TUNNEL  27.0.1.16       UP      Thu Dec 26 09:47:46 JST 2013    1 BGP ROUTES    0
TUNNEL  27.0.1.144      UP      Thu Dec 26 09:48:54 JST 2013    1 BGP ROUTES    0

これだけでも VPN の状態を確認するのには十分なのですが、VPN の状態をコマンドの終了コードとして取得するためには以下のようなシェルスクリプトにします。引数でリージョンと VPN ID を指定します。

# !/bin/sh
#
# Make sure following environment variables are set
# 	EC2_CERT
#	EC2_PRIVATE_KEY
#	JAVA_HOME
#	PATH
#
# EXIT CODES
#	0	At least one of two tunnels is up.
#	1	All tunnels are down.
#

REGION=ap-northeast-1

while [ $# -gt 0 ];
do
	case "$1" in
		-h|--help)
			echo "usage: $0 [-h] [--region REGION] --vpn VPN"
			exit
			;;
		--region)
			shift
			REGION=$1
			;;
		--vpn)
			shift
			VPN_CONN_ID=$1
			;;
	esac
shift
done

ec2dvpn --region "${REGION}" "${VPN_CONN_ID}" | \
grep ^TUNNEL | awk -F'\t' '{print $3}' | grep -q UP 

exit $?

下記例のようにして実行します。

$ ./vpn_status.sh --region ap-northeast-1 --vpn vpn-7axxxxxx

VPN トンネルが2本ともダウンしている場合に終了コード1、1本でもアップなら終了コード0となるため、コマンドの戻り値によってシェルのプロンプトの色が変わるように設定していると、このような結果になります。画像は直前のコマンドが失敗するとプロンプトが赤くなるように設定しているため、Amazon VPC との VPN がダウンしている状態を表します。

vpn_status_sh

VPN コネクションの状態がコマンドの終了コードとなるため、下記の様に他のコマンドと組み合わせて応用することができます。これは VPN がダウンしている場合に CD ドライブのトレイが飛び出し、アップしているとトレイが引っ込むという例です。

$ ./vpn_status.sh --region ap-northeast-1 --vpn vpn-7axxxxxx && eject -t || eject
あるいは
$ ./vpn_status.sh --region ap-northeast-1 --vpn vpn-7axxxxxx; if [ $? -eq 0 ]; then eject -t; else; eject; fi

これを cron で適当な間隔で実行すれば、一定時間ごとに VPN のコネクションを監視しダウンしていれば CD ドライブのトレイが飛び出し、復旧したら引っ込むという仕組みを作ることができます。

しかし、EC2 API Tools は Java で書かれているため、コマンド実行ごとに Java VM を起動するコストが大きく実行に時間がかかるという欠点があります。ec2dvpn コマンドを使って VPN の状態を取得を行ってみると、10回の平均で9.55秒かかっていました。そこで、EC2 API Tools を AWS の Python インターフェイスである boto に置き換えてみます。boto のインストール方法は pip など環境によって様々なので省略します。

前出のシェルスクリプトを Python で置き換えたものがこちらです。実行するには AWS のアクセスキーを取得して AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY という環境変数にそれぞれセットしておく必要があります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Make sure following environment variables are set
#       AWS_SECRET_ACCESS_KEY
#       AWS_ACCESS_KEY_ID
#
# EXIT CODES
#	0	At least one of two tunnels is up.
#	1	All tunnels are down.

import argparse
import os
import sys
import boto
import boto.vpc

parser = argparse.ArgumentParser(description='Returns Amazon VPC Hardware VPN status')
parser.add_argument('--region', default='ap-northeast-1', help='specify region')
parser.add_argument('--vpn', required=True,help='specify VPN connection ID')
args = parser.parse_args()

UP = 'UP'
DOWN = 'DOWN'

vpc = boto.vpc.connect_to_region(args.region)
vpns = vpc.get_all_vpn_connections(args.vpn)
vpn = vpns[0] # the number of vpn connections is always 1

# the number of tunnels is always 2
if vpn.tunnels[0].status == DOWN and vpn.tunnels[1].status == DOWN :
	sys.exit(1)
else :
	sys.exit(0)

実行方法は前出のシェルスクリプトと同じで、リージョンと VPN ID を引数で与えます。こちらは10回の平均実行時間は0.42秒でした。EC2 API Tools を使う場合と比べて、約22倍高速に実行できています。

$ ./vpn_status.py --region ap-northeast-1 --vpn vpn-7axxxxxx

crontab に AWS のアクセスキーを書いて、毎分チェックを行うようにすれば Amazon VPC VPN の eject 監視ソリューションの完成です。コマンドやコードはいずれも例なので、それぞれの環境に合わせて適切に設定してください。

AWS_ACCESS_KEY_ID=foo
AWS_SECRET_ACCESS_KEY=bar
PATH=/sbin:/bin:/usr/sbin:/usr/bin
* * * * * (/path/to/vpn_status.py --region ap-northeast-1 --vpn vpn-7axxxxxx; if [ $? -eq 0 ]; then eject -t; else; eject; fi)