OpenVPN による VPN接続について (証明書編)


前回はOpenVPNの静的鍵(static.key)認証による”簡単”なVPN接続でしたが、今回は独自の認証局(CA:Certification Authority)で署名した証明書(server.crt, client.crt)を使ってのVPN接続になります。

一般的には、静的鍵認証よりも、こちらの証明書認証によるVPN接続の方が主流だと思いますので、間違いのないように、よく調べながら、最も簡単な方法で作業を行いました。

なお、今回の内容は、 OpenVPN.JP を参考にしていますが、そちらで説明されていた easy-rsa は使っておりません。

2021-11-12

ca.crt (ca証明書)についての修正

  • -days オプションを追加(有効期間は通常で30日)
  • 設定(openssl.cnf)に拡張機能コピーを追加

server.csr (server.crt 要求書)についての修正

  • 要求書にTLSエラー拡張機能を追加する設定変更

準備

自己認証局とサーバ、クライアントの所在を明確にするために、固定IPアドレスに*FQDNを設定しました。

FQDNは www.example.com のような完全装飾ドメインのことで、証明書の CommonName に入力する一般名のことです。

今回の構成

端末(フォルダ)用途IPアドレスFQDNVPN アドレス
Debian11 bullseye (~/myca)自己認証局192.168.10.115debi1.example.com
ubuntu 20.04(~/vpn_server)VPNサーバ192.168.10.118ubn2.example.com10.8.0.1
Altelinux (~/vpn_client) VPNクライアント192.168.10.114al3.example.com

Debian11 と Ubuntu 20.04 は別の端末ですが、同じPCのハードディスク上にあります。

端末(PC)のIPアドレスを固定(手動)へ変更

端末(PC)のIPアドレスを自動(DHCP)から固定(手動)へ変更しました。

こちらはUbuntu20.04の設定ですが、他も同じような設定方法になると思います。

「設定」→「ネットワーク」から接続済みのデバイスを選択して、「IPv4メソッド」を自動(DHCP)から手動に切り替えて、任意のアドレスとネットマスク、ゲートウェイ、DNSを入力しました。

入力を終えたら「適用」をして、インターネットが接続されているか確認しました。

各端末のIPアドレスとFQDNを /etc/hosts へ追加

認証局、サーバ、クライアント端末のIPアドレスとFQDNを /etc/hosts へ追加しました。

~$ sudo vi /etc/hosts

設定を終えたら、追加したFQDNへのping 送信で確認しました。

作業のながれ

  1. 自己認証局(CA)作成
  2. サーバ・クライアント証明書署名要求書(server.csr, client.csr)作成
  3. サーバ・クライアント証明書(server.crt, client.crt)作成
  4. OpenVPNの起動・接続
  5. 接続確認

自動化や外部(ローカルエリア外)からの接続は次回に行います。

自己認証局(CA)作成

今回は各証明書を作成するために、独自に認証局を設置する方法を選択しました。(easy-rsa を使えばこの作業は必要ありません。)

自己認証局(myca)の作成

認証局となる端末(Debian11)の openssl設定ファイル( /etc/ssl/openssl.cnf )を確認します。

~$ ls /etc/ssl/

認証局は /etc/ssl/ の下に作るのが一般的だと思いますが、今回はユーザーで自己認証局(myca)を配置しました。

~$ mkdir myca
~$ cd myca

openssl設定ファイルの編集

openssl設定ファイル(/etc/ssl/openssl.cnf)は自己認証局(myca/openssl_CA.cnf)へコピーしました。

~/myca$ sudo cp /etc/ssl/openssl.cnf ./openssl_CA.cnf

設定ファイルの所有権をrootからユーザー(debu)へ変更しました。

~/myca$ sudo chown debu:debu openssl_CA.cnf 

設定ファイルを確認します。

~/myca$ vi openssl_CA.cnf

[ CA_default ] は [ ca ]コマンドに適用されますので、実際のファイル、ディレクトリ構成は上のように配置する必要があります。

