テックブログ

ovpnファイルの作成を自動化

はじめに

はじめまして、4月に入社しましたkkです。
初めてブログ当番が回ってきました。
よろしくお願いします。

以前、EC2インスタンスへの接続にVPN接続が必要な環境構築のテストに携わらせていただきました。
その際、Easy-RSAを利用したプライベート認証局でクライアント証明書を発行し、
それをもとにovpnファイル(ClientVPN接続設定ファイル)を作成するといった工程がありました。
しかしこの工程は、エンドユーザの数だけ実施しなくてはならずとても面倒に感じました…
そのため今回はシェルスクリプトを用いて上記の工程を自動化しようと思います。

想定環境

今回は以下のようなAWS環境を想定しています。

AWS Client VPNエンドポイントとエンドユーザー間でクライアント認証を実施し、特定のユーザのみアクセス可能な環境としています。

クライアント認証…クライアント側がアクセスする際にサーバがクライアントに対して行う認証方式
         認証が通った場合、クライアント側が正規のユーザであると判断する

クライアント認証を行うために、クライアント側(エンドユーザ)に設定するのがovpnファイルです。

以下想定環境の概要

・VPC内のIPでEC2に接続するために、Client VPN (クライアント証明書での相互認証) を利用
 (接続は “Client VPN for Windows” にて)

・Client VPN を利用するユーザは増減する

・クライアント証明書発行はEC2上のプライベート認証局(easy-rsa)で行う

・ルート証明書、サーバ証明書、秘密鍵(サーバ証明書)はACMにインポートし、
 秘密鍵(クライアント証明書)はClient VPN接続設定ファイルに追記の上、エンドユーザーに配布

※同じプライベート認証局でサーバ証明書とクライアント証明書を発行し、
 サーバ証明書をClient VPNエンドポイントに設定した場合(ACMにインポートした場合)、
 Client VPN接続設定ファイルをエンドユーザーに設定することでクライアント認証が可能

事前準備

今回作成したシェルスクリプトを実行する際には、事前にEasy-RSAリポジトリのクローンの取得等が
必要となります。
以下のAWSドキュメント、「相互認証」段落内の「4.サーバー証明書とキーを生成します。」まで
実行済みのものとします。
https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-authentication.html#mutual

ovpn接続設定ファイル作成 ~コマンド編~

ovpn接続設定ファイルを作成するには、以下のような手順が必要となります。

1.クライアント証明書と秘密鍵作成


※easyrsaファイルが存在するディレクトリに移動

[netassist@ip-10-0-0-11 easyrsa3]$ ./easyrsa build-client-full sample.com nopass

2.雛形ovpnファイル設置

※ovpnファイルはAWSコンソール画面「クライアント設定をダウンロード」からダウンロード可能
[netassist@ip-10-0-0-11 ~]$ vi sample.com.ovpn
ダウンロードしたovpnから、以下の部分だけ記述
client
dev tun
remote cvpn-endpoint-**********.amazonaws.com 443
remote-random-hostname
resolv-retry infinite
nobind
remote-cert-tls server
cipher AES-256-GCM
verb 3
reneg-sec 0

3.ルート証明書、クライアント証明書、秘密鍵ファイルの内容を雛型ovpnファイルに追記


ルート証明書の追記
※ovpnファイルには<>等が必要

[netassist@ip-10-0-0-11 ~]$ (echo -e "\n<ca>" ; cat /home/netassist/easy-rsa/easyrsa3/pki/ca.crt ; echo "</ca>") >> sample.com.ovpn

クライアント証明書の追記
→クライアント証明書ファイルは証明書部分のみ必要なため、その箇所のみ抽出した上で連結

[netassist@ip-10-0-0-11 ~]$ (echo -e "\n<cert>" ;   awk '/BEGIN/,/END/' /home/netassist/easy-rsa/easyrsa3/pki/issued/sample.com.crt ; echo "</cert>") >> sample.com.ovpn

秘密鍵の追記

[netassist@ip-10-0-0-11 ~]$ (echo -e "\n<key>" ; cat /home/netassist/easy-rsa/easyrsa3/pki/private/sample.com.key ; echo "</key>" ) >> sample.com.ovpn

ovpnファイル

[netassist@ip-10-0-0-11 ~]$ cat sample.com.ovpn
client
dev tun
proto udp
remote cvpn-endpoint-**********
remote-random-hostname
resolv-retry infinite
nobind
remote-cert-tls server
cipher AES-256-GCM
verb 3
reneg-sec 0

<ca>
-----BEGIN CERTIFICATE-----
MIIDSzCCAjOgAwIBAgIUT3l7YQaGcrPa6q1LdEcN7u1hpwgwDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMjIwODE5MDk0NjE2WhcNMzIw
省略
b3RJYnTDhgBHO/yGqy5Y0pUJnaAkWVWArmPn5BacVzFmQ0NXYY9Nx68ftlc/aPNB
qu3WBNNfFDVj0ceXMvHl+B8qJauRlMHSRSX0gkcfAA==
-----END CERTIFICATE-----
</ca>

