JuniperのNetwork Connect利用時に外部にアクセスする

はじめに

私の大学では学内に専用のネットワークがあり、学生が学外から安全な経路でアクセスできるようにするために、Juniper Networks社の製品を導入してVPN接続サービスを提供しています。VPNに接続する際はWeb上のログイン画面でユーザーIDとパスワードを入力、接続モードを全ての通信でVPNを経由するNetworkConnect、ログイン後のWebシステム上でのみ学内にアクセスできるWebモード(リバースプロキシ)から選択してログインする必要があります。

しかし、この2つのモードにはそれぞれ問題があり、NetworkConnectでは外部のサイトにアクセスできず、Webモードではリバースプロキシを通すため、アドレスバーのURLを書き換える必要があり、任意のアドレスに簡単に飛べません(例えばブックマークから特定の科目のページにアクセスできません)。

そこで、OpenConnectというVPN クライアントとSplit Tunnelingという技術で学内はVPNを経由、それ意外はVPNを経由しないようにし、より簡単に接続するためにOpenConnectをラップしたスクリプトを作成しました。

なお、自作したスクリプトは現時点ではMacのみをサポートしています。

使ったもの

OpenConnect

OpenConnectは初め、CiscoのAnyConnect SSL VPNをサポートするために作成されたもので、その後、Pulse Connect Secureとして知られるJuniper SSL VPNをサポートしました。ということが下記のページに書かれています。

OpenConnect VPN client.

Split Tunneling

VPN接続

f:id:lightnet328:20161230190518p:plain

VPN接続 + Split Tunneling

f:id:lightnet328:20161230190521p:plain 鍵のマークがVPN ゲート、ビルのマークが学内、Webの画面が外部のページです。 Split Tunnelingを利用するとIPを指定することで、指定したIPとそれ以外でVPN ゲートを通すか通さないかを分けることが出来ます。

これを実現するために、OpenConnectではvpncというスクリプト(以下、vpnc-script)を利用しています。 また、vpncではrouteコマンドでルーティングテーブルを書き換えることによって特定のIPのみをVPNゲートを通すようにしているようです。

実際にルーティングテーブルがどのように変わるかを確認したい場合は、

$ netstat -rn > a
$ netstat -rn > b
$ diff a b

とすると良いと思います。

手順

セットアップ

TUN/TAP

仮想ネットワークデバイスです。

$ brew cask install tuntap

OpenConnect

VPN クライアントです。

$ brew install openconnect

HomebrewでOpenConnectを入れるとvpnc-scriptも/usr/local/etc/vpnc-scriptにインストールされます。

Juniper Network Connect Client

OpenConnectの簡素なラッパーです。

$ brew install tuntap
$ brew install openconnect
$ git clone https://github.com/lightnet328/jncc ~/.jncc
$ cp ~/.jncc/jncc.config.example ~/.jncc/jncc.config
$ vim ~/.jncc/jncc.config
$ echo 'export PATH="$PATH:$HOME/jncc"' >> ~/.zshrc
$ exec $SHELL -l

bashを使ってる方は~/.zshrc~/.bashrcと読み替えて実行してください。

接続

OpenConnect

利用するVPNサーバーがJuniper VPNで、認証方式がIDとパスワードの場合、以下のコマンドでネットワーク接続することができます。

$ sudo openconnect --user myid0123 vpn.tekitou.ac.jp --juniper

ただ、これでは前述した通り、全ての通信がVPNを経由してしまいます。 VPNを経由したいIPアドレスがわかっている場合は、以下のようなスクリプトを用意し、openconnectコマンドにそのパスを渡してあげることでVPNを通るかどうか振り分けることができます。

export CISCO_SPLIT_INC=2
export CISCO_SPLIT_INC_1_ADDR=xxx.xxx.xxx.xxx
export CISCO_SPLIT_INC_1_MASK=255.255.255.255
export CISCO_SPLIT_INC_1_MASKLEN=32
export CISCO_SPLIT_INC_2_ADDR=xxx.xxx.xxx.xxx
export CISCO_SPLIT_INC_2_MASK=255.255.255.255
export CISCO_SPLIT_INC_2_MASKLEN=32
exec /usr/local/etc/vpnc-script
$ sudo openconnect --user myid0123 vpn.tekitou.ac.jp --juniper --script=(SCRIPT PATH)

マニュアルはman openconnectOpenConnect VPN client.でどうぞ。

Jniper Network Connect Client

VPNを経由したいIPアドレスが予めわかっている場合は前述の手段で困りませんが、多くの場合はわからないと思います。そこで、設定ファイルにVPNを経由したいドメインを書いておくことで自動でIPアドレスを求めるクライアントを作りました。

安直なネーミングですが、Juniper Network Connect ClientとしてGitHubに公開しています。

仕組みとしては単純で、まずOpenConnectでVPN接続し、その状態でnslookupして設定しておいたドメイン名をIPアドレスに変換し、そのIPアドレスのみをVPNに通すようにしています。

他の部分も結構簡素なので何かあればIssueを建てるなりPull Requestを送るなりしてください。

設定ファイルはjncc.configで中身は以下のようになっています(コメントは除きました)。

ID=myid0123
SERVER=vpn.tekitou.ac.jp
SPLIT_HOSTS[0]=portal.tekitou.ac.jp
SPLIT_HOSTS[1]=xxx.tekitou.ac.jp
SPLIT_HOSTS[2]=oxo.tekitou.ac.jp
VPNC_SCRIPT_FILE=/usr/local/etc/vpnc-script

接続する時は、

$ sudo jncc connect

切断する時は、

$ sudo jncc disconnect

を実行するだけです。

簡単ですね。

おわりに

ネットワークには詳しくないのですが、なんとかVPN接続の手間を減らすことが出来ました。もし、間違っている点があれば、コメントやTwitterのリプライにてお知らせいただければ幸いです。

気がつけば2016年ももうすぐ終わりですね。良いお年を。