OpenSSLでSSLサーバ証明書の有効期間を自動的に確認して更新漏れを防ぐ:Tech TIPS
運用・管理担当者にとって面倒なSSLサーバ証明書の更新。有効期間内に正しく更新できるように、OpenSSLを使って自動的かつ定期的にサーバの証明書を実際に調べて、期限切れが近づいているかどうか網羅的に確認する方法を紹介する。
対象:Windows OS、OpenSSL
Webサイト運用担当者や社内システム管理者にとって、SSLサーバ証明書の更新はやっかいな仕事の1つに挙げられるだろう。証明書の更新は手動作業が多く、手間がかかる。その一方で有効期間内に更新を忘れると、そのサーバにアクセスしたクライアントでエラーが生じるため、ユーザーに迷惑をかけることにもなるからだ。
証明書の枚数が少なければ、期限が切れる日をオンラインのカレンダーに登録し、事前に通知させるといった対策も有効だろう。しかし数十枚、数百枚となると、これを手動で管理するのは手間がかかるし、間違える恐れもあり現実的ではない。
それよりは、サーバに設定されているSSLサーバ証明書を読み出し、有効期間があとどれくらいで終わるのか、定期的かつ自動的にチェックした方が手間なく確実だ。本TIPSではその方法の一例を紹介したい。
前提として、証明書を取り扱うコマンドにはデファクトスタンダードである「OpenSSL」を利用する。またその実行プラットフォームはWindows OSとする。以下では、Windows 10バージョン1709とOpenSSL Ver.1.1.0hの組み合わせで動作を確認している。
【準備】WindowsにOpenSSLをインストールする
まず、証明書のチェックを実行するWindows PCにOpenSSLをインストールする。Windowsの場合は、TIPS「WindowsにOpenSSLをインストールして証明書を取り扱う(基本編)」の手順でインストールしていただきたい。インストーラは、開発者向けのファイルを含まないLight版で十分だ。
インストールしたら、Windows OSの実行パスに「<インストール先フォルダ>\bin」を加えておく。その後、コマンドプロンプトでフルパスを指定することなくopensslコマンドが実行できることを確認する。
C:\>openssl version
OpenSSL 1.1.0h 27 Mar 2018
「version」オプションを指定して実行すると、上記のようにOpenSSLのバージョンが表示されるはずだ。
証明書の有効期間の確認に利用するOpenSSLの2つのサブコマンド
OpenSSLを使ってSSLサーバ証明書の有効期間を確認するには、作業を次の2つに分類して実施する。
- 監視対象のサーバに設定されているSSLサーバ証明書を取得(ダウンロード)する
- 取得した証明書から有効期間を抽出する
「1.」にはOpenSSLのサブコマンド「s_client」を、「2.」には「x509」を用いる。これらのサブコマンドの使い方を以下で解説していく。
サーバに登録されているSSLサーバ証明書を取得する
リモートサーバからSSLサーバ証明書を取得するには、次のように「s_client」サブコマンドを実行する。
openssl s_client -connect <サーバの名前またはIPアドレス>:<ポート番号> < nul > <保存先ファイル名>
<サーバの名前またはIPアドレス>には、次の例のように、監視対象のSSL/TLS対応サーバに到達できる(名前解決が可能な)ホスト名か、IPアドレスを指定する。
- FQDNで指定: -connect www.example.jp:443
- Windows OSのコンピュータ名で指定: -connect WINSVR01:443
- IPv4アドレスで指定: -connect 203.0.113.111:443
- IPv6アドレスで指定: -connect [2001:db8::111]:443
<サーバの名前またはIPアドレス>は、対象のSSLサーバ証明書の共通名(Common Name、CN)あるいは別名(Subject Alternative Names、SAN)のいずれかと合致していなくてもよい。
また<ポート番号>には、次の例のように、対象サーバがSSL/TLSをリッスンしているポートの番号を指定する。
- 一般的なHTTPSサーバ: -connect www.example.jp:443
- リモートデスクトップセッションホスト: -connect www.example.jp:3389
- SMTP over SSL/TLSのサーバ: -connect www.example.jp:465
標準入力をnulにリダイレクトしているのは、SSL/TLSのセッションを自動的に閉じるためだ。s_clientサブコマンドは、サーバに接続してSSL/TLSのセッションを開いた後、コマンド入力待ちの状態になる。SSLサーバ証明書を取得するだけならコマンド入力は不要なので、セッションはすぐ閉じてよい。
正しくSSLサーバ証明書が取得できると、標準出力に出力されるので、リダイレクト先として<保存先ファイル名>を指定して保存する。これは後ほどx509サブコマンドで入力ファイルとして利用する。
●バーチャルホストの場合は「-servername」オプションが必須
1つのIPアドレスで複数のサーバ(ホスト)がリッスンしている、いわゆる「バーチャルホスト」の場合、「-servername」オプションを追加して対象サーバを明確に指定する必要がある。
openssl s_client -connect <サーバの名前またはIPアドレス>:<ポート番号> -servername <サーバのFQDN> < nul > <保存先ファイル名>
<サーバのFQDN>には、バーチャルホストのFQDN(完全なドメイン名)を指定する。これは通常、対象となっているSSLサーバ証明書の共通名あるいは別名のいずれかと合致しているはずだ。
もし、このオプションを指定せずにバーチャルホストからSSLサーバ証明書を取得しようとすると、同じIPアドレスのデフォルトのホスト、つまり(たいていの場合は)見当違いのホストに割り当てられている証明書が返されてしまう。
●STARTTLSの場合は「-name」「-starttls」オプションが必須
587番ポートをリッスンするSMTPサーバは通常、「STARTTLS」というプロトコルを使ってTLSでの接続を確立する。この場合、次のように「-name」「-starttls」オプションを指定する必要がある(指定しないとエラーになる)。
openssl s_client -connect <サーバの名前またはIPアドレス>:<ポート番号> -name <サーバのFQDN> -starttls smtp < nul > <保存先ファイル名>
<サーバのFQDN>には、対象のSMTPサーバのホスト名を完全なドメイン名で記述する。
SSLサーバ証明書の有効期間の終了日時を表示する
取得・保存したSSLサーバ証明書の期限が切れる日時を表示するには、次のようにOpenSSLの「x509」サブコマンドを実行する。
openssl x509 -in <証明書を格納したファイル> -nocert -enddate
<証明書を格納したファイル>には、前述のs_clientサブコマンドの標準出力を保存したファイルを指定する。「-enddate」オプションは、証明書の有効期間の終了日時を表示するためのものだ。「-nocert」オプションは、(ここでは不要な)証明書の内容表示を止めるために指定する。
s_clientサブコマンドの出力とx509サブコマンドの入力を、次のようにパイプでつないでもよい。
openssl s_client -connect www.example.jp:443 < nul | openssl x509 -nocert -enddate
どちらの場合でも、「notAfter=Nov 24 23:59:00 2018 GMT」というフォーマットで有効期間の終了日時が表示される。
SSLサーバ証明書の有効期間が30日以内に終了するかどうか確認する
SSLサーバ証明書を漏れなく更新しなければならない立場としては、その有効期間の日時そのものより、証明書の期限が近日中に切れてしまうのか、それともまだ余裕があるのか判定できる方が便利だ。「-checkend」オプションを使うと、例えば30日以内に期限が切れるかどうかを判定できる。
openssl x509 -in <証明書を格納したファイル> -checkend <期限切れまでの秒数> -nocert
例えば<期限切れまでの秒数>に「2592000」(=30日×24時間×60分×60秒)と指定すると、実行時点から30日後に対象の証明書の有効期間が終了しているかどうか判定され、次のように出力される。
- 「Certificate will not expire」: 30日後でも、まだ有効期間内
- 「Certificate will expire」: 30日後には、有効期間が終了する
ちなみにいずれもGMT(グリニッジ標準時)で判定されるため、日本だと9時間の時差による誤差が生じる。それでも、十数日あるいは数十日といった単位で証明書の有効期間を判別するだけならば特段問題はないだろう。
また有効期間が終了すると判定された場合、openssl実行後の戻り値が1になる(期限内なら0)。これを利用すると、スクリプトやバッチファイルで有効期限切れが近い証明書を見つけたら通知する、といった処理が簡単に実現できる。
複数のサーバの証明書有効期間を一括確認する
あとはスクリプトやバッチファイルなどで、管理下の各サーバの証明書を一括確認し、有効期間の終了が間近なものだけ通知するようにし、タスクスケジューラで1日1回実行するように設定しよう。こうすることで、手動に比べてはるかに網羅的に確認できる。
参考までに、バッチファイルでの実装例を紹介しよう(言うまでもなくPowerShellやシェルスクリプトで実装してもよい)。まず対象のサーバのFQDNとポート番号、サービス名をタブ区切りのテキストファイルにまとめる(ここではlist-hosts.txtとする)。サービス名はSTARTSSLが必須かどうか判定するのに用いる。
#HostName PortNumber Service
www.example.jp 443 www
svr01.example.local 3389 rdsh
smtp.example.jp 587 startssl
このリストをforコマンドで1行ずつ取得して、OpenSSLのオプションに設定しつつ実行する。以下にその例を記す。シンプルにするためエラー処理を省いているので、適宜強化していただきたい。
@echo off
setlocal
REM ----- ↓↓サーバ一覧ファイルの在りか
set URLList=.\list-hosts.txt
REM ----- ↓↓認証局の証明書ファイルの在りかを指定
set OsslClientOpts=-CAfile C:\local\CAcert\ca-bundle.crt
REM ----- ↓↓2592000秒=30日後に有効期間が終了しているかどうか判定
set OsslX509Opts=-checkend 2592000
REM ---------- 一覧ファイルのサーバを1つずつ検証 ----------
for /F "skip=1 tokens=1,2,3 delims= " %%i in (%URLList%) do (
set Host=%%i
set Port=%%j
set Service=%%k
echo ----- %%i:%%j - %%k -----
call :OpenSSL
)
REM ---------- 終了処理 ----------
:END
endlocal
exit /b
REM ---------- SSLサーバ証明書の有効期間を判定 ----------
:OpenSSL
if "%Service%" == "startssl" (
openssl s_client -connect %Host%:%Port% %OsslClientOpts% -name %Host% -starttls smtp <nul | openssl x509 %OsslX509Opts%
) ELSE (
openssl s_client -connect %Host%:%Port% %OsslClientOpts% -servername %Host% <nul | openssl x509 %OsslX509Opts%
)
if errorlevel 1 call :Notification
REM ----- ↑↑もし戻り値が1以上だったら、期限切れが間近だと見なして通知する
exit /b
REM -----
REM ---------- 通知の送信 ----------
: Notification
REM ----- ここにメール送信あるいはWebhookなど通知のためのロジックを記述 -----
exit /b
REM -----
正常に動作することを確認したら、TIPS「タスクスケジューラの基本的な使い方(Windows 7/8.x/10編)」の手順でタスクスケジューラに登録し、1日1回定時に実行されるように仕込むとよいだろう。
筆者が確認した限りでは、上記の手法でHTTPS対応Webサイトはもちろん、その他のSSL/TLS対応サーバでも有効期間を確認できた。
- リモートデスクトップセッションホスト
- リモートデスクトップゲートウェイ
- SSTP対応のVPNサーバ(Windows Server)
- IIS付属のSMTPサーバ
一方、プロキシサーバを経由する必要があるネットワーク環境や、クライアント証明書が必須のサーバなどでは、s_clientサブコマンドにそのためのオプションを追加指定する必要がある。本稿では触れないので、OpenSSLのヘルプなどを参照していただきたい。
Copyright© Digital Advantage Corp. All Rights Reserved.