【新卒 / 中途採用】サーバー / クラウドエンジニア 募集中!【大阪】

【新卒 / 中途採用】サーバー / クラウドエンジニア 募集中!【大阪】

【導入実績300社以上】AWS 構築・運用保守サービス

【導入実績300社以上】AWS 構築・運用保守サービス

【ECサイト構築】Shopify カスタムアプリ開発サービス

【ECサイト構築】Shopify カスタムアプリ開発サービス

【100URLの登録が0円】Webサイト監視サービス「Appmill」

【100URLの登録が0円】Webサイト監視サービス「Appmill」

【音声アプリ開発】Twilio アプリ開発サービス』

【音声アプリ開発】Twilio アプリ開発サービス』

【メッセージアプリ】LINE アプリ開発サービス

【メッセージアプリ】LINE アプリ開発サービス

【対談記事】「やっぱクラウド移設っていいですよね」マイネット × ビヨンド エンジニア対談

【対談記事】「やっぱクラウド移設っていいですよね」マイネット × ビヨンド エンジニア対談

ビヨンド公式YouTubeチャンネル「びよまるチャンネル」

ビヨンド公式YouTubeチャンネル「びよまるチャンネル」

LetsEncryptのROOT証明書の期限が切れたら古いOSからアクセスできなくなって困った


カナダはスタバで注文したら名前を聞かれるんですが(日本でも聞かれたっけ?)Seikenと言っても全然通じないので
次は小粋なイングリッシュネームを使ってやろうと毎回思っても、いざその時になると恥ずかしくて言えない小心者の聖賢です。

10/1以降一部のサイトにHTTPSで接続できない?

LetsEncryptのROOT証明書が"DST Root CA X3"の期限切れ(2021/9/30)に伴い2035年まで有効な認証局"ISRG Root X1"を併用したクロスルート証明書に変更されたのですが、"DST Root CA X3"の期限が切れた10/1以降、環境によってはLetsEncryptの証明書を使っているサイトにアクセスした際にSSL証明書のエラーが発生するようになりました。
同じことで困っていそうな人が沢山居そうなのでこの記事が困っている方の助けになれば幸いです。

発生する現象

LetsEncrypt(のROOT証明書に"ISRG Root X1"と"DST Root CA X3"のクロスルート証明書)を利用しているサイトに接続するとSSLのエラーが発生します

OS別原因と対処

CentOS7, Amazon Linux, Amazon Linux2の場合

十中八九はOSにインストールされているROOT証明書が古く、"ISRG Root X1"ルート証明書がOSのROOT証明書ツリーに存在しないことが原因です、以下のコマンドでROOT証明書を更新してあげましょう。
yum -y update ca-certificates
opensslのバージョンが古い(1.0.1以下)の場合にも問題が発生するのでその場合はopensslも最新版にバージョンアップしてください。

CentOS6の場合とよくあるエラー

クロスルート証明書の検証にはopenssl1.0.2以上のバージョンが必要ですが、CentOS6はサポートが終了しており、1.0.1までのバージョンしか提供されていません。
openssl1.0.1以下のバージョンではSSL証明書のpartial chain機能が実装されていないため、証明書の検証が正しく行えずにSSL通信エラーが発生します。
以下は実際に良くあるエラーパターンの例です。

wgetの例

wget https://LetsEncryptの証明書を利用しているサイト
実行結果
--2021-10-04 20:06:18--  https://LetsEncryptの証明書を利用しているサイト/
Resolving LetsEncryptの証明書を利用しているサイト... xx.xx.xx.xx
Connecting to cLetsEncryptの証明書を利用しているサイト|xx.xx.xx.xx|:443... connected.
ERROR: cannot verify LetsEncryptの証明書を利用しているサイト’s certificate, issued by “/C=US/O=Let's Encrypt/CN=R3”:
  Issued certificate has expired.
To connect to LetsEncryptの証明書を利用しているサイト insecurely, use ‘--no-check-certificate’.

opensslコマンドの例

openssl s_client -connect LetsEncryptの証明書を利用しているサイト:443 -servername LetsEncryptの証明書を利用しているサイト < /dev/null
実行結果
CONNECTED(00000003)
〜中略〜
    Start Time: 1633378075
    Timeout   : 300 (sec)
    Verify return code: 10 (certificate has expired)
---
DONE

opensslのライブラリ(多分libssl.so.10)を使って通信するphpプログラムの例

