ブログ

ryuzeeによるブログ記事。不定期更新

OpenVPN ServerをAmazon EC2上に簡単に構築する方法

Amazon Virtual Private Cloud(VPC)を使ってPrivate Subnetを作っている場合、Private SUbnetにあるインスタンスを触るために一端Public Subnetの踏み台にログインしてから作業するとかは面倒すぎて無理なので、OpenVPNを使ったVPN環境を用意するのがよくある手です。 OpenVPN Server自体のインストールはそんなに大変ではありませんが、手でやると間違えるので、Chef Soloを使ってサクっと作る方法を紹介します。

インストール対象のインスタンスの用意

まずOpenVPN Serverをインストールするインスタンスを用意します。既にNATインスタンスを利用している場合はそれ上にインストールをするのが簡単です。 別で用意する場合は、NATインスタンス作成用のAMIを利用します(他のAMIでももちろん大丈夫です。いざというときのために、NATインスタンスのバックアップ用途として作っておくと良いかもしれないという程度です) nat

インスタンスを起動する際は、Public Subnet上に起動してElastic IPを割り当てます。 またインスタンスを右クリックして、Change Source / Dest Check で、チェックを無効にしてください。

srcdest

Cookbookの用意

OpenVPN ServerのインストールにはOpscodeのcookbookを利用します。 そのまま使っても良いのですが、設定内容が多いので、ラッパーのCookbookを作ると良いでしょう。
knife cookbook create openvpn-wrapper -o .
cd openvpn-wrapper
berks init

これでCookbookのひな形とBerkShelf用のひな形が作成されます。

次にrecipeやattributeの準備をします。 まずrecipeは以下のようにします。CentOSなどの場合はepel経由でOpenVPNのパッケージを取得するために、OpescodeのyumのCookbookを使います。Amazon Linuxの場合は、標準レポジトリにOpenVPNが含まれているので不要です。 また、iptablesでNATの設定をしています。

iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.0.0 -o eth0 -j MASQUERADE

こうすることで、10.8.のアドレスが振られたVPNクライアントからのアクセスがeth0経由で外に出れます。

recipes/default.rb

case node[:platform]
when "redhat", "centos", "fedora"
  include_recipe 'yum::epel'
end
include_recipe "openvpn::default"
include_recipe "openvpn::users"

case node[:platform]
when "redhat", "centos", "fedora", "amazon"
  execute "iptables -t nat -A POSTROUTING -s #{node["openvpn"]["subnet"]}/#{node["openvpn"]["netmask"]} -o eth0 -j MASQUERADE" do
    action :run
  end

  execute "/etc/rc.d/init.d/iptables save" do
    action :run
  end
end

次にmetadata.rbです。依存関係があるので、末尾に以下の2行を追加します。

depends          'yum'
depends          'openvpn'

次にattributes/default.rbです。もともとのOpenVPNのCookbookで設定されている値を上書きするように自分で値を書き換えます。OpenVPN Serverに接続する際のエンドポイントは、上記で作成したインスタンスに振っているEIPもしくはドメイン名を振ってください。また証明書を作成する際の各値(末尾の方)も自分の値に変えます。 下記の例では、OpenVPNはTCPの1194番ポートで稼働するようになっているので、このインスタンスのセキュリティグループの設定で、TCPの1194を許可するようにしてください。ポートは変えても構いませんし、UDPを使うことも可能です。

# Listen IP
default["openvpn"]["local"]   = "0.0.0.0"
default["openvpn"]["proto"]   = "tcp"
default["openvpn"]["port"]    = "1194"
default["openvpn"]["type"]    = "server"
default["openvpn"]["subnet"]  = "10.8.0.0"
default["openvpn"]["netmask"] = "255.255.0.0"
# Endpoint
default["openvpn"]["gateway"] = "vpn.example.com"
default["openvpn"]["log"]     = "/var/log/openvpn.log"
default["openvpn"]["key_dir"] = "/etc/openvpn/keys"
default["openvpn"]["signing_ca_key"]  = "#{node["openvpn"]["key_dir"]}/ca.key"
default["openvpn"]["signing_ca_cert"] = "#{node["openvpn"]["key_dir"]}/ca.crt"
default["openvpn"]["routes"] = [
    "push route 10.0.0.0 255.255.0.0"
]
default["openvpn"]["script_security"] = 1
default["openvpn"]["user"] = "nobody"
case platform
when "redhat", "centos", "fedora", "amazon"
  default["openvpn"]["group"] = "nobody"
else
  default["openvpn"]["group"] = "nogroup"
end
# Used by helper library to generate certificates/keys
default["openvpn"]["key"]["ca_expire"] = 3650
default["openvpn"]["key"]["expire"]    = 3650
default["openvpn"]["key"]["size"]      = 1024
default["openvpn"]["key"]["country"]   = "JP"
default["openvpn"]["key"]["province"]  = "Kanagawa"
default["openvpn"]["key"]["city"]      = "Yokohama"
default["openvpn"]["key"]["org"]       = "Ryuzee.com"
default["openvpn"]["key"]["email"]     = "ryuzee@gmail.com"

