さくらVPSから自宅にVPN接続する

本日の内容はタイトル通りです。 Qiitaに投稿しようか迷ったんですが、ブログの方が残る気がするので、こっちに書こうと思います。半分、自分メモです。
まずは宅内の構成図を見ましょう。

赤線の部分が今回のVPN接続に関係する箇所です。さくらVPSに構築しているCentOS 7.7から、自宅に設置しているASA5520にVPNで接続し、宅内ネットワークに接続します。ASA5520の設定は、その説明を書くだけで膨大な文章になってしまうので、割愛します。CCNA Security程度の知識もしくはググる力があれば十分設定可能です。ASA5520は一般的にはFirewallとして認知されてると思いますが、VPN接続も可能です。
今回はさくらVPS(CentOS)の、接続用シェルスクリプトについてメモります。
ipsecやxl2tpdのインストールやCentOSの設定は済んでいる前提です。ググればインストールから設定まで出来ると思います。ただ実際に接続しようとすると、やれipsecを起動したりxl2tpdを起動したりroute addしたりする必要があって、いちいち一つずつコマンドを叩くのが手間なので、シェルスクリプト化しました。今回は備忘録として、接続・切断・接続確認用のシェルスクリプトについてメモっていきたいと思います。
追記(2019/10/26):スクリプトの一部を修正したので当記事にも反映しました。/etc/resolv.confを書き換える処理を追加しています。また、エラー判定をrcという変数に入れた後にif文でエラーの有無を判定していましたが、直接$?を見ることで判定するようにしました。

VPN接続用スクリプト(vpn_connect.sh)

#!/bin/bash

##---------------------------------------------------------
#
# 変数設定
#
##---------------------------------------------------------

script_name=`/bin/basename $0`
log_file="/var/log/vpn.log"

##---------------------------------------------------------
#
# 関数設定
#
##---------------------------------------------------------
function LOG() {
  /bin/echo -e "`date '+%Y-%m-%d_%H:%M:%S'` ${script_name}: $@" >> ${log_file}
  if [[ `/bin/echo $@ | grep "ERROR"` ]]; then
    /bin/logger -t ${script_name} $@
  fi
}

##---------------------------------------------------------
#
# メイン処理
#
##---------------------------------------------------------

# メイン処理開始宣言
LOG "[INFO] Starting VPN Connection..."
/bin/echo "[INFO] Starting VPN Connection..."

# VPN接続確認
/usr/local/src/vpn_status.sh
if [ $? -eq 0 ];then
  LOG "[INFO] VPN is already established."
  /bin/echo "[INFO] VPN is already established."
  exit 0
fi

# ipsecサービス開始
/bin/systemctl start ipsec
if [ $? -eq 1 ];then
  LOG "[ERROR] ipsec start failed."
  /bin/echo "[ERROR] ipsec start failed."
  exit 1
else
  LOG "[INFO] ipsec started."
  echo "[INFO] ipsec started."
fi

/usr/bin/sleep 1

# xl2tpdサービス開始
/bin/systemctl start xl2tpd
if [ $? -eq 1 ];then
  LOG "[ERROR] xl2tpd start failed."
  /bin/echo "[ERROR] xl2tpd start failed."
  exit 1
else
  LOG "[INFO] xl2tpd started."
  /bin/echo "[INFO] xl2tpd started."
fi

/usr/bin/sleep 1

# VPN接続フェーズ
/sbin/ipsec auto --up vpn-pine > /dev/null 2>&1
if [ $? -eq 1 ];then
  LOG "[ERROR] ipsec connect failed."
  /bin/echo "[ERROR] ipsec connect failed."
  exit 1
else
  LOG "[INFO] ipsec connect started."
  /bin/echo "[INFO] ipsec connect started."
fi

# ppp0インタフェースが存在しない場合のみ追加
/sbin/ip a | /bin/grep ppp0 > /dev/null 2>&1
if [ $? -eq 0 ]; then
  LOG "[INFO] ppp0 exists."
  /bin/echo "[INFO] ppp0 exists."
