ovpnファイル作成用シェルスクリプト

## 背景

最近VPNを構築する機会があり、クライアント用のovpnファイルをたくさん作成するのが面倒だったのでファイル作成をなるべく自動化できるようにシェルスクリプトを作ることにした。

## 前提

- OpenVPNインストール済み
- easy-rsaをopenvpnフォルダ以下にダウンロード済み

## システム構成

![スクリーンショット 2022-04-17 15.37.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1521871/02833804-1fd7-8c76-6d2e-a947b7307432.png)

最終的なシステム構成は上記の図のとおり。openvpnフォルダはopenvpnインストール時に、easy-rsaフォルダ、easyrsa3フォルダおよびpki以下のフォルダはeasy-rsaインストール時に作成される。easy-rsaのコマンドはeasyrsa3フォルダ上で実行する必要があるので、今回実行するシェルスクリプトもeasyrsa3フォルダに作成する。

## プログラム

### 概要

mkovpn.shとしてeasyrsa3ディレクトリに置かれている。
```:mkovpn.sh
# サーバ証明書のパス
ca_path="/etc/openvpn/easy-rsa/easyrsa3/pki"
# クライアント用秘密鍵のパス
key_path="/etc/openvpn/easy-rsa/easyrsa3/pki/private"
# クライアント用証明書のパス
crt_path="/etc/openvpn/easy-rsa/easyrsa3/pki/issued"
# tls-auth用の静的鍵のパス
ta_path="/etc/openvpn/easy-rsa/easyrsa3/pki/"

# 引数チェック
if [ $# -ne 1 ]; then
	echo "コマンド実行には対象のユーザを引数にする必要があります。" 1>&2
	exit 1
fi

# 対象のクライアント
username=$1

# クライアント用の鍵作成
./easyrsa build-client-full $username nopass

# 作成開始
cat ovpn_header >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
<ca>
EOL

grep -A 30 'BEGIN CERTIFICATE' "$ca_path/ca.crt" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</ca>
<cert>
EOL

grep -A 30 'BEGIN CERTIFICATE' "$crt_path/$username.crt" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</cert>
<key>
EOL

cat "$key_path/$username.key" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</key>
<tls-auth>
EOL

cat "$ta_path/ta.key" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</tls-auth>
EOL
```

`./mkovpn.sh username`でコマンドが実行できる。usernameには使用するクライアントの名前などを指定するとよいと思う。
実行後、ovpn_filesディレクトリ以下にusername.ovpnが作成されるようになっている(ovpn_filesディレクトリは前もって作成しておく)。

### 必要なファイルの読み込み

```
# サーバ証明書のパス
ca_path="/etc/openvpn/easy-rsa/easyrsa3/pki"
# クライアント用秘密鍵のパス
key_path="/etc/openvpn/easy-rsa/easyrsa3/pki/private"
# クライアント用証明書のパス
crt_path="/etc/openvpn/easy-rsa/easyrsa3/pki/issued"
# tls-auth用の静的鍵のパス
ta_path="/etc/openvpn/easy-rsa/easyrsa3/pki/"
```
ovpnファイルの作成に必要な鍵の場所を指定している。鍵の作成方法などについてはここでは割愛する。

### 引数チェック

```
# 引数チェック
if [ $# -ne 1 ]; then
	echo "コマンド実行には対象のユーザを引数にする必要があります。" 1>&2
	exit 1
fi
```
コマンド実行時に引数が指定されているかを確認する。

### クライアント証明書と鍵の作成

```
# 対象のクライアント
username=$1

# クライアント用の鍵作成
./easyrsa build-client-full $username nopass
```
easy-rsaのbuild-client-fullをシェルスクリプト内で実行し、username.crtおよびusername.keyを作成する。証明書はpki/issued、秘密鍵はpki/private以下に保存される。
秘密鍵にパスワードを設定したい場合はnopassを削除しておくとよい。

### ovpnファイルの作成

```
# 作成開始
cat ovpn_header >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
<ca>
EOL

grep -A 30 'BEGIN CERTIFICATE' "$ca_path/ca.crt" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</ca>
<cert>
EOL

grep -A 30 'BEGIN CERTIFICATE' "$crt_path/$username.crt" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</cert>
<key>
EOL

cat "$key_path/$username.key" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</key>
<tls-auth>
EOL

cat "$ta_path/ta.key" >> ovpn_files/$username.ovpn
cat <<EOL >> ovpn_files/$username.ovpn
</tls-auth>
EOL
```

全てのovpnファイルに共通する部分となるovpn_headerをあらかじめ作成しておき、$username.ovpnに書き込む。以下は例。

```:ovpn_header
client
proto tcp-client
remote $domain $port
dev tun
resolv-retry infinite
nobind
auth-nocache
persist-key
persist-tun
remote-cert-tls server
tls-client
tls-version-min 1.2
key-direction 1
verb 3
tun-mtu 1500

```

`cat <<EOL >> ovpn_files/$username.ovpn`を用いて次の`EOL`まで`$username.ovpn`に書き込みを続けることで自動的にovpnファイルを作成する。また`grep -A 30 'BEGIN CERTIFICATE' "$crt_path/$username.crt"`についてはmkovpn.sh実行時に作成した`$username.crt`から'BEGIN CERTIFICATE'を探してそれ以下30行を抽出し、`$username.ovpn`に書き込んでいる。`$username.key`、`ta.key`についても同様である。

## まとめ

OpenVPNを作動させるための最低限の準備が整っていれば、名前を指定するだけでクライアント用のファイルがすぐに作れるので便利だと思う(自画自賛)。セットアップではできるだけ楽をしたい...


## 参考

こちらを改造させていただきました。ありがとうございました。

[OpenVPNの「.ovpn」ファイル作成シェル](https://qiita.com/SSMU3/items/bf82f76af9534b21da8c)