以下のようにget_file_contents関数を使っているプログラムでは証明書の検証に失敗します
サンプルコード
<?php
$url = "https://LetsEncryptの証明書を利用しているサイト/";
$output = file_get_contents($url);
var_dump($output);
実行結果
PHP Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in "実行したプログラム" on line 3
PHP Warning: file_get_contents(): Failed to enable crypto in "実行したプログラム" on line 3
PHP Warning: file_get_contents(https://LetsEncryptの証明書を利用しているサイト/): failed to open stream: operation failed in "実行したプログラム" on line 3
bool(false)

curlコマンドやphpのcurl関数を使っている場合は問題が起きません。

おそらくcurlコマンドが利用している暗号通信関連ライブラリにopenssl系のlibssl.so.10だけではなくNSS系のlibssl3.soが含まれているためだと思います。
ldd /usr/bin/curl | grep ssl

libssl3.so => /usr/lib64/libssl3.so (0x00007f43fc44b000)
libssl.so.10 => /usr/lib64/libssl.so.10 (0x00007f43fb1c5000)

ldd /usr/bin/wget | grep ssl

libssl.so.10 => /usr/lib64/libssl.so.10 (0x00007f79a04c6000)

ldd /usr/bin/openssl | grep ssl

libssl.so.10 => /usr/lib64/libssl.so.10 (0x00007f2872a3a000)

rpm -qf /usr/lib64/libssl3.so

nss-3.44.0-7.el6_10.x86_64

rpm -qf /usr/lib64/libssl.so.10

openssl-1.0.1e-58.el6_10.x86_64

問題の解消のためには

curlコマンドまたはcurl系のライブラリを使うようにプログラムを修正するか、opensslの1.0.2以上のバージョンが必要ですが、
前述のとおりCentOS6では1.0.1以上のバージョンが提供されていないため、プログラムの修正が難しい場合は、CentOS7のリポジトリからSRPMを取得してCentOS6用に修正してビルド、インストールすることでなんとか問題を回避することが可能でした。
元ネタはこちらです。
※弊社では実際に稼働しているサーバでも実績のある手順ですが、opensslの全ての機能についての影響と動作確認はできておりませんのでご注意ください。
※根本的にはOSのアップデートを行うことを推奨します。

CentOS6に強引にopenssl1.0.2をインストールする手順

srpmからrpmパッケージを作成

CentOS7のリポジトリからopenssl 1.0.2のsrpmパッケージの取得

cd /usr/local/src
wget --no-check-certificate https://vault.centos.org/7.9.2009/updates/Source/SPackages/openssl-1.0.2k-21.el7_9.src.rpm
rpm -i openssl-1.0.2k-21.el7_9.src.rpm

※rpmコマンドを実行したユーザーのホームディレクトリ以下にrpmbuildというディレクトリが作成されソースコードが展開されているので移動します。

cd ~/rpmbuild

SPECファイルの修正

※"%patch68"は不要な処理なのでコメントアウトします

sed -i -e "s/%patch68/#%patch68/g" SPECS/openssl.spec

 

patchファイルの修正

※secure_getenvというglibcの関数がCentOS6にはないのでgetenvに置き換えます

sed -i -e "s/secure_getenv/getenv/g" SOURCES/openssl-1.0.2a-env-zlib.patch
sed -i -e "s/secure_getenv/getenv/g" SOURCES/openssl-1.0.2j-deprecate-algos.patch
sed -i -e "s/secure_getenv/getenv/g" SOURCES/openssl-1.0.2a-fips-ctor.patch

 

rpmパッケージのbuild

※ビルドに必要なツールがインストールされていなければインストールしてからrpmbuildしてください

yum install rpm-build krb5-devel zkib-devel lksctp-tools-devel zlib-devel gcc
rpmbuild -ba SPECS/openssl.spec

 

rpmパッケージをインストール

依存関係で必要なパッケージ(perl-WWW-Curl)をインストール

yum install perl-WWW-Curl

 

rpmパッケージがビルドされたディレクトリに移動してrpmコマンドでインストール

cd RPMS/
rpm -Uvh openssl-*

 

ちゃんとバージョンが上がったか確認

openssl version

※1.0.2kになっていれば成功です

 

DST Root CA X3証明書の無効化

※DST Root CA X3証明書がOSのroot証明書に残っていると問題が解消しません、どちらにせよ期限の切れている証明書なので無効化しましょう。

OSのroot証明書を最新化

yum update ca-certificates

 

update-ca-trust機能を有効にしてroot証明書を一度update-ca-trustコマンドで更新

update-ca-trust enable
update-ca-trust

※yum update ca-certificatesでroot証明書を更新した直後はOSの信頼済みroot証明書(/pki/tls/certs/ca-bundle.crt)のファイルが証明書の内容だけではなくIssuerや期限などのコメントが入った状態になっています。

この状態でもOSの動作には問題ありませんがupdate-ca-trustコマンドを引数なしで実行するとOSの信頼済みroot証明書が証明書の内容とコメントのみのファイルに整理されます。
次のコマンドで証明書部分だけを確実に取り出すために必ず実行してください。

"DST Root CA X3"証明書のみを取り出し/etc/pki/ca-trust/source/blacklist/以下にファイルとして保存

perl -e 'while(<>){last if $_ =~ m/DST Root CA X3/;}print $_;while(<>){last if length($_)==1;print $_}' </etc/pki/tls/certs/ca-bundle.crt > /etc/pki/ca-trust/source/blacklist/DST_Root_CA_X3.pem

※/etc/pki/ca-trust/source/blacklist/DST_Root_CA_X3.pemという名前のファイルが作成されて、内容が以下のようになっていれば大丈夫です。うまくいかない場合は手動でファイルを作成しても問題ありません。

#DST Root CA X3
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----

"DST Root CA X3"証明書を無効化

update-ca-trust extract
grep "DST Root CA X3" /etc/pki/tls/certs/ca-bundle.crt

※何も表示されなければOKです

grep "ISRG Root X1" /etc/pki/tls/certs/ca-bundle.crt

※# ISRG Root X1 と表示されればOKです

アップデート後にエラーの出ていたプログラムを実行して問題が解消されたかどうか確認してみてください。

サーバ上でSSLを提供するサービス(Apacheなど)が動いている場合はサービスを再起動することを推奨します。

 


この記事をかいた人

About the author

佐藤聖賢

ピンチになると第6感が冴えるが基本はオールドタイプのエンジニア
今はカナダオフィスで仕事してます。