NPM 包 `pem` 在 AWS lambda NodeJS 10.x 中似乎不起作用(导致 OpenSSL 错误)

Set*_*ine 6 node.js aws-lambda

当我在本地运行该函数时,NodeJS 11.7.0它可以工作,当我在AWS Lambda NodeJS 8.10其中运行它时,它可以工作,但我最近尝试运行它AWS Lambda NodeJS 10.x并在 Cloud Watch 中获得此响应和此错误。

关于如何纠正这个问题的任何想法?

回复

{
    "success": false,
    "error": "Error: Could not find openssl on your system on this path: openssl"
}
Run Code Online (Sandbox Code Playgroud)

云监视错误

ERROR (node:8) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
Run Code Online (Sandbox Code Playgroud)

功能

...
const util = require('util');
const pem = require('pem');
...

return new Promise((fulfill) => {
        require('./certs').get(req, res, () => {
            return fulfill();
        });
    }).then(() => {
        const createCSR = util.promisify(pem.createCSR);

        //This seems to be where the issue is coming from 
        return createCSR({
            keyBitsize: 1024,
            hash: HASH,
            commonName: id.toString(),
            country: 'US',
            state: 'Maryland',
            organization: 'ABC', //Obfuscated 
            organizationUnit: 'XYZ', //Obfuscated
        });
    }).then(({ csr, clientKey }) => {
        ...
    }).then(async ({ certificate, clientKey }) => {
        ...
    }, (err) => {
        return res.status(404).json({
            success: false,
            error: err,
        });
    });
...

Run Code Online (Sandbox Code Playgroud)

我试过 "pem": "^1.14.3","pem": "^1.14.2",

Pfl*_*ugs 6

我尝试了@Kris White 记录的答案,但我无法让它发挥作用。每次执行都会导致错误Could not find openssl on your system on this path: /opt/openssl。我尝试了几种不同的路径和方法,但没有一个效果很好。我完全有可能只是没有正确复制 OpenSSL 可执行文件。

由于我需要一个有效的解决方案,我使用了@Wilfred Dittmer 提供的答案。因为我没有使用 Docker,所以我稍微修改了它。我启动了一个 Amazon Linux 2 服务器,在其上构建了 OpenSSL,将包传输到我的本地机器,并通过 Serverless 进行部署。


创建一个以create-openssl-zip.sh以下内容命名的文件。该脚本将创建 Lambda 层 OpenSSL 包。

#!/bin/bash -x

# This file should be copied to and run inside the /tmp folder
yum update -y
yum install autoconf bison gcc gcc-c++ libcurl-devel libxml2-devel -y
curl -sL http://www.openssl.org/source/openssl-1.1.1d.tar.gz | tar -xvz
cd openssl-1.1.1d
./config --prefix=/tmp/nodejs/openssl --openssldir=/tmp/nodejs/openssl && make && make install
cd /tmp
rm -rf nodejs/openssl/share nodejs/openssl/include
zip -r lambda-layer-openssl.zip nodejs
rm -rf nodejs openssl-1.1.1d
Run Code Online (Sandbox Code Playgroud)

然后,按照以下步骤操作:

  1. 在此项目的根文件夹中打开一个终端会话。
  2. 运行以下命令上传Linux bash 脚本。
    • curl -F "file=@create-openssl-zip.sh" https://file.io
    • 注意:上面的命令使用流行的工具File.io将脚本临时复制到云端,以便可以从构建服务器安全地检索它。
    • 注意:如果curl您的开发机器上没有安装,您也可以使用 File.io 网站手动上传脚本。
  3. 从终端会话或 File.io 网站复制上传文件的 URL。
    • 注意:该 url 将类似于此示例: https://file.io/a1B2c3
  4. 打开 AWS 控制台到EC2 实例列表
  5. 启动具有以下属性的新实例:
    1. AMI:Amazon Linux 2 AMI (HVM),SSD 卷类型(id:ami-0a887e401f7654935)
    2. 实例类型:t2.micro
    3. 实例详细信息:(使用所有默认值)
    4. 存储:(使用所有默认值)
    5. 标签:名称 - 'build-lambda-layer-openssl'
    6. 安全组:“创建新的安全组”(使用所有默认值以确保实例可通过互联网上的 SSH 公开访问)
  6. 启动实例并选择密钥对时,请务必从您有权访问的列表中选择一个密钥对。
  7. 启动实例并等待它可以访问。
  8. 实例运行后,使用 SSH 客户端连接到实例。
    • 可以在此处找到有关如何打开 SSH 连接的更多详细信息。
  9. 在 SSH 终端会话中,tmp通过运行导航到目录cd /tmp
  10. 通过运行下载之前上传的 bash 脚本curl {FILE_IO_URL} --output create-openssl-zip.sh
    • 注意:在上面的脚本中,替换FILE_IO_URL为从 File.io 返回并在步骤 3 中复制的 URL。
  11. 通过运行执行 bash 脚本sudo bash ./create-openssl-zip.sh。脚本可能需要一段时间才能完成。您可能需要确认一个或多个软件包安装提示。
  12. 脚本完成后,运行以下命令将包上传到 File.io:curl -F "file=@lambda-layer-openssl.zip" https://file.io.
  13. 从终端会话复制上传文件的 URL。
  14. 在本地开发机器上的终端会话中,运行以下命令下载文件:curl {FILE_IO_URL} --output lambda-layer-openssl.zip.
    • 注意:在上面的脚本中,替换FILE_IO_URL为从 File.io 返回并在步骤 13 中复制的 URL。
    • 注意:如果curl您的开发机器上没有安装该文件,您也可以通过将复制的 URL 粘贴到您喜欢的浏览器的地址栏中来手动下载该文件。
  15. 关闭 SSH 会话。
  16. EC2 Instances 列表中,终止build-lambda-layer-opensslEC2 实例,因为不再需要它。
  17. OpenSSL Lambda 层现在可以部署了。