<cert>
-----BEGIN CERTIFICATE-----
MIIDUzCCAjugAwIBAgIQDoAcb00kXLErt8tP8EubKTANBgkqhkiG9w0BAQsFADAW
MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTAeFw0yMjA5MDcwNjEwMzBaFw0yNDEyMTAw
省略
WJt6fO1Q+I3PssGO+X5eJf8YDKH51gjdfK3UmvWB81GWv8mdtHLZ6xJFslHAoV5I
YjAxi/edX+9owwinys989pM81en/P4fVVkESaIGR5vSDBjzxolJQ
-----END CERTIFICATE-----
</cert>

<key>
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCj3Kp2Cj53XvTH
mg57VIVhc/3gEL65JOdBblsrtsimtc7aNa/ywVycp/9eno9ogpPUVEMvAAlJJOzz
省略
QRPf4x6gJCXkgpli/zh21ZWTKHWkLc3q8v/FXnHJ+0H/Ig6aH6FTwcyPvAaQw2fo
X/W7UlsOn0ZvvkX5j0SWNdao
-----END PRIVATE KEY-----
</key>

ovpnファイルの作成には以上のような手順が必要です。
また今回は必要最低限のコマンドしか記載していませんが、
環境によっては決められたディレクトリへの移動等も必要になってくるかと思います。
次にシェルスクリプトを用いて実施します。

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

今回作成した、ovpnファイルを作成するシェルスクリプトが以下の通りです。

#!/bin/bash

#-------------------#
# variables setting #
#-------------------#

COUNT=$1
EASYRSA_DIR=/home/netassist/easy-rsa/easyrsa3
CLIENTFILE_DIR=/home/netassist/client.crt
OVPN_DIR=/home/netassist/conf
CA_FILE=/home/netassist/easy-rsa/easyrsa3/pki/ca.crt
OVPN_FILE=/home/netassist/downloaded-client-config.ovpn
FILENUM=$(ls /home/netassist/conf/ | awk -F . '{ gsub("^0*",""); print $1 }' | sort -nr | head -1)
LOG=/home/netassist/logs/`date +%Y%m%d`
ERRORLOG=/home/netassist/logs/error.`date +%Y%m%d`


#-----------------#
# parameter check #
#-----------------#

