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

时间:2019-10-24 20:15:05

标签: 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"
}

Cloudwatch错误

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.

功能

...
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,
        });
    });
...

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

5 个答案:

答案 0 :(得分:6)

我尝试了@Kris White记录的answer,但无法使其正常工作。每次执行都会导致错误Could not find openssl on your system on this path: /opt/openssl。我尝试了几种不同的途径和方法,但是都没有奏效。完全有可能我只是没有正确地复制OpenSSL可执行文件。

由于我需要一个可行的解决方案,因此我使用了@Wilfred Dittmer提供的answer。由于未使用Docker,因此对其进行了一些修改。我启动了Amazon Linux 2服务器,在其上构建了OpenSSL,将程序包转移到我的本地计算机上,并通过Serverless进行了部署。


创建一个包含以下内容的名为create-openssl-zip.sh的文件。该脚本将创建Lambda Layer 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

然后,请按照下列步骤操作:

  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 Instances list
  5. 使用以下属性启动新实例:
    1. AMI:Amazon Linux 2 AMI(HVM),SSD卷类型(id:ami-0a887e401f7654935)
    2. 实例类型:t2.micro
    3. 实例详细信息:(使用所有默认设置)
    4. 存储:(使用所有默认设置)
    5. 标签:名称-'build-lambda-layer-openssl'
    6. 安全组:“创建新的安全组”(使用所有默认设置,以确保可以通过SSH通过Internet公开访问实例)
  6. 启动实例并选择密钥对时,请确保从您有权访问的列表中选择一个密钥对。
  7. 启动实例并等待其可访问。
  8. 实例运行后,请使用SSH客户端连接到实例。
    • 有关如何打开SSH连接的更多详细信息,请参见here
  9. 在SSH终端会话中,通过运行tmp导航到cd /tmp目录。
  10. 通过运行curl {FILE_IO_URL} --output create-openssl-zip.sh下载先前上传的bash脚本。
    • 注意:在上面的脚本中,将FILE_IO_URL替换为File.io返回并在步骤3中复制的URL。
  11. 通过运行sudo bash ./create-openssl-zip.sh执行bash脚本。该脚本可能需要一段时间才能完成。您可能需要确认一个或多个软件包安装提示。
  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 list中,终止build-lambda-layer-openssl EC2实例,因为不再需要它。
  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

...这是我在代码文件中配置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...

答案 1 :(得分:1)

PEM NPM文档说:

  

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

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

#Replicate data frame
UserID <- c(1, 1, 1, 1, 2, 2)
SessionID <- c(1.1, 1.1, 1.1, 1.1, 2.1, 2.1)
TimeStamp <- c(1, 2, 3, 4, 5, 6)
PagePath <-
  c(
    "google.com",
    "google.com/products",
    "google.com/info",
    "google.com/purchase",
    "google.com",
    "google.com/info"
  )
PageViews <- c(1, 1, 1, 1, 1, 1)
df <- data.frame(UserID, SessionID, TimeStamp, PagePath, PageViews)

在使用AWS Lambda时,只需尝试打印var pem = require('pem') pem.config({ pathOpenSSL: '/usr/local/bin/openssl' }) ,您将了解路径路径env变量中是否包含OpenSSL。

您还可以通过运行以下代码

来检查“ OpenSSL”
process.env.path

更新

正如@hoangdv在他的答案中提到的openssl似乎已在node10.x运行时中删除,我认为他是对的。另外,我们对文件系统具有只读访问权限,因此我们无法做很多事情。

@Seth McClaine,您可以尝试使用const exec = require('child_process').exec; exec('which openssl',function(err,stdopt,stderr){ console.log(err ? err : stdopt); }) npm模块。在此基础上构建的模块之一是“ https://github.com/jfromaniello/selfsigned”,它将使您的任务更加轻松

答案 2 :(得分:1)

https://github.com/lambci/git-lambda-layer/issues/13#issue-444697784(公告电子邮件)

似乎openssl已在nodejs10.x运行时中删除。

我再次检查了lambci/lambda:build-nodejs10.x码头工人镜像,并确认了这一点。也许您需要更改运行时版本或找到另一种createCSR的方式。

which: no openssl in (/var/lang/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin)

答案 3 :(得分:0)

您可以做的是使用openssl库创建一个lambda层。 使用lambdaci / lambda:build-nodejes10.x,您可以编译openssl库并从安装中创建一个zip文件。然后,您可以将zip文件用作lambda的图层。

创建一个名为create-openssl-zip.sh的文件,并确保将其chmod u + x。

#!/bin/bash -x

# This file should be run inside the lambci/lambda:build-nodejs10.x container
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=/var/task/nodejs/openssl --openssldir=/var/task/nodejs/openssl && make && make install
cd /var/task/
rm -rf nodejs/openssl/share
rm -rf nodejs/openssl/include
zip -r lambda-openssl-layer.zip nodejs
cp lambda-openssl-layer.zip /opt/layer/

然后运行:

docker run -it -v `pwd`:/opt/layer lambci/lambda:build-nodejs10.x /opt/layer/create-openssl-zip.sh

这将在docker容器中运行脚本,完成后,您在当前目录中会有一个名为lambda-openssl-layer.zip的文件。

将此lambda上载到s3存储桶并创建lambda层。 在原始的lambda上,添加此层并修改代码,以使PEM库知道在何处查找OpenSSL库,如下所示:

PEM.config({
  pathOpenSSL: '/opt/nodejs/openssl/bin/openssl'
})

最后,将一个名为LD_LIBRARY_PATH的额外环境变量添加到您的lambda中,其值为/opt/nodejs/openssl/lib

否则它将失败并显示: /opt/nodejs/openssl/bin/openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory

答案 4 :(得分:0)

我联系了AWS支持有关此问题,结果发现openssl库仍在Node10x映像上,而不是命令行实用程序上。但是,将其从标准AMI上抓取并将其用作Lambda层是很容易的。

步骤:

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

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