为了完整起见,这是我的serverless.yml文件的一部分:

functions:
  functionName:
    # ...
    layers:
      - { Ref: OpensslLambdaLayer }

layers:
  openssl:
    name: ${self:provider.stage}-openssl
    description: Contains openssl command line utility for lambdas that need it
    package:
      artifact: 'path\to\lambda-layer-openssl.zip'
    compatibleRuntimes: 
      - nodejs10.x
      - nodejs12.x
    retain: false
Run Code Online (Sandbox Code Playgroud)

...这是我在代码文件中配置 PEM 的方式:

import * as pem from 'pem';
process.env.LD_LIBRARY_PATH = '/opt/nodejs/openssl/lib';
pem.config({
    pathOpenSSL: '/opt/nodejs/openssl/bin/openssl',
});
// other code...
Run Code Online (Sandbox Code Playgroud)


Kri*_*ite 5

我就此事联系了 AWS Support,结果发现 openssl 库仍在 Node10x 映像上,只是不在命令行实用程序上。然而,从标准 AMI 中获取它并将其用作 Lambda 层非常容易。

脚步:

  1. 启动 Amazon Linux 2 AMI 作为 EC2
  2. 通过 SSH 连接到盒子,或使用 SFTP 实用程序连接到盒子
  3. 将 openssl 的命令行实用程序复制到 /usr/bin/openssl 中您可以在本地使用它的位置。就我而言,即使它是 Linux 文件,我也将其下载到我的 Mac 上。
  4. 验证它是否仍标记为可执行文件(如果您已在其他地方下载了它,则如有必要,请使用 chmod a+x openssl)
  5. 压缩文件
  6. 可选:将其上传到您可以访问的 S3 存储桶
  7. 转到 AWS 控制台中的 Lambda 层
  8. 创建一个新的 lambda 层。我将我的命名为 openssl 并使用 S3 指针指向 S3 上的文件。如果本地文件系统上有 zip 文件,您也可以直接上传它。
  9. 将为该层提供的 arn 附加到您的 Lambda 函数。我使用无服务器,因此它是在每个文档的功能设置中定义的。
  10. 在您的代码中,将 openssl 引用为 /opt/openssl 或者您可以通过将 /opt 添加到您的路径来避免在代码中对其进行路径处理(或者如果它是您无法控制的包,则可能没有选项),即
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'] + ':/opt';
Run Code Online (Sandbox Code Playgroud)

该层将已为您解压缩,并且由于您事先将其设置为可执行,因此它应该可以正常工作。底层的 openssl 库就在那里,所以只需复制 cli 就可以了。


San*_*tel 2

PEM NPM 文档说:

设置 openssl 位置 在某些系统中,openssl 可执行文件可能无法以默认名称使用,或者未包含在 $PATH 中。在这种情况下,您可以在加载 pem 模块后将可执行文件的位置定义为一次性操作:

所以我认为它无法在系统中找到 OpenSSL 路径,您可以尝试以编程方式配置它:

var pem = require('pem')
pem.config({
  pathOpenSSL: '/usr/local/bin/openssl'
}) 
Run Code Online (Sandbox Code Playgroud)

由于您正在使用 AWS Lambda,因此只需尝试打印process.env.path您就会了解 OpenSSL 是否包含在路径环境变量中。

您还可以通过运行以下代码来检查“OpenSSL”

const exec = require('child_process').exec;
exec('which openssl',function(err,stdopt,stderr){
      console.log(err ? err : stdopt);    
})
Run Code Online (Sandbox Code Playgroud)

更新

正如 @hoangdv 在他的回答中提到的,openssl 似乎已在 node10.x 运行时被删除,我认为他是对的。此外,我们对文件系统具有只读访问权限,因此我们无能为力。

@Seth McClaine,你可以尝试node-forgenpm 模块。在此基础上构建的模块之一是“ https://github.com/jfromaniello/selfsigned ”,这将使您的任务更轻松

  • 即使 OpenSSL 模块也无法工作,因为内部使用系统 OpenSSL。您可以检查此https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html。或者您将不得不切换到 Lambda 的其他运行时 (2认同)