OpenVPN + Azureでクラウド開発環境を作る

2020-02-26Azure,TIPScode-server,OpenVPN,VPN,VSCode,リモート

先日のmacOS Catalinaリリースに伴ってクリーンインストールしたついでに今更ながら開発環境をDockerに詰め込んだのですが、外部セミナーやら外に出る時はiPad Proで済ませたい気持ちもありAzure上にも開発環境を構築してみました。


開発に使用するVMはセキュリティ上、パブリック公開する訳にもいかないのでインターネットに面したPortは全て閉じます。
従ってクライアントからはVPNを介してprivateサブネット上に配置したVMにアクセスします。

AzureにはVPN Gatewayリソースが用意されていますが、最も安価なBasic SKUではP2SではトンネリングにSSTPしか対応していません。
VpnGw1 SKUからはOpenVPNやIKEv2が対応されていますが価格は約15,000円/月ほどとなり個人の開発環境として使うには勇気のいるコストです。
(Basic SKUでも約3,000円/月のコストが掛かります。)

そこでライセンス無しでも2ユーザまで無償で使えるOpenVPN Access ServerをBYOLで活用しVPN Gatewayの変わりにしました。


主な使用リソース

  • Azure VM (OpenVPN AS)
  • Azure VM (開発用)
  • Azure Vnet
  • Azure Route table

私の場合、VPN用のVMは立ち上げっぱなしですが開発機は適宜停止させるためサイズにもよりますが約3,000円/月くらいに落ち着いています。
Windowでしか接続できないBasic SKUを使用したAzure VPN Gateway構成に比べ、MacやiOSでもVPN接続が可能でかつBasic SKU単体のコストと同じというリーズナブルな金額です!

今回作成したリソースのみでの予測値

構築手順

ざっくらばんに大きく4ステップで構築していきます。

  1. OpenVPN用のサーバー作成
  2. OpenVPNの初期設定
  3. 開発用のサーバー作成
  4. Route tableの作成

それでは早速リソースを作成していきましょう。

OpenVPN Access Server の作成

Azure Portal にログインし画面左上の + リソースの作成 を押下します。
Marketplaceの検索欄に “OpenVPN” と入力し検索実行します。

OpenVPN Inc. 提供の OpenVPN Access Server を選び 作成 を押下し、それぞれのタブを設定していきます。

基本

リソースグループ: OpenVPN-Gateway
適当なリソースグループを作成するのをオススメします。

仮想マシン名: OpenVPN-VM

・リージョン: (アジア太平洋) 東日本
一番近い好きなリージョンを選択して下さい。

・イメージ: OpenVPN Access Server 2.7.5

・サイズ: Standard B1s
お好みで。一人で利用する分には Standard B1s でも大分余裕があります。

認証の種類: SSH公開キー
適宜ユーザ名と公開キーをセットして下さい。

ディスク

ディスクのオプション: Standard SSD
VPNサーバとして使用するのでディスクはほぼ必要ありません。

データ ディスク: なし

ネットワーク

仮想ネットワークを以下のように作成します。

アドレス空間: 10.1.1.0/24, 10.2.1.0/24
CIDRはご自身の環境に合わせて他のVnetと干渉しない値をセットして下さい。

サブネット: public – 10.1.1.0/24, private – 10.2.1.0/24
アドレス空間で定義したCIDRを public , private として設定してください。

publicサブネットには OpenVPN Access Server を配置し、privateサブネットには開発用VMを配置します。

パブリックIPは新規作成するか余っている物があれば適当にアタッチしてください。
セキュリティグループはOpenVPN Inc. にてデフォルトで設定されているため何も設定せずに進みます。

こだわりがなければ 管理, タグ についてはそれぞれデフォルトのままで構いません。
確認および作成 に進みデプロイします。

デプロイが完了したらリソースに移動しVMと一緒に作成されたネットワークインターフェイス(Nic)を開きます。
IP構成 ブレードに入りデプロイ時に作成された ipconfig1 を開き割り当てを 静的 に設定し保存しておきます。