else
  LOG "[INFO] create ppp0 interface."
  /bin/echo "[INFO] create ppp0 interface."
  /bin/echo "c vpn-pine" > /var/run/xl2tpd/l2tp-control
fi

/bin/sleep 5

# VPN接続した際のローカルIPアドレスのルーティングを追加
/sbin/ip r | grep 192.168.0.0 > /dev/null 2>&1
if [ $? -eq 0 ]; then
  LOG "[INFO] route to 192.168.0.0/24 exists."
  /bin/echo -e "[INFO] route to 192.168.0.0/24 exists."
else
  LOG "[INFO] route add 192.168.0.0/24 dev ppp0."
  /bin/echo -e "[INFO] route add 192.168.0.0/24 dev ppp0."
  /sbin/ip route add 192.168.0.0/24 dev ppp0
fi

/bin/sleep 1

# DNSサーバのIPアドレスを/etc/resolv.confに追加
/usr/bin/grep '^nameserver 192.168.0.209' /etc/resolv.conf
if [ $? -ne 0 ];then
  /usr/bin/sed -i -e "2i nameserver 192.168.0.209" /etc/resolv.conf
  /usr/bin/sed -i -e "3i search pine.com" /etc/resolv.conf
  if [ $? -eq 0 ];then
    LOG "[INFO] Added DNS server to /etc/resolv.conf."
    /bin/echo -e "[INFO] Added DNS server to /etc/resolv.conf"
  fi
fi

# ルータに疎通確認することでVPN接続の確立を確認
/bin/ping -c 1 router > /dev/null 2>&1
if [ $? -eq 0 ]; then
  LOG "[INFO] VPN connected."
  /bin/echo -e "\e[1;32m [INFO] VPN connected. \e[m"
else
  LOG "[ERROR] VPN not connected."
  /bin/echo -e "\e[1;31m [ERROR] VPN not connected. \e[m"
fi

exit 0

VPN切断用スクリプト(vpn_disconnect.sh)

#!/bin/bash

##---------------------------------------------------------
#
# 変数設定
#
##---------------------------------------------------------

script_name=`/bin/basename $0`
log_file="/var/log/vpn.log"

##---------------------------------------------------------
#
# 関数設定
#
##---------------------------------------------------------
function LOG() {
  /bin/echo -e "`date '+%Y-%m-%d_%H:%M:%S'` ${script_name}: $@" >> ${log_file}
  if [[ `/bin/echo $@ | grep "ERROR"` ]]; then
    logger -t ${script_name} $@
  fi
}

##---------------------------------------------------------
#
# メイン処理
#
##---------------------------------------------------------

# メイン処理開始宣言
LOG "[INFO] Stopping VPN Connection..."
echo "[INFO] Stoopping VPN Connection..."

# 事前処理
echo "d vpn-pine" > /var/run/xl2tpd/l2tp-control

# VPN切断フェーズ
ipsec auto --down vpn-pine  > /dev/null 2>&1
if [ $? -eq 1 ];then
  LOG "[ERROR] ipsec disconnect had failed."
  echo "[ERROR] ipsec disconnect had failed."
  exit 1
else
  LOG "[INFO] ipsec disconnecting."
  echo "[INFO] ipsec disconnecting."
fi

# ipsecサービス停止
systemctl stop ipsec
if [ $? -eq 1 ];then
  LOG "[ERROR] ipsec stop failed."
  echo "[ERROR] ipsec stop failed."
  exit 1
else
  LOG "[INFO] ipsec stopped."
  echo "[INFO] ipsec stopped."
fi
sleep 1

# xl2tpdサービス停止
systemctl stop xl2tpd
if [ $? -eq 1 ];then
  LOG "[ERROR] xl2tpd stop failed."
  echo "[ERROR] xl2tpd stop failed."
  exit 1
else
  LOG "[INFO] xl2tpd stopped."
  echo "[INFO] xl2tpd stopped."
fi
sleep 1

# VPN切断
echo "d vpn-pine" > /var/run/xl2tpd/l2tp-control

