Chromebook から OpenVPN（TLS-Auth、LZO圧縮有り）へ接続してみた

#はじめに
Chromebook には OpenVPN にも対応したVPN 機能がデフォルトで搭載されており、別途アプリケーションをインストールすることなく GUI で設定可能です。
ただ、GUI で設定する場合は次のような制約がありますので、企業で導入している OpenVPN サーバ等への接続には難があります。

- 対応プロトコルは UDP のみ
- OpenVPN の接続先ポートは、1194（OpenVPN でのデフォルトポート）のみ
- TLS-Auth 利用不可
- LZO 圧縮の利用不可
- クライアント証明書での認証もできるが、パスワード認証も併用する必要あり

そこで、本投稿では「Open Network COnfiguration（ONC）」という設定ファイルを利用し、これら制約を回避する設定方法をまとめます。

#Open Network Configuration とは
元々 Chromium プロジェクトの一部として Google 社において開発されたもので、JSON ベースの形式でネットワーク構成を細かく設定することができます。
一般的に、その JSON が記述されたファイルは「ONCファイル」とも呼ばれます。

尚、Open Network Configuration の仕様は、[こちら](https://chromium.googlesource.com/chromium/src/+/master/components/onc/docs/onc_spec.md)で公開されています。

#個人情報交換（PKCS#12）ファイルの作成
OpenVPN でのクライアント証明書の発行に `easyrsa` を利用している場合、証明書（.crt）と秘密鍵（.key）がペアで発行されます。
その .crt ファイルと .key ファイルを元に PKCS#12 フォーマットのファイル（.p12）を生成します。

```bash
$ sudo openssl pkcs12 -export -in /etc/openvpn/easyrsa3/pki/issued/<username>.crt -inkey /etc/openvpn/easyrsa3/pki/private/<username>.key -out /path/to/<username>.p12
Enter Export Password: <任意のパスワード>
Verifying - Enter Export Password: <任意のパスワード>
```

また、パスワードが空でも Chromebook側でインポートすることは出来ますが、セキュリティを考慮するとパスワードを設定しておきましょう。

作成した .p12 ファイルは、Googleドライブの適当な場所に保存します。

#ONCファイルの作成
公開されている [OpenVPN on ChromeOS](https://docs.google.com/document/d/18TU22gueH5OKYHZVJ5nXuqHnk2GN6nDvfu2Hbrb4YLE/pub) の情報を元に ONC ファイル（client.onc）を作成し、Googleドライブ内の適当な場所に保存します。

```json:client.onc
{
 "Type":"UnencryptedConfiguration",
      "Certificates": [ {
      "GUID": "{<GUID#1>}",
      "Type": "Authority",
      "X509":  "<CA_CERT>"
   } ],
    "NetworkConfigurations": [ {
      "GUID": "{<GUID#2>}",
      "Name": "<VPN_NAME>",
      "Type": "VPN",
      "VPN": {
          "Type": "OpenVPN",
          "Host": "<FQDN|IPADDR>",
          "OpenVPN": {
                        "ServerCARef": "{<GUID#1>}",
                    "AuthRetry": "interact",
                    "ClientCertType": "Pattern",
                    "ClientCertPattern": {              
                          "IssuerCARef": [ "{<GUID#1>}" ]
                         },
                    "Port": <PORT>,
                    "Proto": "udp",
                    "CompLZO": "true",
                    "IgnoreDefaultRoute": true,
                    "RemoteCertTLS":"none",
                    "RemoteCertEKU": "TLS Web Server Authentication",
                    "SaveCredentials": true,
                    "ServerPollTimeout": 10,
                    "Username": "<USERNAME>",
                    "KeyDirection":"1",                                      
                    "TLSAuthContents":"<TLS_AUTH_KEY>"
                     },
         "Recommended": [ "Host" ]
             }
                               } ]
}
```

|項目|設定値|説明|
|---|---|---|
|\<GUID#1>、\<GUID#2>|それぞれ異なるUUID値|任意のUUIDをそれぞれ設定します。UUIDは[このページ](https://www.uuidgenerator.net/version4)で取得できます。（アクセスする度にランダム値表示）|
|\<CA_CERT>|CA証明書の内容|CA証明書（`ca.key`）のヘッダー行（BEGIN CERTIFICATE）、フッター行（END CERTIFICATE）を除いた内容を、改行を削除し1行で記述します。<br />`"X509": "MII ... "`|
|\<VPN_NAME>|"OpenVPN"|任意の名称を記述できます。ここで設定した名称が、Chromebook 側のVPN名として表示されます。|
|\<FQDN｜IPADDR>|"X.X.X.X"|VPNサーバのホスト名、またはIPアドレスを記述します。|
|\<PORT>|1194|VPNサーバのポート番号を記述します。ダブルクォートで括らず、そのまま数字で記述してください。|
|\<USERNAME>|任意のユーザー名|クライアント証明書作成時のユーザー名を記述します。|
|\<TLS_AUTH_KEY>|TLS認証鍵の内容|TLS認証鍵（ta.key）の、先頭のコメント（#）行を除いた内容を記述します。尚、改行は全て `\n` に変更し、1行で記述してください。<br />`"TLSAuthContents":"-----BEGIN OpenVPN Static key V1-----\n ... \n-----END OpenVPN Static key V1-----\n"`|

（設定例）

```json
{
 "Type":"UnencryptedConfiguration",
      "Certificates": [ {
      "GUID": "{eeca5398-661a-4450-9f59-be19b43c0bef}",
      "Type": "Authority",
      "X509":  "MIIXXXXXXXX ... XXXXXXXX"
   } ],
    "NetworkConfigurations": [ {
      "GUID": "{2c8106b7-de97-4841-a449-df023dfae4b5}",
      "Name": "OpenVPN",
      "Type": "VPN",
      "VPN": {
          "Type": "OpenVPN",
          "Host": "1.2.3.4",
          "OpenVPN": {
                        "ServerCARef": "{eeca5398-661a-4450-9f59-be19b43c0bef}",
                    "AuthRetry": "interact",
                    "ClientCertType": "Pattern",
                    "ClientCertPattern": {              
                          "IssuerCARef": [ "{eeca5398-661a-4450-9f59-be19b43c0bef}" ]
                         },
                    "Port": 1194,
                    "Proto": "udp",
                    "CompLZO": "true",
                    "IgnoreDefaultRoute": true,
                    "RemoteCertTLS":"none",
                    "RemoteCertEKU": "TLS Web Server Authentication",
                    "SaveCredentials": true,
                    "ServerPollTimeout": 10,
                    "Username": "testuser",
                    "KeyDirection":"1",                                      
                    "TLSAuthContents":"-----BEGIN OpenVPN Static key V1-----\n ... \n-----END OpenVPN Static key V1-----\n"
                     },
         "Recommended": [ "Host" ]
             }
                               } ]
}
```

#PKCS#12ファイルのインポート
Chromebook のブラウザを起動し、次のURLにアクセスします。
`chrome://certificate-manager`

`インポートしてバインド` をクリックします。
![Screenshot 2018-04-23 at 14.29.03.png](https://qiita-image-store.s3.amazonaws.com/0/94476/eed05ac8-7311-5318-2157-4029a661a2c5.png)


Googleドライブに保存しておいた `<ユーザー名>.p12` ファイルを選択します。
![Screenshot 2018-04-23 at 14.29.57.png](https://qiita-image-store.s3.amazonaws.com/0/94476/ebc3019f-8a5d-57f3-9569-5ccb604c7562.png)

パスワードに、PKCS#12作成時に設定したパスワードを入力します。
![Screenshot 2018-04-23 at 14.31.11.png](https://qiita-image-store.s3.amazonaws.com/0/94476/2a744318-a1e1-c718-389a-3687da048a5f.png)


ユーザーの証明書が表示されたら、インポートの完了です。
![Screenshot 2018-04-23 at 14.45.04.png](https://qiita-image-store.s3.amazonaws.com/0/94476/b3ad07ea-f289-40b5-8218-50a71f157f51.png)



#ONCファイルのインポート
Chromebook のブラウザを起動し、次のURLにアクセスします。
`chrome://net-internals/#chromeos`

`Import ONC file` にある `Choose File` ボタンをクリックします。
![Screenshot 2018-04-23 at 14.22.23.png](https://qiita-image-store.s3.amazonaws.com/0/94476/08a7e600-6171-595b-4814-c711d6ab4458.png)


Googleドライブに保存した `client.onc` ファイルを選択します。
![Screenshot 2018-04-23 at 14.24.21.png](https://qiita-image-store.s3.amazonaws.com/0/94476/24235f58-f923-1fff-1d37-7bd3b6ad16a8.png)


タスクバーの Wi-Fi マークをクリックすると、`VPN が切断されました` が新しく表示されているので、そこをクリックします。
![Screenshot 2018-04-23 at 14.25.08.png](https://qiita-image-store.s3.amazonaws.com/0/94476/5996513c-0f22-d98f-c051-2cb990c50014.png)


ONCファイルで設定したVPN名（本投稿通りであれば `OpenVPN`）が表示されているのでクリックします。
![Screenshot 2018-04-23 at 14.26.37.png](https://qiita-image-store.s3.amazonaws.com/0/94476/dd7a364f-d2ce-de70-4f41-78a3197052dd.png)


`パスワード` にクライアント証明書（.crt）を作成した際に設定したパスワードを入力し `接続` ボタンをクリックします。
もしクライアント証明書にパスワードが設定されていない場合は、適当な文字列を入力してください。（空欄は不可です）
![Screenshot 2018-04-23 at 14.27.08.png](https://qiita-image-store.s3.amazonaws.com/0/94476/3be2368b-df4d-3ec9-f039-6c8f4a2f669d.png)


問題なければ `<VPN名> に接続しました` と表示されます。（接続完了まで数秒程度を要します）
![Screenshot 2018-04-23 at 14.46.58.png](https://qiita-image-store.s3.amazonaws.com/0/94476/dea4c96c-8b6b-456a-0ee5-505c8e8ed6f5.png)


#Tips
ブラウザから `chrome://net-internals/#dns` にアクセスすると、現在設定されているDNSサーバのアドレスや、DNSサフィックス等の情報を確認することができます。 
![Screenshot 2018-04-23 at 17.26.52.png](https://qiita-image-store.s3.amazonaws.com/0/94476/c4287ec5-ccd6-5c16-91d8-e64b279b9eec.png)

また、DHCP オプションとして DNS サフィックスを Chromebook に広報したい場合、OpenVPN サーバ側の設定ファイル（server.conf）で次のように `DOMAIN-SEARCH` オプションを設定する必要があります。

```
push "dhcp-option DOMAIN-SEARCH example1.com"
push "dhcp-option DOMAIN-SEARCH example2.com"
```

#参考
https://chromium.googlesource.com/chromium/src/+/master/components/onc/docs/onc_spec.md
https://docs.google.com/document/d/18TU22gueH5OKYHZVJ5nXuqHnk2GN6nDvfu2Hbrb4YLE/pub
https://docs.google.com/document/d/17DMcg0JLDSkrlD5jqhvnVbnzPx5vxCG0vjjSA8mPx70/edit