ここでは、[カレントディレクトリ]と[拡張機能のコピー]を変更しました。

[ CA_default ]
44 dir      =./demoCA
      ↓
44 dir      =./

68 # copy_extensions = copy
      ↓
68 copy_extensions = copy

各要求書( server.csrなど)の拡張機能(extensions)追加はTLSエラーをなくすために必要です。

設定ファイル(openssl_CA.cnf)ファイル・ディレクトリ構成と同じように、ファイルとディレクトリを作成し、配置しました。

~/myca$ mkdir certs
~/myca$ mkdir crl
~/myca$ mkdir newcerts
~/myca$ mkdir private (ca秘密鍵用ディレクトリ)
~/myca$ chmod 700 private (ユーザー以外操作不可へ変更)
~/myca$ touch index.txt (ca証明書発行リスト)
~/myca$ echo '01' > serial (ca証明書発行シリアル番号)
~/myca$ echo '00' > crlnumber (証明書失効リスト番号)

ca.key はprivateディレクトリに作成して他のユーザーが閲覧不可の状態にしています。

ca秘密鍵(ca.key)とca証明書(ca.crt)を作成

設定ファイル(openssl_CA.cnf)の内容を反映させるためには -config オプションが必要です。

ca.key(ca秘密鍵)

~/myca$ openssl genrsa -config openssl_CA.cnf -out private/ca.key

ca.csr (ca要求書)

~/myca$ openssl req -config openssl_CA.cnf -new -key private/ca.key -out ca.csr

ca.crt(ca証明書)

~/myca$ openssl x509 -config openssl_CA.cnf -req -in ca.csr -signkey private/ca.key -days 365 -out ca.crt
~/myca$ openssl x509 -in ca.crt -noout -text(内容確認)

ca証明書の有効期間は通常で30日ですので -days オプションにより365日に変更しました。

なお、ca.crtは次のようにca.csr(ca証明書署名要求書)の作成を飛ばしたほうが楽です。

~/myca$ openssl req -new -x509 -config openssl_CA.cnf -key private/ca.key -days 365 -out ca.crt

すべて完了すると自己認証局(myca)内は次のようになります。

こちらで作成したもの以外は、最初の証明書を作成後に自動で作られたものです。

これで 各証明書に署名するための 準備ができました。

サーバ・クライアント証明書署名要求書の作成

CA(自己認証局)の準備ができましたので、サーバ・クライアントの各証明書署名要求書を作成しました。

サーバ証明書署名要求書(server.csr)の作成

ここからはサーバ側(ubuntu)での作業になります。

ここでは自己認証局(CA)で署名してもらうための証明書署名要求ファイル(server.csr)を作成します。

まず作業用ディレクトリ(vpn_server)をユーザー(ubusr)に作成しました。

~$ mkdir -p vpn_server
~$ cd vpn_server

/etc/ssl/openssl.cnf を作業ディレクトリ(~/vpn_server)へコピーして編集しました。

~/vpn_server$ sudo cp /etc/ssl/openssl.cnf ./my_openssl.cnf
~/vpn_server$ sudo chown user:user my_openssl.cnf (ユーザー権限へ変更)
~/vpn_server$ vi my_openssl.cnf

ここではTLSエラーをなくすための拡張機能を追加しました。

[ req ]
127 # req_extensions = v3_req # The extensions to add to a certificate request
               ↓
127 req_extensions = v3_req # The extensions to add to a certificate request (有効)

[ v3_req ]
223 basicConstraints = CA:FALSE
224 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
                  ↓
223 basicConstraints = CA:FALSE
224 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
225 extendedKeyUsage = serverAuth (追加)

その他に入力項目のデフォルト設定をしました。

vpnサーバ用の秘密鍵(server.key)と、自己認証局(myca)提出用のサーバ証明書署名要求ファイル(server.csr)を作成しました。

server.csr (証明書署名要求)

~/vpn_server$ openssl genrsa -out server.key (秘密鍵)
~/vpn_server$ openssl req -new -key server.key -config my_openssl.cnf -out server.csr
~/vpn_server$ openssl req -in server.csr -noout -text (内容確認)