# DNSサーバのIPアドレスを/etc/resolv.confから削除
/usr/bin/sed -i -e "/^nameserver 192.168.0.209$/d" /etc/resolv.conf
/usr/bin/sed -i -e "/^search pine.com$/d" /etc/resolv.conf
if [ $? -eq 0 ];then
    LOG "[INFO] Deleted DNS server from /etc/resolv.conf."
    /bin/echo -e "[INFO] Deleted DNS server from /etc/resolv.conf"
fi

# VPN切断確認
# ping -c 1 192.168.0.1 > /dev/null 2>&1
/bin/nslookup router > /dev/null 2>&1
if [ $? -ne 0 ]; then
  LOG "[INFO] VPN disconnected."
  echo -e "\e[1;32m [INFO] VPN disconnected. \e[m"
else
  LOG "[ERROR] VPN failed to disconnect."
  echo -e "\e[1;31m [ERROR] VPN failed to disconnect. \e[m"
fi

exit 0

VPN接続確認用スクリプト(vpn_status.sh)

#!/bin/bash

##---------------------------------------------------------
#
# 変数設定
#
##---------------------------------------------------------

script_name=`/bin/basename $0`
log_file="/var/log/vpn.log"
now_time=`date +%s`
l2tp_control_time=`ls -l --time-style='+%s' /var/run/xl2tpd/l2tp-control | cut -d" " -f 6`

# 時刻計算
vpn_time=`/bin/expr ${now_time} - ${l2tp_control_time}`
H=`/bin/expr ${vpn_time} / 3600`
vpn_time=`/bin/expr ${vpn_time} % 3600`
M=`/bin/expr ${vpn_time} / 60`
S=`/bin/expr ${vpn_time} % 60`

##---------------------------------------------------------
#
# 関数設定
#
##---------------------------------------------------------
function LOG() {
  /bin/echo -e "`date '+%Y-%m-%d_%H:%M:%S'` ${script_name}: $@" >> ${log_file}
  if [[ `/bin/echo $@ | grep "ERROR"` ]]; then
    /bin/logger -t ${script_name} $@
  fi
}

##---------------------------------------------------------
#
# メイン処理
#
##---------------------------------------------------------


# VPN接続確認
# ipsec auto --status > /dev/null 2>&1
/bin/ping -c 1 192.168.0.1 > /dev/null 2>&1
if [ $? -eq 0 ];then
  LOG "[INFO] VPN connected."
  /bin/echo -e "[INFO] VPN connected. (${H}:${M}:${S})"
  exit 0
else
  LOG "[INFO] VPN not connected."
  /bin/echo "[INFO] VPN not connected."
  exit 1
fi

exit 0

teratermでさくらVPSからVPN接続・自宅サーバにping・VPN切断してみる

今回はシェルスクリプトを/usr/local/src配下に格納してるのですが、Pathを通していますので、/usr/local/srcにcdしなくても実行可能です。
※ systemctlを使う都合で、root権限で実行する必要があります。

自宅にVPN接続することで何が便利なのか

  • さくらVPSを踏み台にすることで宅内環境(自宅サーバ、Windows、NASなど)に直接潜り込める。
  • さくらVPS以外にもiPhoneやMacBook AirからでもVPNで繋がるので、自宅の環境へアクセスしやすい。
  • 出先の環境で外部への接続がSSH(port 22)のみ許可されている場合、さくらVPSを踏み台としてSSH portforwardingで宅内のWindowsやNASにアクセスが可能。

余談:Cisco ASA5520の管理画面について

ASA5520の設定はコマンドラインからも可能なのですが、Cisco ASDMIDM Launcherを利用することでGUIからも設定が可能です。このランチャーの操作についてはCCNA Securityの問題で頻出するので見方や操作を覚える必要があります。(CCNA Securityの試験は2020年にCCNAとして一本化されるようなので、この画面を見ることは無くなってしまうかもしれませんが…)
画像では、VPN Sessionsの箇所で IPsec:1になっていますが、これはさくらVPSからVPN接続しているためです。