続いてNSGに移動し、規定で定義されるDenyAllInboiundでVnetからのインターネット向け通信がドロップされないよう、Vnetからの受信ルールを追加します。

名前は適当で構いません

OpenVPN Access Server のセットアップ

作成したVPN用のVMにアクセスし割り当てられたパブリックIPアドレスを確認して下さい。
PIPが確認できたら早速SSHします。

$ ssh -i /path/to/id_rsa hogehoge@40.115.176.67

接続するとセットアップウィザードが立ち上がります。
まず最初に規約が表示されるので良く読み、yesを送信して同意してください。

幾つか質問が表示されるので次のように回答します。

Will this be the primary Access Server node?
$ (Enter

Please specify the network interface and IP address to be used by the Admin Web UI
$ (Enter

Please specify the port number for the Admin Web UI
$ (Enter

Please specify the TCP port number for the OpenVPN Daemon
$ (Enter

Should client traffic be routed by default through the VPN?
$ No

Should client DNS traffic be routed by default through the VPN?
$ (Enter

Use local authentication via internal DB?
$ yes

Should private subnets be accessible to clients by default?
$ (Enter

Do you wish to login to the Admin UI as “openvpn”?
お好みで。noと返しデフォルトユーザを変更することをお勧めします。
この場合、ウィザードが開始され代替ユーザ名とパスワードと設定できます。

Please specify your OpenVPN-AS license key (or leave blank to specify later)
仮にライセンスをお持ちでも現段階ではEnterでOKです。
検証完了後に管理画面からライセンスの登録が可能です。
尚、2ユーザまでは無償使用が可能です。

openvpnユーザのパスワードを設定する

もしデフォルトユーザを変更していない場合はsudo passwd openvpn を送信し任意のパスワードを設定してください。

デフォルトユーザから変更しユーザ名とパスワードと定義しているのであればこの工程は不要です。

タイムゾーンの変更

以下のコマンドを実行しタイムゾーンを変更します。
sudo dpkg-reconfigure tzdata

時刻自動同期を有効にする

以下のコマンドを実行し時刻を自動で同期してくれるNTPを導入します。

sudo apt install ntp

IPマスカレードを有効にする

この設定はVMを再起動すると初期化されてしまうため、サービス登録してスタートアップスクリプトにすることをお勧めします。

まずルート権限でスクリプトを用意します。

$ sudo vim /etc/onboot.sh

onboot.sh

#! /bin/bash

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

次に作成したスクリプトを実行出来るように権限設定を行ってからサービスを定義します

$ sudo chmod 777 /etc/onboot.sh
$ sudo vim /etc/systemd/system/onboot.service

onboot.service

[Unit]                                        
Description = hello daemon                    
                                              
[Service]                                     
ExecStart = /etc/onboot.sh                    
Restart = always                              
Type = simple                                 
                                              
[Install]                                     
WantedBy = multi-user.target  

最後にこのserviceを有効にし開始させましょう。

$ sudo systemctl enable onboot
$ sudo systemctl start onboot

有効になっているかは以下のコマンドで確認できます。

$ sudo systemctl list-unit-files --type=service | grep onboot

onboot.service                                        enabled  

管理画面にログインする

管理画面へはWeb ブラウザからアクセスできます。

作成したOpenVPN用のVMに紐づけられたパブリックIPアドレスを確認しURLを置き換え943ポートにアクセスしてください。

https://xxx.xxx.xxx.xxx:943/admin/
  1. 現時点では自己証明書を用いているためSSL 警告が表示されますが無視して先に進んでください。Chromeを使用している場合は証明書をインポートする必要があります。
  2. openvpn もしくは 定義したデフォルトユーザのID/PWに入力しログインします。
  3. 規約が表示されるのでよく読み、同意します。

ネットワーク設定

OpenVPN ASはデフォルトの状態でホスト名にVMの内部IPアドレスが割り振られているため、これをパブリックIPアドレスもしくはDNSラベルに変更をします。

画面左のメニューから Configuration > Network Settings を選択してください。
VPN Server 項目にある Hostname or IP Address: の部分にVMのIPアドレスもしくはDNSラベルを設定します。
静的パブリックIPアドレスに設定している場合はIPアドレスでの設定で問題ありませんが、動的にしている場合インスタンスを停止させるとIPアドレスが変更されてしまうためDNSラベルを設定する必要があります。

入力後、画面最下部にある Save Settings 、画面最上部に現れるUpdate Running Server の順にクリックしサーバに変更を反映させます。

続いてprivateサブネットのCIDRを設定します。
画面左のメニューからConfiguration > VPN Settings へ進みます。
デフォルトではRouting 項目にpublicサブネットに紐づけたCIDRが入力されているはずです。
ここにprivateサブネットで紐づけたCIDRを追記します。

入力後、先程同様に画面最下部にある Save Settings 、画面最上部に現れるUpdate Running Server の順にクリックしサーバに変更を反映させます。

これで管理画面側の設定は完了です。

クライアント構成ファイルの入手

続いて/adminを外したURLにアクセスします。

https://xxx.xxx.xxx.xxx:943/

するとクライアントの入手画面が表示されます。
セッションが切れログインを求められた場合はログイン後にこの画面に推移します。
お使いの端末に合わせたOpenVPNクライアントを入手して下さい。

画面下部には.ovpn 形式のProfileもありますのでTunnelblick など使い慣れたクライアントアプリも引き続き使用可能です。

続いて開発用サーバを作ります。
一度接続を終了しAzure Portalに戻りましょう。

開発用VMの作成

開発に使用するVMを作成していきます。

+ リソースの追加 からお好みのOSを検索しリソースを作成して下さい。

共通

リージョン: アジア太平洋 東日本
VPNサーバを配置したリージョンと同じ地域を選択してください。

ネットワーク

Vnet: OpenVPN AS用に作成したVnet

サブネット: privateサブネット

パブリックIPアドレス: なし
開発用VMは外部に公開しないため紐付けの必要はありません。

リソース作成後、デプロイされたNICに移動しIP構成ブレードからローカルIPアドレスを静的に設定しておきます。

この画像では途中で一度 Vnet を変更したため、Vnetの名称やIPアドレスが上述した工程で作成したものと異なっているので注意

Route tableの作成

次にOpenVPN経由でprivateサブネットへ配置した、PIP無しの開発用VMにアクセス可能とするためRoute tableを定義する必要があります。

+ リソースの追加 からRoute tableと入力し検索を行いリソースを作成して下さい。

ルートの定義

作成したRoute tableに移動しルートブレードを開き追加をクリックします。
ルート名: proxy
適当な名前を設定します

アドレス プレフィックス: 0.0.0.0/0

次ホップの種類: 仮想アプライアンス

次ホップ アドレス: 10.2.1.4
ここには開発用VMのプライベートIPアドレスを入力します

サブネットの紐付け

次に作成したルートを適用させるサブネットに関連付けを行います。
サブネットブレードを開き + 関連付け から仮想ネットワークとprivateサブネット選択しOKを押下し反映させます。

開発サーバへSSHで接続

最後に作成した開発サーバへSSHで接続してみましょう。
パブリックIPアドレスは紐づいていないため、接続情報にはプライベートIPアドレスを使用します。

configファイルに接続情報を追記

Host AzureUbuntu
  HostName 10.2.1.5
  User hogehoge
  IdentityFile ~/.ssh/id_rsa

追記したHost名を使用して接続します

$ ssh AzureUbuntu                                                      [~/.ssh]
Enter passphrase for key '~/.ssh/id_rsa': 
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 5.0.0-1022-azure x86_64)
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
...
Last login: Mon Oct 21 17:41:59 2019 from 10.2.1.5
hogehoge@devUbuntuVM:~$ 

無事に接続できました!
あとは開発サーバに好きなものを入れて事由に構成すればクラウドライフの始まりです!


VSCodeとcode-serverの使用

ベテランVimmerの方には必要ないかもしれませんがクラウド上でもIDEを使用したくなるケースはあると思います。
今回はVSCodeと、VSCodeをオンライン上で実行するOSSであるcode-serverをセットアップしてみます。

VSCode でリモート開発

公式から提供されている拡張機能であるRemote Developmentを使用します。
これはSSH, Docker container, WSL への接続をサポートしており簡単にリモート開発を開始することが可能になります。

まずは拡張機能を検索しインストールしましょう。

SSH接続に関しては、 ~/.ssh/config に接続情報を記述して置くと自動で読み込んでくれます。
今回作成した環境への接続情報を管理しておきましょう。

Host AzureUbuntu
  HostName 10.2.0.5
  User hogehoge
  IdentityFile ~/.ssh/id_rsa

上記形式に合わせ、ご自身の環境における接続情報を記入してください。
configファイルに定義を追加するとVSCode上からHostネームが確認できるようになるので接続したい接続を選択するだけでOKです。

パスフレーズへの回答を済ませるといつものVSCode画面でリモート先の作業が開始できるようになっています!

code-serverでリモート開発

今度はVSCodeをサーバ側で実行させてブラウザから利用できるようにしてみましょう。
この方式だとクライアントにVSCodeが入っている必要性はなく、ブラウザさえ使えれば開発可能となりますのでiPadやChromebookなど携帯性が高い端末でネットさえ繋がっていればOKという環境にできます。

code-serverはdockerイメージも公開されていますが、クラウド上で構築する際はバイナリ形式をオススメします。
以下のコマンドを実行してください。

$ mkdir ~/coder && cd c~/coder
$ wget https://github.com/cdr/code-server/releases/download/2.1523-vsc1.38.1/code-server2.1523-vsc1.38.1-linux-x86_64.tar.gz

$ tar xvfz code-server2.1523-vsc1.38.1-linux-x86_64.tar.gz -C ~/coder
$ mv code-server2.1523-vsc1.38.1-linux-x86_64/code-server ~/coder

次にVMの起動時に自動で立ち上がるようにサービス登録しておきましょう。
まずは以下のようにサービスを作成します。

$ vim /etc/systemd/system/coder.service
[Unit]
Description = VSCode on a browser                                         
                                                                          
[Service]                                                                 
ExecStart = /home/{USER}/coder/code-server --host "10.2.0.5" /home/{USER}/projects    
ExecStop = /sbin/start-stop-daemon --stop -x /home/{USER}/coder/code-server                                                                                    
Restart=on-failure                                                        
Type = simple                                                             
                                                                          
[Install]                                                                 
WantedBy = multi-user.target

{USER} には自身の使用しているユーザ名を代入してください。
デーモンの起動時はrootユーザで実行されるため絶対パスでの記述が推奨されています。

また、--host "10.2.0.5" の箇所はVMのプライベートIPアドレスに置き換えてください。
この指定を行わないと0.0.0.0での実行となりクライアントから利用できなくなります。

サービスを作成したら自動起動の登録し起動させましょう。

$ systemctl daemon-reload
$ systemctl enable coder.service
$ systemctl start coder.service

正常に起動しているかは以下のコマンドで確認できます。

$ systemctl status coder.service

もしここでエラーなどが吐かれている場合はサービス内で指定したパスが誤っていないか確認をしてください。
問題がなければVPNを繋いでいる状態で http://10.2.0.5:8080 をブラウザで開くと見慣れたVSCodeがひょっこり表示されます!

まとめ

色々バタついて中々更新の時間が取れませんでしたが環境の整理も終わりそろそろアップしたい記事も積み上がってきたので頑張ります。

2020-02-26Azure,TIPScode-server,OpenVPN,VPN,VSCode,リモート

Posted by Kenny