PythonでOSError: Cannot load native module 'Crypto.Hash._MD5'が出た

Python 3.8ランタイムで動かしていたAWS Lambda関数でエラーが出たので対応した際のメモ。

一年後の自分に向けて。

 

 

[OSError: Cannot load native module]

AWS Lambdaがエラーを吐いて、CloudWatch Logsにこんなエラーメッセージが出ていた。

[ERROR] OSError: Cannot load native module 'Crypto.Hash._MD5': Trying '_MD5.cpython-38-x86_64-linux-gnu.so': /var/task/vendor/Crypto/Util/../Hash/_MD5.cpython-38-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory, Trying '_MD5.abi3.so': /var/task/vendor/Crypto/Util/../Hash/_MD5.abi3.so: cannot open shared object file: No such file or directory, Trying '_MD5.so': /var/task/vendor/Crypto/Util/../Hash/_MD5.so: cannot open shared object file: No such file or directory
Traceback (most recent call last):
  File "/var/lang/lib/python3.8/imp.py", line 234, in load_module
    return load_source(name, filename, file)
  File "/var/lang/lib/python3.8/imp.py", line 171, in load_source
    module = _load(spec)
  File "<frozen importlib._bootstrap>", line 702, in _load
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 843, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/var/task/my-lambda-func.py", line 15, in <module>
    from Crypto.PublicKey import RSA
  File "/var/task/vendor/Crypto/PublicKey/RSA.py", line 38, in <module>
    from Crypto.IO import PKCS8, PEM
  File "/var/task/vendor/Crypto/IO/PKCS8.py", line 44, in <module>
    from Crypto.IO._PBES import PBES1, PBES2, PbesError
  File "/var/task/vendor/Crypto/IO/_PBES.py", line 41, in <module>
    from Crypto.Hash import MD5, SHA1, SHA224, SHA256, SHA384, SHA512
  File "/var/task/vendor/Crypto/Hash/MD5.py", line 29, in <module>
    _raw_md5_lib = load_pycryptodome_raw_lib("Crypto.Hash._MD5",
  File "/var/task/vendor/Crypto/Util/_raw_api.py", line 300, in load_pycryptodome_raw_lib
    raise OSError("Cannot load native module '%s': %s" % (name, ", ".join(attempts)))

 

requirements.txtの記載はこう。

pycryptodome==3.8.2

 

実際のコードはこんな感じ。

from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256

def lambda_handler(event, context):
(略) h = SHA256.new() h.update(plain_text.encode()) signature_scheme = RSA.importKey(key) signer = PKCS1_v1_5.new(signature_scheme) signer.sign(h)
(略)

 

[原因と対策]

エラーメッセージで検索すると、こちらのスレッドにたどり着いた。

AWS Lambda “Cannot load native module 'Cryptodome.Hash._MD5'”

 

詳細は自分の遭遇した事象とは違っていそうだが、大筋では同じようだ。

ようするに、C言語で書かれたネイティブモジュールを利用している部分があるせいか、Pythonのバージョンとプラットフォームが同じでないとエラーが出る、ということらしい。

 

Lambda関数のランタイムを確認すると、Python 3.8を指定していた。ここはエラー発生前から変更されていない。

ビルドとデプロイを行っているパイプラインの直近のログを確認すると、Python 3.9がどうの、というログが目に入った。以前のデプロイのログでは、この部分はPython 3.8と出力されていた。

慌ててパイプラインのソースコードを確認すると、ランタイムのPythonバージョン指定が漏れていた。このズレが原因だろう。

 

というわけで、Lambda関数を動かすために、Lambda関数のランタイムをPython 3.9に更新したところ、問題なく従前通りに動作した。

 

Pythonのリリースサイクルを確認したところ、2019年からは毎年新バージョンをリリース、ということになっているようだ。

www.python.org

 

このままいくと一年後にまた同じことが起きそうだったので、パイプラインのPythonランタイムバージョンも3.9でとりあえず固定しておいた。

 

1年後くらいに、AWS Lambda関数のPython 3.10ランタイムが使えるようになってたらそれぞれ更新せねば。

 

[まとめ]

  • Pythonのビルド環境と実行環境のランタイムバージョンはそろえよう
  • 2019年以降Pythonは毎年リリースされるので、毎年バージョンアップが必要そう