前回は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アドレス | FQDN | VPN アドレス |
Debian11 bullseye (~/myca) | 自己認証局 | 192.168.10.115 | debi1.example.com | |
ubuntu 20.04(~/vpn_server) | VPNサーバ | 192.168.10.118 | ubn2.example.com | 10.8.0.1 |
Altelinux (~/vpn_client) | VPNクライアント | 192.168.10.114 | al3.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 送信で確認しました。
作業のながれ
- 自己認証局(CA)作成
- サーバ・クライアント証明書署名要求書(server.csr, client.csr)作成
- サーバ・クライアント証明書(server.crt, client.crt)作成
- OpenVPNの起動・接続
- 接続確認
自動化や外部(ローカルエリア外)からの接続は次回に行います。
自己認証局(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 を無効にすることでもエラーは解消されますが、暗号化通信ができませんので、中間車攻撃の対象となってしまい、オススメできません。
ですので、サーバ証明書を作り直す必要があるようです。
それには、サーバ証明書(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接続ができなくなり、かなり焦りましたので備忘録として残しておきます。