AWS LambdaでOpenSSLを使う方法
AWS Lambdaの最新のランタイムではAmazon Linux 2が使われていて、OpenSSLパッケージを見つける事ができません。このような環境でOpenSSLコマンドを使う方法を説明します。
OpenSSLコマンドの確認
ランタイムがPython3.8(Amazon Linux 2)のLambda関数でOpenSSLコマンドを実行してみました。
import subprocess def lambda_handler(event, context): output = subprocess.run(['openssl', 'version'], stdout=subprocess.PIPE) print(output.stdout.decode())
コンソールにコマンドが見つからない場合のエラーが出力されます。
{ "errorMessage": "[Errno 2] No such file or directory: 'openssl'", "errorType": "FileNotFoundError", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 4, in lambda_handler\n output = subprocess.run(['openssl', 'version'], stdout=subprocess.PIPE)\n", " File \"/var/lang/lib/python3.8/subprocess.py\", line 489, in run\n with Popen(*popenargs, **kwargs) as process:\n", " File \"/var/lang/lib/python3.8/subprocess.py\", line 854, in __init__\n self._execute_child(args, executable, preexec_fn, close_fds,\n", " File \"/var/lang/lib/python3.8/subprocess.py\", line 1702, in _execute_child\n raise child_exception_type(errno_num, err_msg, err_filename)\n" ] }
ランタイムがPython3.7(Amazon Linux)のLambda関数では、OpenSSLのバージョンが出力されます。
OpenSSL 1.0.2k-fips 26 Jan 2017
AWS LambdaのランタイムとOS
OSにAmazon Linux 2を使用しているランタイムでOpenSSLを利用するためには、EC2のインスタンスからOpenSSLのバイナリを取得して、Lambdaにデプロイする必要があります。
Node.jsのランタイム
名前 | 識別子 | AWS SDK for JavaScript | オペレーティングシステム |
---|---|---|---|
Node.js 12 | nodejs12.x |
2.585.0 | Amazon Linux 2 |
Node.js 10 | nodejs10.x |
2.585.0 | Amazon Linux 2 |
Pythonのランタイム
名前 | 識別子 | AWS SDK for Python | オペレーティングシステム |
---|---|---|---|
Python 3.8 | python3.8 |
boto3-1.10.34 botocore-1.13.34 | Amazon Linux 2 |
Python 3.7 | python3.7 |
boto3-1.10.34 botocore-1.13.34 | Amazon Linux |
Python 3.6 | python3.6 |
boto3-1.10.34 botocore-1.13.34 | Amazon Linux |
Python 2.7 | python2.7 |
boto3-1.10.34 botocore-1.13.34 | Amazon Linux |
OpenSSLのバイナリを取得
EC2でAmazon Linux 2 AMIのインスタンスを立ち上げます。
インスタンスにSSHで接続して、OpenSSLパッケージのパスを確認します。
$ which openssl /usr/bin/openssl
SCPでローカルに保存します。
$ mkdir openssl $ scp -i <鍵ファイルのパス> ec2-user@xxx.xxx.xxx.xxx:/usr/bin/openssl ./openssl
Lambdaレイヤーを作成
先ほどローカルに保存したOpenSSLのバイナリをZIPファイルにします。
$ zip -r openssl.zip openssl/
Lambdaレイヤーを作成します。
Lambda関数を作成
新しくLambda関数を作成して、Lambdaレイヤーを設定します。
LambdaレイヤーのPATHを追加して、OpensSSLコマンドを実行します。
import os import subprocess os.environ['PATH'] = os.environ['PATH'] + ':/opt/openssl' def lambda_handler(event, context): output = subprocess.run(['openssl', 'version'], stdout=subprocess.PIPE) print(output.stdout.decode())
OpenSSLのバージョンが出力されます。
OpenSSL 1.0.2k-fips 26 Jan 2017
まとめ
Lambda関数で秘密鍵や証明書を作成しようとした際に、最新のランタイムでOpenSSLコマンドが使えなくて困りました。他にもOS依存のパッケージをLambdaで使いたい場合は、Lambdaと同じOS(Amazon Linux)をEC2で立ち上げて、バイナリをLambdaレイヤーにデプロイする事で実行できるようになるかと思います。