プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Let's Encrypt の更新エラー

こちらの記事で書いたサーバーの Let's Encrypt の証明書の更新ですが、cron で自動実行されているので安心と思い込んでいたら、あと20日で有効期限が切れるよ、というメールが先日やってきました。

慌てて、サーバーを確認すると。syslogに更新失敗の記録が載っていました。

Dec 19 06:19:10 ip-xxx-xxx-xxx-xxx systemd[1]: Starting Certbot...
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx certbot[8506]: Attempting to renew cert (サーバーのドメイン名) from /etc/letsencrypt/renewal/サーバーのドメイン名.conf produced an unexpected error: Failed authorization procedure. サーバーのドメイン名 (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from https://サーバーのドメイン名/.well-known/acme-challenge/JDoMfpSsox4bWhzrsYgGLIVN4OUEx0NJHFcdWgL0Wwg [52.199.225.177]: "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p". Skipping.
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx certbot[8506]: All renewal attempts failed. The following certs could not be renewed:
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx certbot[8506]:   /etc/letsencrypt/live/サーバーのドメイン名/fullchain.pem (failure)
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx certbot[8506]: 1 renew failure(s), 0 parse failure(s)
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx systemd[1]: certbot.service: Main process exited, code=exited, status=1/FAILURE
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx systemd[1]: certbot.service: Failed with result 'exit-code'.
Dec 19 06:19:15 ip-xxx-xxx-xxx-xxx systemd[1]: Failed to start Certbot.

このエラーを解決しようとした際にやったことをメモっておきます。

改めてテスト

下記の記事などを参考にもう一度テストしました。

Let&#39;sEncryptの取得&amp;自動更新設定してみた(CentOS7.1&amp;Apache2.4.6) - Qiita

最初は --dry-run つけて試してました。

ubuntu@ip-xxx-xxx-xxx-xxx:/etc/cron.d$ sudo certbot renew --force-renew --dry-run --webroot-path /var/www/html/ドキュメントルート
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/サーバーのドメイン名.conf
-------------------------------------------------------------------------------
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Attempting to renew cert (サーバーのドメイン名) from /etc/letsencrypt/renewal/サーバーのドメイン名.conf produced an unexpected error: urn:ietf:params:acme:error:malformed :: The request message was malformed :: Method not allowed. Skipping.
All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/サーバーのドメイン名/fullchain.pem (failure)

-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/サーバーのドメイン名/fullchain.pem (failure)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
-------------------------------------------------------------------------------
1 renew failure(s), 0 parse failure(s)
ubuntu@ip-xxx-xxx-xxx-xxx:/etc/cron.d$ 

エラーになっていました。 --force-renew かな?と思い、これをはずしても同じ結果。

でも、深く考えずに --dry-run をはずすと、できてしまった・・・

ubuntu@ip-xxx-xxx-xxx-xxx:/etc/cron.d$ sudo certbot renew --webroot-path /var/www/html/ドキュメントルート
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/サーバーのドメイン名.conf
-------------------------------------------------------------------------------
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for サーバーのドメイン名
Using the webroot path /var/www/html/ドキュメントルート for all unmatched domains.
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/サーバーのドメイン名/fullchain.pem
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/サーバーのドメイン名/fullchain.pem (success)
-------------------------------------------------------------------------------
ubuntu@ip-xxx-xxx-xxx-xxx:/etc/cron.d$ 

cron.d でエラーになっていた理由

あとから、考えるとLet's Encrypt の設定ファイル(/etc/letsencrypt/renewal/サーバーのドメイン名.conf)内のwebrootの指定が 実際のフォルダよりも一つ上のフォルダを指していました。

webroot_path = /var/www/html,

どうもこのため、エラーが起きていたようです(ただ、 renew に成功するとこの.confファイルが書き換えられるため、記憶をたどって書いています)。

で、上のコマンドラインで実行時には、正しいwebrootを指定していたので、成功になったようです。

--dry-run でエラーになっていた理由

下記の記事などによると、 --dry-run をつけた場合、0.32 以前の certbot だと、エラーが起きるようなこと書いています。

Problem with renew certificates - The request message was malformed :: Method not allowed - Help - Let's Encrypt Community Support

今の環境だと、0.23 だったようです。多分これですね。

ubuntu@ip-xxx-xxx-xxx-xxx:/var/log$ certbot --version
certbot 0.23.0
ubuntu@ip-xxx-xxx-xxx-xxx:/var/log$ 

まあ、とりあえず更新が動くようになったので、今日のところはこれでOKとします。

Cognito AdminCreateUser で作成したユーザーの仮パスワードのリセット

cognito の小ネタです。

cognito ユーザープールのユーザーを管理者が作成する際に、仮パスワードを発行することができます。

管理者としてのユーザーアカウントの作成 - Amazon Cognito

その仮パスワードの有効期間が切れた場合の再発行方法は、

aws --profile プロファイル名 cognito-idp  admin-create-user
--user-pool-id ユーザープールID --username ユーザー名(メールアドレス)
-user-attributes "[{\"Name\":\"email\",\"Value\":\メールアドレス\"},{\"Name\":\"email_verified\",\"Value\":\"true\"}]"
--desired-delivery-mediums "EMAIL" --message-action RESEND

(適宜改行を入れています)

のように admin-create-user を同じユーザー名を指定して --message-action RESEND を追加して呼ぶだけのようです(CLIでの例になります)。

知らなかったなー。

元ネタはこちら。

How do I reset a Cognito user's password that has expired? - Stack Overflow

リファレンスにもちゃんと書いてありました。

admin-create-user — AWS CLI 1.16.299 Command Reference

pip3 のアップデートに失敗しました

別の記事で書きました、 aws cli からクロスアカウントを使う設定をする際に、いろいろと試していました。

その時、

mor@DESKTOP-H6IEJF9:~$ aws --version
aws-cli/1.16.269 Python/3.6.6 Linux/4.4.0-18362-Microsoft botocore/1.13.5

となっていたので、aws cli を更新してみるかと思い、 一度 aws cli をアップデートしてみました。

まずは、最新版を確認しようとして

mor@DESKTOP-H6IEJF9:~$ pip3 list -o

とすると

mor@DESKTOP-H6IEJF9:~$ pip3 list -o
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
Exception:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/commands/list.py", line 157, in run
    packages = self.get_outdated(packages, options)
  File "/usr/lib/python3/dist-packages/pip/commands/list.py", line 168, in get_outdated
    dist for dist in self.iter_packages_latest_infos(packages, options)
  File "/usr/lib/python3/dist-packages/pip/commands/list.py", line 169, in 
    if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'
mor@DESKTOP-H6IEJF9:~$

エラーとなります。

ググってみると、

exception error when ```pip3 list --outdated``` · Issue #6786 · pypa/pip · GitHub

とのことで、pip3 のバージョンを上げれば修正されてるっぽいです。

ということで、まずは、pip3 を更新してみました。

mor@DESKTOP-H6IEJF9:~$ pip3 install --upgrade pip
Collecting pip
  Cache entry deserialization failed, entry ignored
  Using cached https://files.pythonhosted.org/packages/00/b6/9cfa56b4081ad13874b0c6f96af8ce16cfbc1cb06bedf8e9164ce5551ec1/pip-19.3.1-py2.py3-none-any.whl
Installing collected packages: pip
Successfully installed pip-19.3.1
mor@DESKTOP-H6IEJF9:~$

あれ?pip3 ではなく pip がインストールされたっポイぞ。

mor@DESKTOP-H6IEJF9:~$ pip --version
pip 19.3.1 from /home/mor/.local/lib/python3.6/site-packages/pip (python 3.6)
mor@DESKTOP-H6IEJF9:~$

pip3 はどうなってるんだろうか?

mor@DESKTOP-H6IEJF9:~$ pip3 --version
Traceback (most recent call last):
  File "/usr/bin/pip3", line 9, in 
    from pip import main
ImportError: cannot import name 'main'
mor@DESKTOP-H6IEJF9:~$

エラーになってる・・・。

まあ、気にせず、 pip で更新してみると

mor@DESKTOP-H6IEJF9:~$ pip install --upgrade awscli
(中略)
ERROR: Could not install packages due to an EnvironmentError: [Errno 13] 許可がありません: '/usr/local/lib/python3.6/dist-packages/botocore'
Consider using the `--user` option or check the permissions.

mor@DESKTOP-H6IEJF9:~$

途中でエラーになります。 やっちゃったようです。

まあ、よくよく考えてみると、原因は、pip3 は apt 経由でパッケージで入れてるので、これと、 pip3 自身でアップデートしたものが齟齬をきたしてるみたいです。

【Ubuntu】pip install –upgrade pip コマンドを実行すると、その後、ImportError: cannot import name main というエラーが発生する場合の対応方法 | ラボラジアン

下記を参考に復旧します。

Python pip3 - pip upgradeした後 「cannot import name 'main' 」error - KOKENSHAの技術ブログ

mor@DESKTOP-H6IEJF9:~$ sudo python3 -m pip uninstall pip
WARNING: The directory '/home/mor/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Uninstalling pip-19.3.1:
  Would remove:
    /home/mor/.local/bin/pip
    /home/mor/.local/bin/pip3
    /home/mor/.local/bin/pip3.6
    /home/mor/.local/lib/python3.6/site-packages/pip-19.3.1.dist-info/*
    /home/mor/.local/lib/python3.6/site-packages/pip/*
Proceed (y/n)? y
  Successfully uninstalled pip-19.3.1
mor@DESKTOP-H6IEJF9:~$ sudo apt install python3-pip --reinstall

もう一度pip3を動かしてみます。

mor@DESKTOP-H6IEJF9:~$ pip3 --version
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
mor@DESKTOP-H6IEJF9:~$ aws --version
aws-cli/1.16.269 Python/3.6.6 Linux/4.4.0-18362-Microsoft botocore/1.13.5
mor@DESKTOP-H6IEJF9:~$

ふー、とりあえず元に戻せたようです。

まあ、最終的に aws cli のバージョンの問題ではなくMFAの設定の問題だったので、 pip3 も aws cli もいまのままとしておきます。

とはいえ、いずれはどこかで、pip3 の再インストールからしないといけないようですね。