このあとserver.csrは、認証局(debian11:~/myca)へ移しました。

クライアント証明書署名要求書(client.csr)の作成

こちらはクライアント(Alterlinux)での作業になります。

作業内容はサーバ側とほぼ同じです。(拡張機能の追加はありません。)

~$ mkdir -p vpn_client
~$ cd vpn_client
~/vpn_client$ openssl genrsa -out client.key
~/vpn_client$ openssl req -new -key client.key -out client.csr
~/vpn_client$ openssl req -in client.csr -noout -text (内容確認)

このあとクライアント証明書要求ファイル(client.csr)は、一旦サーバ(ubuntu:~/vpn_server)へ移して、認証局(debian:~/myca)へ移動しました。

サーバ・クライアント証明書(server.crt, client.crt)作成

各証明書の署名要求書(server.csr, client.csr)は、自己認証局(Debian11:~/myca)へ集められました。

拡張機能を追加しますので-config オプションが必要です。

~/myca$ openssl ca -config openssl_CA.cnf -in server.csr -out server.crt
~/myca$ openssl ca -config openssl_CA.cnf -in client.csr -out client.crt

証明書への署名では、次のような確認画面が出ますので「y」を入力します。

証明書内容の確認です。

~/myca$ openssl x509 -in server.crt -noout -text
~/myca$ openssl x509 -in client.crt -noout -text

サーバ証明書に認証局(CA)の情報が記載されています。

特に有効期限や拡張機能が追加されているかを確認します。

万が一、証明書に不備があった場合は、次のように証明書を失効させてから、新たに証明書を作成しなければなりません。

~/myca$ openssl ca -revork server.crt (サーバ証明書失効)
~/myca$ openssl ca -gencrl -out cacrl.pem (失効リスト作成・更新)
~/myca$ openssl crl -in cacrl.pem -noout -text (失効リスト確認)
~/myca$ openssl ca -in server.csr -out server.crt(再交付)

作成された各証明書 (server.crt, client.crt) はCA証明書 (ca.crt) と共に、元の端末へ移動します。

OpenVPNの起動・接続

OpenVPNを起動するためには、設定ファイル(.conf)を作成する必要があります。

OpenVPNの設定ファイルは、サーバ用とクライアント用にサンプル設定ファイル(server.conf, client.conf)がありますので、こちらをコピーして使います。

サンプル設定ファイル server.conf と client.conf は対になっていますので、一方の設定を変更すれば、必ずもう一方を見直す必要があります。なお、通常では何も変更せずに接続が可能なはずです。

OpenVPNサーバ起動

サーバ側に必要なファイルは 「CA証明書」ca.crt、「サーバ証明書」server.crt、「サーバ鍵」server.key 以外にも、「設定ファイル」server.conf、「Diffe Hellman 鍵共有 パラメータ」dh2048.pem と「HMACファイアウォール 」ta.key や「システム管理」ipp.txt、「ログファイル」openvpn-status.log などがあります。

これらのファイルを作業ディレクトリ(vpn_server)で作成します。

サンプル設定ファイル(server.conf)

サンプル設定ファイルの保管場所( /usr/share/doc/openvpn/examples/sample-config-files/ )から server.conf を作業ディレクトリ( vpn_server ) へコピーします。

~/vpn_server$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz ./my_server.conf.gz

サーバ用のサンプル設定ファイル (server.conf) は、gzipで圧縮されていますので、gunzipで伸張して使います。

~/vpn_server$ sudo gunzip my_server.conf.gz

ファイル所有権をユーザー(ubusr)へ移行

~/vpn_server$ sudo chown ubusr:ubusr my_server.conf

dh2048.pem

鍵受け渡しのための暗号化「Diffe Hellman 鍵共有 パラメータ」dh2048.pem を作成します。

~/vpn_server$ openssl dhparam -out dh2048.pem 2048 (Diffie hellman parameter)

ta.key

