ORNEW

DockerによるVPN隔離コンテナ

Facebook にシェア
Pocket

セキュアでシンプルなネットワークを構成するのは容易ではありません。ネットワーク周辺技術への深い知識があったとしても、様々なアプリケーション・プロセスに影響を受けるシステムを正常に保つのにはなにかと苦労するものでしょう。

先日、ネットワークに関するちょっとした悩みを解決したので、備忘録として記事にまとめておきます。

私の通う大学では外部からのネットワークアクセスの手段としてCisco Anyconnectを用いたSSL-VPNを提供しています。それを通過して研究室に置いてあるサーバーマシンへSSHでアクセスし、作業をします。大学にかぎらず、仕事でもこういうシチュエーションはよくある話ですね。

VPNへ接続すると、クライアントマシンは基本的にすべての通信をVPNを通した接続に切り替えます。VPNクライアントである間、クライアントマシンは接続したVPNのノードとして機能します。結果だけ見るならば、自宅のホームネットワークに接続した状況を仮想的に再現していると考えても大して問題ありません。

ここで問題となるのは、すべての通信が大学のネットワークを通過することにあります。正直、大学のネットワークなど信用できませんし、何より私の大学のネットワークは貧弱で、非常にけちなのです。Youtubeで動画を再生しようものならば、30分もしないうちに強制的に通信をぶった切られます。ひどい話です。こっちだって使いたくて使ってるわけではないのです。動画を流しながら作業したい。しかし、そのために仮想マシンを動かしたり、システムに手を入れるのはコストやリスクが大きすぎます。

そこで、Dockerの登場です。

コンテナ型仮想化

一口に仮想化と言っても、その技術は様々です。Dockerはコンテナ型仮想化と呼ばれており、ユーザー空間の隔離(isolation)をすることで仮想的なシステムを構築します。この隔離されたユーザー空間がコンテナです。従来の仮想化技術は主に仮想マシンを作ることで実現されているのに対し、コンテナ型仮想化は仮想マシンではありません。それ故にブート等が不要であり、高速に動作します。イメージとしては、機械(machine)のエミュレーションというより純粋な環境(system)のエミュレーションに近いでしょう。同一のマシン上で動いているため様々なオーバーヘッドをカットすることに成功しています。

Dockerコンテナは、様々なリソースを隔離します。その一つに、ネットワークがあります。Dockerはコンテナ起動時にデフォルトで仮想ブリッジを作成・経由し仮想イーサネットをコンテナと直結します。これでコンテナは独立したネットワークネームスペースを持ちます。ホストマシンのデバイスも同様にしてコンテナに割り当て(allocation)できるため、独立したネットワークをコンテナに構築することができます。

ホストとは独立したネットワークを構築し、それをSSL-VPNへ接続することでホスト環境のネットワークを維持したままVPNアクセスが可能になります。もちろん、VPNに接続しているのはあくまでもコンテナなので、作業はその中で行うか、あるいはSSHサーバーをコンテナで稼働させ、それを踏み台にしてホストのシェル上から操作するなどが考えられます。ホストからコンテナ内にアタッチする手段がdockerには備わっていますので、今回の件ではコンテナでSSHサーバーを立てるメリットはあまりありませんが、更に外側からアクセスするなどの場合は有効です。

VPN隔離コンテナ

実際に私が作成したコンテナのベースはDocker Hubに公開してあります。

https://hub.docker.com/r/ornew/vsh-cisco/

dockerの参照リポジトリをデフォルトから変えていないのなら、以下のようにすればすぐに使えます。シェルに入るため、-i-tオプションは忘れないでください。

$ docker pull ornew/vsh-cisco
$ docker run -it ornew/vsh-cisco

起動するとshにログインします。ashも使用できます。基本的にAlpineとBusyBoxのコマンドはそのまま残っているので、APKで追加のアプリケーションをインストールすることも可能です。

ログインしたら、openconnectコマンドでVPNに接続します。その後、sshでいつも通り作業をするだけです。

# openconnect -u vpnusername vpn.example.com
# ssh sshuser@255.255.255.255

簡単ですね。試しに、コンテナを起動したままホストシェルでSSHへアクセスしようとみてください。失敗するはずです。これで、VPNアクセスを隔離することができました。

このようにDockerの真骨頂はシステムの隔離にあるのではないかと思います。

APKでのトラブル

実はコンテナイメージ作成でトラブルがありました。当初、このコンテナ作成はものの数行でできてしまうような簡単なものでした。openconnectopenssh-clientがAPKで提供されていたからです。ところが、あろうことかコンテナを作成した次の日にAPKからopenconnectが消されました。

aports – testing/[multiple]: move unmaintained packages

厳密には、半年間メンテナンスが行われていないという理由でリポジトリから除外されたようです。安定版なのだから別に良いのではないかと思うのですが、ルールなのでしょう。致し方ありません。

仕方がないので、現在はソースコードから全てビルドを行っています。依存パッケージが多いし情報もないし、パッチを当てないとビルドが通らなかったりと、なにかと無駄に時間を使いました。

余談ですが、当初のイメージが圧縮状態で8MB、自前でビルドしたバージョンは7MBです。展開すると15MBで、2MBくらい小さくなりました。例えばUbuntuイメージなどを使うと、VPN越しにSSHアクセスするだけなのに、140MB近くなります。それを考えると15MBに収まったのは嬉しい限りです。やろうと思えば更に減らすこともできますが、メンテナンス用にコマンドはある程度残しておきたいので、このままにしておきます。やるとしても別イメージとしてでしょうか。

今回、Alpineには若干翻弄されましたが、やはり軽量LinuxとDockerの組み合わせは便利だと実感しました。

Dockerの利点をもっと活かした環境構築をしていきたいですね。