Chromeでエラーにならない自己認証局&サーバー証明書を作る

仕事で画像ベースの回帰テストをWebサービスの社内検証環境でできるよう準備する中で、すでに用意されている自己署名証明書だとhttpsなページにHeadless Chromeでアクセスできない(スクリーンショットが真っ白)問題があり、自己認証局を立ててサーバー証明書を発行させて、ということをした。その時の経験をもとに手順を精査してまとめてみる。

原因

Chromeがコモンネームの設定を非推奨化、そのエラー対策としての自己署名証明書のCSRの作り方という記事にある通り、サブジェクト代替名の指定のない自己署名証明書を使っていたから。
具体的にはopenssl.confデフォ設定ままで以下のような作り方をしていた。

$ sudo openssl genrsa 2048 > server.key
$ sudo openssl req -new -key server.key > server.csr
$ sudo openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt

これで生成される証明書はX.509 v1の証明書で、v3フィールドのサブジェクト代替名は当然なし。

Chromeのオプションでなんとかならないかと探してみたけど、--allow-insecure-localhost--disable-web-securityなどはうまく動かなかった。

達成したいこと

hostsや社内DNSなどで解決している開発環境ドメインのhttpsページに、Headless Chromeでアクセス可能にすること。

サブで、証明書を発行するたびにキーチェーンアクセスなりcertmgrなりに登録しないでいいように、社内認証局を立てて、そこに証明書を発行させるようにする。

※ドメインは社内DNSで解決している & 本番環境と異なるため、本番環境の証明書をワイルドカードにするとか、Let’s Encrypt使うとかは対策として取れない。

証明書の作り方

前提

  • Chrome 64
  • 証明書を作る環境
    • CentOS 7.4
    • OpenSSL 1.0.2k-fips 26 Jan 2017
  • 鍵、証明書
    • 鍵のパスフレーズは未設定
      • 社内の検証環境で使うことを想定
        • CAの鍵はつけてもよかったかな…
      • Webサーバーで使うため再起動時にパスフレーズを要求させたくない
    • ドメイン
      • example.com
      • www.example.com
  • 設定ファイル

準備

rootユーザーで設定ファイルをダウンロードしておく。これ以降も全てrootユーザーでの実行を想定している。

# mkdir ~/cert
# cd ~/cert/
# curl -O https://gist.githubusercontent.com/nishim/f39fa9ea1d041de66e83f5267b317ea0/raw/752e7c69f405838c6b4e9dc3be98e4a37335830e/openssl.ca.conf
# curl -O https://gist.githubusercontent.com/nishim/8e65e0cc1660c91ea28e809b754dafe7/raw/9df5bc22fc7a2f342a6be52d587ef48d72463130/openssl.server.conf
# curl -O https://gist.githubusercontent.com/nishim/273687cb767595de0f725ef8982176cf/raw/4c8223defd1b039c82d623ebafdb466859346044/openssl.v3-req.ext

CAを構築する

  1. CAの秘密鍵と証明書作成

    # openssl req -new -x509 -keyout ca.key -out ca.crt -days 3650 -config openssl.ca.conf
    
  2. 秘密鍵のアクセス権限設定

    # chmod 600 ca.key
    
  3. 発行する証明書を管理するファイルの作成(存在しない場合のみ作る)

    # ls /etc/pki/CA/index.txt > /dev/null 2>&1 || touch /etc/pki/CA/index.txt
    # ls /etc/pki/CA/serial > /dev/null 2>&1 || echo "1000" > /etc/pki/CA/serial
    

証明書の内容は以下のコマンドで確認できる

# openssl x509 -text -noout -in ca.crt 

サーバー証明書を発行する

  1. サーバーの秘密鍵と証明書署名要求を作成

    # openssl req -new -sha512 -nodes -out server.csr -newkey rsa:4096 -keyout server.key -config openssl.server.conf
    
  2. CAで証明書を発行

    # openssl ca -policy policy_anything -cert ca.crt -keyfile ca.key -out server.crt -extfile openssl.v3-req.ext -infiles server.csr
    
  3. Webサーバーで鍵を使うよう設定変更し再起動
    対象のWebサーバーに秘密鍵とサーバー証明書をコピーし、nginxなりhttpdの設定を変更する。その後再起動

クライアントの証明書ストアにCAの証明書を登録

CAの証明書を各人のクライアントに配布し、MacならキーチェーンアクセスのシステムセクションにD&D、Windowsならcertmgr.mscで「信頼されたルート証明機関」に追加する。 これでChromeで表示するとロケーションバーの端っこが緑で「保護された通信」になるし、Headless Chromeでのアクセスもできた。

今後やる/チェックすること

https://bugs.chromium.org/p/chromium/issues/detail?id=721739

参考