certbot実行時にエラーが出るようになってしまった。原因と対処法のメモ。
現象
certbot実行時に次のようなエラーが出る。
Traceback (most recent call last):
File "/usr/local/bin/certbot", line 33, in <module>
sys.exit(load_entry_point('certbot==1.31.0', 'console_scripts', 'certbot')())
File "/usr/local/bin/certbot", line 25, in importlib_load_entry_point
return next(matches).load()
File "/usr/local/lib/python3.9/importlib/metadata.py", line 86, in load
module = import_module(match.group('module'))
File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/usr/local/lib/python3.9/site-packages/certbot/main.py", line 6, in <module>
from certbot._internal import main as internal_main
File "/usr/local/lib/python3.9/site-packages/certbot/_internal/main.py", line 19, in <module>
import josepy as jose
File "/usr/local/lib/python3.9/site-packages/josepy/__init__.py", line 40, in <module>
from josepy.json_util import (
File "/usr/local/lib/python3.9/site-packages/josepy/json_util.py", line 14, in <module>
from OpenSSL import crypto
File "/usr/local/lib/python3.9/site-packages/OpenSSL/__init__.py", line 8, in <module>
from OpenSSL import crypto, SSL
File "/usr/local/lib/python3.9/site-packages/OpenSSL/crypto.py", line 14, in <module>
from cryptography import utils, x509
File "/usr/local/lib/python3.9/site-packages/cryptography/x509/__init__.py", line 6, in <module>
from cryptography.x509 import certificate_transparency
File "/usr/local/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py", line 10, in <module>
from cryptography.hazmat.bindings._rust import x509 as rust_x509
ImportError: cannot import name 'x509' from 'cryptography.hazmat.bindings._rust' (unknown location)
思い当たる原因は、portmasterでパッケージを更新したこと。
原因
security/py-cryptographyの最新パッケージでは、lang/rustが必須となった。にもかかわらず、rustを含めてビルドするための設定がpy-cryptographyに含まれていないために、エラーが出る。
対処法
取れる対処法は、次のいずれか。
- certbotを捨てて、acme.shに移行する。
- py-cryptographyを38.0.1から3.4.8に戻す。
- py-cryptographyにパッチを当てて、rustと共にビルドする。
- portsのパッケージをアンインストールして、pipでインストールし直す。
- portsが修正されるのを気長に待つ。
acme.shを推す声が割と多い。依存関係が少ないので、トラブルが少ないから。この機会に乗り換えるのもいいかもしれない。
portsもいつかは修正されると思うけど、いつになったら修正されるかは……。修正される前に認証の有効期限が切れそうな気がしてならない。
対処法
acme.shへの移行と、portsの修正待ちについては省略。
py-cryptographyのバージョンを戻す
38.0.1から3.4.8に戻せばcertbotが動くようになる。
パッケージのバージョンを戻すなら、net/gitupを使うのが便利らしい。以前はportdowngradeが使われていたが、ソースのバージョン管理がSVNからgitに切り替わったのにともなって使えなくなった。
ただし、py-cryptographyのバージョンを戻すだけのためにgitupを設定するのもかったるい。というわけで、超邪道だけどpipを使ってお茶を濁すことにした。
# pip install cryptography==3.4.8
ただし、これをやっちゃうと、portmasterで管理されているバージョンと実際にインストールされているバージョンが食い違ってしまう。決してお薦めはできない。でも、とりあえず動くようにはなる。
いっそこれを機会に、Pythonパッケージは全部portsからではなくてpip管理に変更しちゃってもいいかもしれない。
py-cryptographyにパッチを当てる
FreeBSD Bugzillaの「Bug 254853 – security/py-cryptography: Update to 37.0.2」のAttachment「update to 38.0.1 with rust build」をファイルに保存して、次のようにコマンドを実行してパッチを当てる。パッチはRAW_UNIFIED.patchというファイルに保存したものとする。
# sudo patch -p1 --directory /usr/ports/ --input RAW_UNIFIED.patch
# cd /usr/ports/security/py-cryptography
# make install
ただし、このパッチはpy-opensslのバージョン22.00を必要とする。portsから入れたものは20.0なので、pipで更新する必要あり。
# pip install openssl=22.00
パッチを当てた上にpipで別バージョンを入れる必要があるので、py-cryptographyを単純に戻すだけの方が楽だと思う。
pipでインストールし直す
certbot関連のパッケージをすべてアンインストールする、または仮想環境上で、pipを使ってインストールし直せば、cryptographyが最新バージョンでもcertbotでエラーが出ることはない。
部分的にpipでインストールするよりは、もういっそcertbot用の仮想環境を作ってpipで管理する方がいいのかもしれない。
参考
この件に関する報告は、次のとおり。
- Bug 254853 – security/py-cryptography: Update to 37.0.2 (FreeBSD Bugzilla)
- Bug 266937 – security/py-certbot broken in v 1.31.0,1 (FreeBSD Bugzilla)
- certbot ImportError: cannot import name ‘x509’ from ‘cryptography.hazmat.bindings._rust’ (FreeBSD Forum)
- ImportError: cannot import name ‘x509’ from ‘cryptography.hazmat.bindings._rust (Let’s Encrypt community)