docker
acme
letsencrypt
https-portal

https-portalのVerが1.2.0未満だと証明書の取得に失敗する

現象の内容

  • 手軽にLet's Encryptの証明書を取得できる「https-portal」というdockerイメージがありますが、こちらのVerが1.2.0未満だとコンテナ起動時に証明書の取得エラーが発生し、リトライでコンテナが再起動を繰り返します。
  • v1.2.0未満でも証明書の再取得が行われるまでは正常に動作しますが、コンテナの再起動や証明書の有効期限切れで証明書の更新が走った時にエラーが発生します。
  • つまり、imageのアップデートを行っていないと、ある日突然https-portalコンテナがエラーを吐いて再起動を繰り返す(=https-portalはリバースプロキシとして動作させることが主なので、https-portal配下のサーバにアクセスできなくなる)という悪夢のような事態が発生します。

原因

  • https-portalはacme-tinyというLet's Encryptの証明書自動認証/更新スクリプトを使用していますが、2017年11月15日頃にACMEプロトコルの"Provided agreement URL"の更新が行われており、acme-tinyがこのURLをハードコーディングしていたのが原因のようです。
  • 詳しくは以下のIssueを参照。

対策

https-portalのイメージをv1.2.0以上にしてください。
Quick Startにも書かれていますが、以下のように指定すると1系で最新のバージョンのイメージを取得してくれます。

docker-compose.yml
https-portal:
  image: steveltn/https-portal:1

まとめ

dockerイメージに限らず各種ライブラリなど外部に依存するものは、重大な仕様変更や不具合が発生していないか等、情報収集を欠かさないようにしたいですね。

おまけ

  • 下記の環境でのコンテナ起動時のエラーログ、解決後のログを残しておきます。
    • ホスト:QNAP TS251+(ファームウェアVer:4.3.3.0229)
    • docker v1.11.2
エラーログ(https-portal_v1.0.0)
[fix-attrs.d] applying owners & permissions fixes...
[fix-attrs.d] 00-runscripts: applying...
[fix-attrs.d] 00-runscripts: exited 0.
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 00-setup: executing...
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
...........................(省略)......++*++*
Generating RSA private key, 4096 bit long modulus
..............................................................................................................................................++
.........................++
e is 65537 (0x10001)
2017/11/28 11:10:23 [notice] 126#126: signal process started
Generating RSA private key, 2048 bit long modulus
....................+++
...............................+++
e is 65537 (0x10001)
Signing certificates from https://acme-v01.api.letsencrypt.org ...
Parsing account key...
Parsing CSR...
Registering account...
Traceback (most recent call last):
  File "/bin/acme_tiny", line 198, in <module>
    main(sys.argv[1:])
  File "/bin/acme_tiny", line 194, in main
    signed_crt = get_crt(args.account_key, args.csr, args.acme_dir, log=LOGGER, CA=args.ca)
  File "/bin/acme_tiny", line 92, in get_crt
    raise ValueError("Error registering: {0} {1}".format(code, result))
ValueError: Error registering: 400 {
  "type": "urn:acme:error:malformed",
  "detail": "Provided agreement URL [https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf] does not match current agreement URL [https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf]";,
  "status": 400
}
2017/11/28 11:10:24 [emerg] 141#141: SSL_CTX_use_PrivateKey_file("/var/lib/https-portal/{サーバドメイン}/production/domain.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
nginx: [emerg] SSL_CTX_use_PrivateKey_file("/var/lib/https-portal/{サーバドメイン}/production/domain.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
Signed key for {サーバドメイン}
2017/11/28 11:10:24 [emerg] 142#142: SSL_CTX_use_PrivateKey_file("/var/lib/https-portal/{サーバドメイン}/production/domain.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
nginx: [emerg] SSL_CTX_use_PrivateKey_file("/var/lib/https-portal/{サーバドメイン}/production/domain.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
[cont-init.d] 00-setup: exited 0.
[cont-init.d] 10-set-docker-gen-status: executing...
[cont-init.d] 10-set-docker-gen-status: exited 0.
[cont-init.d] done.
[services.d] starting services
[services.d] done.
Starting crond ...
2017/11/28 11:10:26 [emerg] 171#171: SSL_CTX_use_PrivateKey_file("/var/lib/https-portal/{サーバドメイン}/production/domain.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
nginx: [emerg] SSL_CTX_use_PrivateKey_file("/var/lib/https-portal/{サーバドメイン}/production/domain.key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
[cont-finish.d] executing container finish scripts...
[cont-finish.d] done.
[s6-finish] syncing disks.
[s6-finish] sending all processes the TERM signal.
[s6-finish] sending all processes the KILL signal and exiting.
エラー解決後のログ(https-portal_v1.2.1)
[fix-attrs.d] applying owners & permissions fixes...
[fix-attrs.d] 00-runscripts: applying...
[fix-attrs.d] 00-runscripts: exited 0.
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 00-welcome: executing...
========================================
HTTPS-PORTAL v1.2.1
========================================
[cont-init.d] 00-welcome: exited 0.
[cont-init.d] 10-setup: executing...
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
.......................+..........(省略).....++*++*
Generating RSA private key, 4096 bit long modulus
......................................++
......................................................................................................++
e is 65537 (0x010001)
2017/11/28 11:23:55 [notice] 139#139: signal process started
Generating RSA private key, 2048 bit long modulus
............................+++
......................................................+++
e is 65537 (0x010001)
Signing certificates from https://acme-v01.api.letsencrypt.org ...
Parsing account key...
Parsing CSR...
Registering account...
Registered!
Verifying {サーバドメイン}...
{サーバドメイン} verified!
Signing certificate...
Certificate signed!
2017/11/28 11:24:03 [notice] 158#158: signal process started
Signed key for {サーバドメイン}
2017/11/28 11:24:03 [notice] 159#159: signal process started
[cont-init.d] 10-setup: exited 0.
[cont-init.d] 20-set-docker-gen-status: executing...
[cont-init.d] 20-set-docker-gen-status: exited 0.
[cont-init.d] done.
[services.d] starting services
[services.d] done.
Starting crond ...