安全な証明書自動更新のやり方

cybozu.com Cloud Platformチームのhsntomoです。今回はサイボウズで証明書更新の自動化を安全に行うための工夫をご紹介します。

背景

サイボウズではcybozu.comのサービスを提供するために数多くの証明書を取得し、管理しています。 今まではそれらをすべて手動で取得し、入れ替えを行っていました。

しかし、元来の運用ではいくつかの問題が浮上してきました。

手動更新の際は認証局によって更新手順が異なります。 具体的にはドメインの所有確認(DCV: Domain Control Validation)と証明書のダウンロード手順を、それぞれの認証局が独自に提供しています。 そのため、ドメインの更新手順書は複雑に長くなってしまいます。結果として更新の準備に時間がかかり、実施の際にミスも発生しやすくなっていました。

サイボウズでは証明書の有効期限が切れる1か月前に管理用のKintoneアプリから通知が届き、SREは準備を始めます。 手順書のテンプレートを確認したうえで、該当の証明書に合わせた手順を作成します。 ミス防止の内部でのポリシーとして、作成した手動作業の手順書は別のSREメンバーによるレビューを受ける必要があります。 レビューに合格したら、まず認証局のDCV作業を行います。確認が成功したら、新しい証明書が発行されるので、認証局よりダウンロードします。 ダウンロードした証明書を運用環境の各機材に配置し、テスト機で動作確認ののち、全台に順々に適用を行います。

cybozu.comサービス関連では2-3種類の認証局を利用していて、約15個の証明書を運用しています。証明書更新の際は準備期間や手順作成及び作業の実行を含めて約8人時の工数が発生していました。有効期限が3年の証明書は3年に1回の頻度で実施しているので、年間40人時の更新コストが発生していました。普段順調にいけば約8人時程度で済むのですが、もしトラブルが発生すればさらに時間がかかります。

一方、近年証明書の有効期限を短縮する傾向にあります。 例えば、認証局の運用規則(Baseline Requirements)を決めているCA/B Forumにて、証明書の最長有効期限を2020年8月のBaseline Requirements v1.7.1の時点で825日から398日に引き下げました。その前は39か月(約1186日)でした。 詳しい基準はCA/B Forum Baseline Requirements section 6.3.2に記載されています。 上記以前にもApple社が独自の基準としてSafariにて証明書の有効期限を13か月に絞ったこともあります。

証明書の有効期限が短縮されると、証明書更新手順を実施する頻度も増えることになります。 結果として以前年間40人時で済んでいた作業が、年間120人時という3倍のコストになってしまう見込みです。

さらに、取得する証明書の数が増えていくことで、このコストが上がっていってしまいます。

もちろん、証明書が何らかのトラブルで正常に更新できなければ、サービスが全体的に使えなくなってしまううえ、その状況下で早く正確に証明書を更新しなおさなければならず、非常に苦しい障害対応を迫られることになります。

これらの事情から、証明書の更新の自動化をすることにしました。

証明書の自動更新と付随する問題

証明書の自動更新に利用できる仕組みとして、ACME(Automated Certificate Management Environment)という証明書自動更新・管理の為の通信プロトコルがあります。これはISRG(Internet Security Research Group)の取り組みなどを通じて作られたものです。ISRGはLet's Encryptというサービスを提供しています。

ACMEでは下記の流れで、クライアントと認証局との間で共通仕様のJSON形式のメッセージをHTTPSでやり取りします。

  1. 証明書を要求する側(クライアント)がCSR(Certificate Sigining Request)を作成する
  2. CSRをACME対応の認証局に提出する
  3. 認証局はDCVをクライアントに要求する
  4. クライアントは、DCVの要求に応じて対応を行う
  5. 認証局は証明書を作成して渡す

これにより、異なる認証局・異なるクライアントの間でも、共通化された流れで証明書を発行することができます。

ACMEで利用できるDCVのチャレンジ方式のうちの一つに、DNS-01という方式があります。 DNS-01ではまず認証局が登録すべきDNSレコードをクライアントに指示します。 例えばexample.comの証明書を発行したい場合は、認証局が決めた文字列を_acme-challange.example.comのTXTレコードに登録する必要があります。

ここで、クライアントプログラムがDNS-01でDCVを行うためには、DNSゾーンに対する編集権限を渡さなければいけません。 しかし、example.comでサービスを提供している中、編集権限をプログラムに渡してしまうと、既存のexample.comの任意のDNSレコードをクライアントプログラムも編集できるようになってしまいます。

万が一クライアントプログラムが乗っ取られるなどのセキュリティインシデントが発生した場合、example.comの他のサービスが危険にさらされます。

以降、上記をはじめとする証明書の自動更新に伴う問題に対して、サイボウズで行っている対策を解説します。

サイボウズで行っている対策

cybozu.comでは証明書自動更新を導入するにあたってクライアントプログラムとしてcert-managerを利用しています。 証明書の自動更新を安全に行うために、以下の対策を行っています。

DNS-01を行うための代理ゾーンを作成

cert-managerではACMEのDNS-01チャレンジ方式を利用しますが、過剰な権限を渡さないために、代理ゾーンを利用しています。

hoge.example.comの証明書を発行する時の通常の流れは以下の図の通りです。

証明書を発行する時の通常の流れの図
証明書を発行する時の通常の流れ

最初に認証局からexample.comのDNSゾーンに対してacme-challenge.hoge.example.comのTXTレコードへの問い合わせが来ます。 acme-challenge.hoge.example.comのTXTレコードには認証局が決めたチャレンジの文字列をあらかじめ記載してあるので、DCVが成功します。

これに対し、代理ゾーンがある場合は以下のようになります。

代理ゾーンがある場合の流れの図
代理ゾーンがある場合の流れ