「HMACファイアウォール」こちらの鍵のコピーはクライアント側でも使います。(クライアント側では作りません)

~/vpn_server$ openvpn --genkey --secret ta.key (HMACファイアウォール)

ipp.txt

作らないとエラーが出ます。

~/vpn_server$ touch ipp.txt

openvpn-status.log

作らないとエラーが出ます。

~/vpn_server$ touch openvpn-status.log

ファイル一覧

~/vpn_server$ ls
my_server.conf  ca.crt  server.crt  server.key  
dh2048.pem  ta.key  ipp.txt  openvpn-status.log

OpenVPNサーバーを起動します。

ここだけは管理者権限が必要です。

~/vpn_server$ sudo openvpn my_server.conf

この状態でクライアント側からの接続を待ちます。

OpenVPNクライアント起動・接続

クライアント側に必要なファイルは「CA証明書」ca.crt、「クライアント証明書」client.crt、「クライアント鍵」client.key の他に「サンプル設定ファイル」client.conf、「HMACファイアウォール 」ta.key です。

client.conf と ta.keyは、サーバー側からコピーしたものを使います。

クライアント用サンプル設定ファイル(client.conf)

サーバ側(ubuntu)のクライアント用サンプル設定ファイル(client.conf)保管場所からコピーします。

~/vpn_server$ sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ./my_client.conf

ファイル所有権をユーザー(ubusr)へ移行

~/vpn_server$ sudo chown ubser:ubser my_client.conf

ta.key

サーバ側で作成したものをコピーして使います。

client.conf と ta.key は、まとめてクライアント側へ送ると良いと思います。

例:SCPによるサーバへのリモート接続の場合

~/vpn_client$ scp ubusr@ubn2.example.com:~/vpn_server/my_client.conf ./
~/vpn_client$ scp ubusr@ubn2.example.com:~/vpn_server/ta.key ./

ファイル一覧は次のようになります。

~/vpn_client$ ls
my_client.conf  ca.crt  client.crt  client.key  ta.key  

クライアント用設定ファイル(my_client.conf)を編集します。

~/vpn_client$ vi my_client.conf

remote パラメータにサーバアドレス(ubn2.example.com)と接続ポート(1194)を追加します。

39 # The hostname/IP and port of the server.
40 # You can have multiple remote entries
41 # to load balance between the servers.
42 ;remote my-server-1 1194 ← 無効にします
43 ;remote my-server-2 1194
44 remote ubn2.example.com 1194 ← サーバ側アドレスとポート番号を追加します

OpenVPNクライアントの起動は管理者権限が必要です。

~/vpn_client$ sudo openvpn my_client.conf

これでエラーが出なければ、ping送信を行います。

接続できない場合について

何らかのエラーで、クライアント側から接続できない場合についてです。

とりあえず、インターネットが接続されているか、証明書などのファイルに不備がないかを確認します。

もし、これらのすべてで問題がなければ、おそらくTLSエラーだと思います。

このエラーは、サーバ証明書にkeyUsage(鍵用途)関連の機能を追加することで解消されるようです。

また、クライアント側のopenvpn設定(client.conf)の中で、remote-cert-tls server を無効にすることでもエラーは解消されますが、暗号化通信ができませんので、中間車攻撃の対象となってしまい、オススメできません。

my_client.conf の remote-cert-tls server をコメントアウトすることで、ERRORはなくなります。

ですので、サーバ証明書を作り直す必要があるようです。

それには、サーバ証明書(server.crt)を作成する認証局(CA)の設定ファイル(openssl_CA.cnf)を変更する方法と、サーバ証明書要求ファイル(server.csr)に拡張機能をリクエストしたものを認証局(CA)で署名してもらう方法があります。

認証局(CA)の[usr_sert] keyUsage, extendedkeyUsageを有効にする方法

こちらは認証局の設定ファイル(openssl_CA.cnf)を変更して、署名する際に拡張機能を追加する方法です。