次に、Chef Soloでsearchコマンドを使うためにchef-solo-searchのライブラリを用意します。 chef-solo-searchをチェックアウトして、ライブラリを自分のCookbookのlibrariesフォルダにコピーします。

git clone https://github.com/edelight/chef-solo-search
cd chef-solo-search
cp -Rp libraries/* /your_cookbook_path/libraries/

この時点で一端githubなどのバージョン管理システムに登録しておきます。

Knife Soloの準備

Chef Soloを使ってインスタンスに対して作業するのにはKnife Soloを使うのが便利です。
gem install knife-solo --no-ri --no-rdoc

適当なディレクトリに移動して

knife solo init chef-repo

として初期化します。

Knife Soloの設定

先ほど作成したCookbookをKnife Solo経由で適用できるようにしましょう。 まず、chef-repoディレクトリの直下にBerksfileを用意します。内容は以下の通りです。 (gitレポジトリは僕の環境なので適宜自分の環境にあわせましょう)
site :opscode
cookbook 'openvpn-wrapper', git:'git://github.com/ryuzee-cookbooks/openvpn-wrapper.git'

Cookbookをberksコマンドでcookbookディレクトリにインストールします。

berks install --path=./cookbooks

こんなふうに表示されます。

Installing openvpn-wrapper (0.1.1) from git: 'git://github.com/ryuzee-cookbooks/openvpn-wrapper.git' with branch: 'master' at ref: '772c996ad468d76c1173749f2f472d600900f669'
Using yum (2.3.0)
Using openvpn (1.1.0)

これは、先ほどopenvpn-wrapperのCookbookのmetadata.rbで依存性を記述したため、依存性のあるCookbookをまとめて取ってきてくれていることを指しています。

次に、OpenVPNのユーザーを作成するために、data_bagsフォルダにusersフォルダを作成し、ユーザー用のjsonを作成します。

mkdir data_bags/users
touch data_bags/users/ryuzee.json

jsonの中身は以下のような感じです。(これも自分の環境にあわせましょう)

{
  "id": "ryuzee"
}

これで準備ができました。

Knife Soloの実行

それではKnife Soloを実行しますが、まずは、インストール対象のインスタンスにChef Soloをインストールしましょう。 インスタンスのアドレスと秘密鍵については自分の環境にあわせて設定します
knife solo prepare ec2-user@your-instance -i your_identity_file

以下のようにomnibus-installer経由でChef SoloやChef Clientがインストールされます。

Bootstrapping Chef...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6510  100  6510    0     0   7553      0 --:--:-- --:--:-- --:--:-- 35189
Downloading Chef  for el...
Installing Chef
warning: /tmp/tmp.4SBKYZB1/chef-.x86_64.rpm: Header V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY
Preparing...                ########################################### [100%]
   1:chef                   ########################################### [100%]
Thank you for installing Chef!
Generating node config 'nodes/54.249.31.93.json'…

ここでnodesディレクトリ以下にjsonファイルが作成されるので、runlistの編集をおこないます。 内容は以下のようになります。

{"run_list":["openvpn-wrapper"]}

これで準備ができたので、knife cookコマンドで実行します。

knife solo cook ec2-user@your-instance -i your_identity_file

これでOpenVPNのインストールと起動そしてクライアント側の設定ファイルの作成などが完了します。 クライアント側の設定ファイルは /etc/openvpn/keys ディレクトリに圧縮して保存されているので自分でダウンロードして設定を行えばOKです。

まとめ

上に書いている手順が長く感じられるかもしれませんが、手で毎回インストールや設定の作業をするよりもはるかに楽ですし、何度でも実行可能です。たまーに構築するのでかえって手順を忘れてしまいますし、テキストで手順書を書いていてもバージョンアップなどで手順が古くなってしまったりしていて時間を食ってしまう可能性もあります。なので定番の作業として自動化しておくと良いと思います。 OpscodeのopenvpnのCookbookを直接使わずにラッパーをかませるのはよくやる手です。コミュニティCookbookは設定項目が多いので、自分たちの利用シーンではデフォルト値が違う場合は、上書きしたattributesを用意しておく方が間違いが少ないです。 絶対ダメなのはコミュニティCookbookをフォークして内容を書き換えてしまうことです。これをやってしまうとバージョンアップに追随できなくなりCookbookのメンテナンスが破綻します。

アジャイルコーチングやトレーニングを提供しています

株式会社アトラクタでは、アジャイル開発に取り組むチーム向けのコーチングや、認定スクラムマスター研修などの各種トレーニングを提供しています。ぜひお気軽にご相談ください。

詳細はこちら