if [ $# -ne 1 ]; then
  echo -e "\e[2;31mError:invalid argument \e[m"
  exit
fi


#-------------------------#
# create ovpn-config-file #
#-------------------------#

sharp=$(printf "%.s#" {0..40})
hyphen=$(printf "%.s-" {0..25})
date=$(date +%Y\/%m\/%d\/%H\:%M)


for i in `seq $COUNT`
do
  if [ $(($FILENUM + 1)) = $(($FILENUM + $i)) ]; then
    echo "$hyphen    CREATE FILE    $hyphen"
  fi

  NUM=$(echo $(($FILENUM + i)) | xargs printf '%06d\n')
  echo -e "\n\n$sharp Number:$NUM  Date:$date $sharp" >>$LOG
  cd $EASYRSA_DIR
  echo yes | ./easyrsa build-client-full $NUM nopass >> $LOG 2>&1

  RESULT=$?
  if [ $RESULT = 0 ]; then
    echo "$sharp    END   ReturnValue:[$RESULT]    $sharp" >>$LOG
  else
    echo "$sharp    END   ReturnValue:[$RESULT]    $sharp" >>$LOG
    awk "/$NUM/,/ReturnValue:[1]/" $LOG >>$ERRORLOG
    echo "$hyphen $date $hyphen"
    echo -e "\e[2;31mError:Faild easyrsa Number:$NUM \nPlease check the $ERRORLOG \e[m"
    exit
  fi

  cp $EASYRSA_DIR/pki/issued/$NUM.crt $CLIENTFILE_DIR/$NUM.crt
  cp $EASYRSA_DIR/pki/private/$NUM.key $CLIENTFILE_DIR/$NUM.key
  cp $OVPN_FILE $OVPN_DIR/$NUM.ovpn
  {
    (echo -e "\n<ca>" ; cat $CA_FILE ; echo "</ca>")
    (echo -e "\n<cert>" ; awk '/BEGIN/,/END/' $CLIENTFILE_DIR/$NUM.crt ; echo "</cert>")
    (echo -e "\n<key>" ; cat $CLIENTFILE_DIR/$NUM.key ; echo "</key>" )
  } >>$OVPN_DIR/$NUM.ovpn
  OUTPUT=$OVPN_DIR/$NUM.ovpn
  echo "$i: $OUTPUT"
done

echo "$hyphen $date $hyphen"

尚、最初の変数定義は各自の環境に合わせる必要があります。
※「downloaded-client-config.ovpn」についてはAWSコンソール画面からインストールした、
 ovpn設定ファイルを使用

引数の指定
・引数は作成したいovpnファイルの「数」を指定します
 →設定ファイル名は自動的に連番で割り振られます。※下記実行結果参照

実行結果
正常時
 正常に処理が終了すると連番で名前の付いたファイルが作成されます。
 また実行時に画面出力される内容は、ログファイルに出力されるようになっています。
 ・ログファイルは各実行時の出力ごとに「#」を用いて見やすく表示
 ・各実行時のログの最下段には、Easy-RSAスクリプトを実行した後の返り値を表示

[netassist@ip-10-0-0-11 ~]$ sh ovpn.sh 5
--------------------------    CREATE FILE    --------------------------
1: /home/netassist/conf/000001.ovpn
2: /home/netassist/conf/000002.ovpn
3: /home/netassist/conf/000003.ovpn
4: /home/netassist/conf/000004.ovpn
5: /home/netassist/conf/000005.ovpn
-------------------------- 2022/09/30/12:05 --------------------------
[netassist@ip-10-0-0-11 ~]$ less logs/20220930
省略
###### Number:000003  Date:2022/09/30/12:04 ######
* Using SSL: openssl OpenSSL 1.1.1k  FIPS 25 Mar 2021

* Using Easy-RSA configuration: /home/netassist/easy-rsa/easyrsa3/pki/vars

Generating a RSA private key
................+++++
..........................................+++++
writing new private key to '/home/netassist/easy-rsa/easyrsa3/pki/9901b4fd/temp.4a3ca21e'
-----

Notice
------
Keypair and certificate request completed. Your files are:
req: /home/netassist/easy-rsa/easyrsa3/pki/reqs/000003.req
key: /home/netassist/easy-rsa/easyrsa3/pki/private/000003.key


You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a client certificate for 825 days:

subject=
    commonName                = 000003


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details:
Using configuration from /home/netassist/easy-rsa/easyrsa3/pki/safessl-easyrsa.cnf.init-tmp
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'000003'
Certificate is to be certified until Jan  2 12:04:09 2025 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Notice
------
Certificate created at: /home/netassist/easy-rsa/easyrsa3/pki/issued/000003.crt

######    END   ReturnValue:[0]    ######
省略

※「#」の数は実際に出力される数よりも少なくしています。

エラー時
 同じ名前のファイルが存在する等、エラーの場合には以下のような表示となります。
 また正常時と同様、実行時の画面出力の内容はログへ出力しています。
 ※エラーの場合は、通常のログとは別にエラーログにも出力されます。
 例 000009.ovpnが既に存在していた場合

[netassist@ip-10-0-0-11 ~]$ sh ovpn.sh 5
--------------------------    CREATE FILE    --------------------------
1: /home/netassist/conf/000006.ovpn
2: /home/netassist/conf/000007.ovpn
3: /home/netassist/conf/000008.ovpn
-------------------------- 2022/09/30/13:41 --------------------------
Error:Faild easyrsa Number:000009
Please check the /home/netassist/logs/error.20220930
[netassist@ip-10-0-0-11 ~]$
[netassist@ip-10-0-0-11 ~]$ cat /home/netassist/logs/error.20220930
###### Number:000009  Date:2022/09/30/13:41 ######
* Using SSL: openssl OpenSSL 1.1.1k  FIPS 25 Mar 2021

* Using Easy-RSA configuration: /home/netassist/easy-rsa/easyrsa3/pki/vars


Easy-RSA error:

Request file already exists. Aborting build to avoid overwriting this file.
If you wish to continue, please use a different name or remove the file.
Matching file found at:  /home/netassist/easy-rsa/easyrsa3/pki/reqs/000009.req


EasyRSA Version Information
Version:     ~VER~
Generated:   ~DATE~
SSL Lib:     OpenSSL 1.1.1k  FIPS 25 Mar 2021
Git Commit:  ~GITHEAD~
Source Repo: https://github.com/OpenVPN/easy-rsa
Host: dev | nix | Linux | /bin/bash | OpenSSL 1.1.1k  FIPS 25 Mar 2021
######    END   ReturnValue:[1]    ######

※「#」の数は実際に出力される数よりも少なくしています。

最後に

いかがだったでしょうか。
今回はovpnファイルの作成を自動化するシェルスクリプトを作成してみました。

ちなみにこのシェルスクリプトだけでは、実際に運用していく上では不十分かと思います。
例えば今回の場合はファイル名に連番を使用しているため、
どのファイルがどのエンドユーザと紐づいているのか判断が難しいかといった部分です。
そのため、エンドユーザ名とファイル名を紐づけた情報を記載したExcel等も必要になり、
この辺りは人力となります。
また利用が終了したユーザの管理も必要であるため、CRL等についても考える必要があります。

このように懸念点は残るものの、最低限のシェルスクリプトが作成できたので今回はよしとします。

改善案が浮かべば、改めて記事を書いてみようと思います。

以上です。ありがとうございました。

この記事をシェアする

  • facebook
  • twitter
  • hatena
  • line
URLとタイトルをコピーする

実績数30,000件!
サーバーやネットワークなど
ITインフラのことならネットアシストへ、
お気軽にご相談ください