この場合サーバ証明書要求ファイル(server.csr)を作り直す必要はありませんが、認証局(myca)の設定を変更する必要があります。

~/myca$ vi openssl_CA.cnf

keyUsage(鍵用途)に否認防止、電子署名、鍵暗号の機能を追加します。

extendedkeyUsage(拡張鍵用途)にserverAuth(サーバ認証)を追加します。

165 [ usr_cert ]
190 keyUsage = nonRepudiation, digitalSignature, keyEncipherment 
217 extendedKeyUsage = critical,timeStamping,serverAuth

認証局で、これまでのserver.crtを失効させます。

~/myca$ openssl ca -config openssl_CA.cnf -revoke server.crt (サーバ証明書の失効)
~/myca$ openssl ca -config openssl_CA.cnf -gencrl -out cacrl.pem (失効リスト作成)
~/myca$ openssl crl -config openssl_CA.cnf -in cacrl.pem -text (失効リスト確認)

認証局でサーバ証明書(server.crt)を作り直します。

認証局またはサーバ側で証明書要求(server.csr)が残っていれば、新たに作り直す必要はありません。そのまま以前のserver.csrを使えます。

~/myca$ openssl ca -config openssl_CA.cnf -in server.csr -out server.crt
~/myca$ openssl x509 -config openssl_CA.cnf -in server.crt -text (確認)

このサーバ証明書(server.crt)をサーバ側に移して、起動することでTLSエラーを回避できました。

サーバ証明書要求ファイル(server.csr)の[req]req_extensionsを有効にする方法

こちらは本編でも実行していますが、一般的で簡単な方法だと思います。

前準備として、openssl.cnf設定ファイルを作業ディレクトリ(vpm_server)へコピーします。

~/vpn_server$ sudo cp /etc/ssl/openssl.cnf ./openssl_srv.cnf 

サーバ側の設定ファイル(openssl_srv.cnf)を以下のように編集します。

~/vpn_server$ vi openssl_srv.cnf
[ req ]
req_extensions = v3_req (有効化)

[ v3_req ]
extendedKeyUsage = serverAuth (追加)

サーバ証明書要求ファイル(server.csr)を作成して、認証局(CA)へ送ります。

~/vpn_server$ openssl req -config openssl_srv.cnf -new -key server.key -out server.csr

認証局の設定ファイル(openssl_CA.cnf)を以下のように変更します。

[ CA_default ]
copy_extensions = copy (有効化)

サーバ証明書の作成

~/myca$ openssl ca -config openssl_CA.cnf -in server.csr -out server.crt

server.crtをサーバ側(vpn_server)へ戻して、OpenVPNサーバを起動します。

~/vpn_server$ sudo openvpn my_server.conf

OpenVPNサーバが待受状態であることを確認したら、OpenVPNクライアント起動してOpenVPNサーバへ接続します。

~/vpn_client$ sudo openvpn my_client.conf

これでOpenVPN接続が完了しました。

接続確認

クライアント側からサーバ側への接続を確認できたら、別のターミナル(端末)を開いて「10.8.0.1」へping送信を試みます。

うまく送信できたらOKです。

このあと、smbファイル共有で使ってみても問題なく接続できました。

まとめ

今回は、自己認証局(CA)で署名した証明書を使って、OpenVPN環境の構築をしてきましたが、実際には、設定を変えずに証明書を作成した場合、TLSエラーで接続できません。

この状態から抜け出すには、証明書の鍵用途(keyUsage)機能を有効にして、TLS暗号化通信が正常に行われる状態にしなければなりませんでした。

ここまで理解することにかなり苦労しましたが、良い勉強になりました。

今後は、OpenVPNをバックグラウンドで起動させて、外部ネットワークから接続できるようにしていきたいと思います。

[追記 2021-11-12]

今回のことを最初にまとめたときは ca.crt 作成時に -days オプションを指定しておらず30日で有効期間が終わってしまいました。有効期間が通常で365日だと勘違いしていたので、突然VPN接続ができなくなり、かなり焦りましたので備忘録として残しておきます。

,

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)