通常と同じく認証局から example.com のDNSゾーンに対して acme-challenge.hoge.example.com のTXTレコードへの問い合わせが来ます。 example.com がCNAMEレコードを用いて acme.example.com にある acme-challenge.hoge.acme.example.com のTXTレコードを参照するように誘導します。 認証局は改めて acme.example.com に _acme-challenge.hoge.acme.example.com のTXTレコードを問い合わせ、認証局が決めたチャレンジの文字列をあらかじめ記載してあるので、DCVが成功します。

上記の代理ゾーンを用いたDNS-01 DCVを実現するために、以下の設定をしました。

あらかじめ acme.example.com のDNSゾーンとDNSサーバを example.com のDNSゾーンとDNSサーバとは別に用意します。 example.com のゾーンにて acme.example.com の NSレコードを acme.example.com のDNSサーバーに設定することで、 acme.example.com への参照を example.com のDNSサーバーから、acme.example.com のDNSサーバーに移譲します。 acme.example.com への操作権限だけをcert-managerに渡すことで、cert-managerに渡す権限を絞ることができます。

さらに、hoge.example.com のDNS-01にて代理ゾーンを参照させるため、acme-challenge.hoge.example.com の代わりに acme-challenge.hoge.acme.example.com へ誘導するCNAMEレコードを example.com のDNSゾーンに設定します。

これらの設定を入れることで、DNSゾーンの操作の安全性は以下のように高まります。 まずcert-managerは example.com のDNSゾーンの操作ができないため、任意の example.com のサブドメインに対するDCVをされることはありません。 さらに管理者にしか example.com のDNSゾーンの操作ができないため、意図しない代理ゾーンへの紐づけもされることはありません。

CAAの設定

前節で述べたDNS-01を行うための代理ゾーンを導入したことで、証明書自動更新を行うクライアントプログラムの権限を制限しました。 ただし、そのクライアントプログラムが利用するトークン自体が何らかの理由で流出した場合、入手した攻撃者は代理ゾーンの編集ができるようになります。

すでに、前述の example.com がCNAMEレコードを用いて acme.example.com にある _acme-challenge.hoge.acme.example.com のTXTレコードを参照するように誘導する設定が行われていた場合、 トークンを入手した攻撃者は代わりにDCVを行うことができてしまいます。 結果として、hoge.example.comの証明書を、任意の認証局で発行させるリスクがあります。

ここで、RFC 8659で定義されている Certification Authority Authorization (以後CAA) を利用することができます。 CAAでは証明書を発行していい認証局をドメインの所有者がDNSレコードを用いて指定できます。 CAAレコードはCA/B ForumのBallot 187の意思決定により、CAAレコードに認証局自身が含まれていない時は証明書を発行してはならないと義務付けられています。

サイボウズでは、実際に証明書の発行に利用している認証局のみをCAAレコードで指定することで、証明書を発行できる認証局を制限しています。

ct-monitorによる意図しない証明書発行の検知

ただし、CAAを設定したとしても、完全に不正な証明書の発行を防ぐことはできません。 トークンが万が一流出した場合、トークンを手に入れた攻撃者がCAAで許可している認証局で証明書を発行させることができます。 この場合の不正発行は未然に防ぐことはできません。

ここで、RFC 6962で定義されている Certificate Transparency(以降CT) を利用することができます。 認証局が証明書を発行するときに監査のために証明書発行の痕跡をCTログと呼ばれている監査ログに残す必要があります。 これは近年多くのブラウザが、証明書がCTログに乗っていることを確認しているためです。 CTログはだれでも閲覧することができるため、ドメイン管理者は自分たちの管理しているドメインに対する不正な証明書発行を監視することができます。

ただし、CTログは自ら閲覧しに行く必要があります。不正発行に気づきやすくするため、自動的にCTログを監視するためのツールとして、ct-monitorを導入しました。 ct-monitorでは定期的に対象ドメインのCTログを監視します。証明書発行を検知した場合、管理者にメールにて報告を送ります。 ct-monitorのデフォルト設定では正当な証明書発行と、不正な証明書発行を区別せずにメールを送ります。 これはct-monitor単体が持つ情報だけでは、自分たちが意図した証明書発行かどうかを判断できないためです。 このままでは、管理者はメールを受け取るたびに、それが自分たちが意図した証明書発行かどうかを判断しなければなりません。 これまで証明書自動発行などの取り組みで手間を削減できたのに、このままではCTログ対応によって増えてしまいます。

ct-monitorにはプラグイン機能があります。プラグインでは証明書発行の一覧に対してフィルタリングや追加の処理を行うことができます。 フィルタリングを行うことで、報告対象のCTログを減らすことができます。 サイボウズではその機能を用いて、cybozu.comの環境に適した2つのプラグインを導入しました。 1つ目のプラグインは自動的に正しく発行された証明書と確定できるCTログを報告から除外する機能を持ちます。 2つ目のプラグインは自動的に判断できない証明書のCTログを担当の管理者に転送する機能を持ちます。

上記のプラグインの導入により、オペレータが負担にならない程度の通知を受け取ることができるようになります。 これにより、事後にはなってしまいますが、証明書の不正発行が検出できるようになりました。

まとめ

今回はサイボウズで証明書更新の自動化を安全に行うための工夫をご紹介しました。

これまで手動で行っていた証明書更新作業はオペレータの多くの工数を必要とする作業でしたが、自動更新を導入することでその工数を減らすことができました。 その際、代理ゾーンを利用して自動更新を行うプログラムの権限を制限することで安全性を確保し、CAAの設定により証明書を発行できる認証局を制限し、ct-monitorにより意図しない証明書発行の監視も行うことで証明書の運用の安全性を高めることができました。

みなさんの今後の証明書関連の取り組みの参考になれば幸いです。