Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
518 views
in Technique[技术] by (71.8m points)

node.js - NPM package `pem` doesn't seem to work in AWS lambda NodeJS 10.x (results in OpenSSL error)

When I run the function locally on NodeJS 11.7.0 it works, when I run it in AWS Lambda NodeJS 8.10 it works, but I've recently tried to run it in AWS Lambda NodeJS 10.x and get this response and this error in Cloud Watch.

Any thoughts on how to correct this?

Response

{
    "success": false,
    "error": "Error: Could not find openssl on your system on this path: openssl"
}

Cloudwatch Error

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.

Function

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

I've tried with "pem": "^1.14.3", and "pem": "^1.14.2",

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I tried the answer documented by @Kris White, but I was not able to get it to work. Each execution resulted in the error Could not find openssl on your system on this path: /opt/openssl. I tried several different paths and approaches, but none worked well. It's entirely possible that I simply didn't copy the OpenSSL executable correctly.

Since I needed a working solution, I used the answer provided by @Wilfred Dittmer. I modified it slightly since I wasn't using Docker. I launched an Amazon Linux 2 server, built OpenSSL on it, transferred the package to my local machine, and deployed it via Serverless.


Create a file named create-openssl-zip.sh with the following contents. The script will create the Lambda Layer OpenSSL package.

#!/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

Then, follow these steps:

  1. Open a terminal session in this project's root folder.
  2. Run the following command to upload the Linux bash script.
    • curl -F "file=@create-openssl-zip.sh" https://file.io
    • Note: The command above uses the popular tool File.io to copy the script to the cloud temporarily so it can be securely retrieved from the build server.
    • Note: If curl is not installed on your dev machine, you can also upload the script manually using the File.io website.
  3. Copy the URL for the uploaded file from either the terminal session or the File.io website.
    • Note: The url will look similar to this example: https://file.io/a1B2c3
  4. Open the AWS Console to the EC2 Instances list.
  5. Launch a new instance with these attributes:
    1. AMI: Amazon Linux 2 AMI (HVM), SSD Volume Type (id: ami-0a887e401f7654935)
    2. Instance Type: t2.micro
    3. Instance Details: (use all defaults)
    4. Storage: (use all defaults)
    5. Tags: Name - 'build-lambda-layer-openssl'
    6. Security Group: 'Create new security group' (use all defaults to ensure Instance will be publicly accessible via SSH over the internet)
  6. When launching the instance and selecting a key pair, be sure to choose a Key Pair from the list to which you have access.
  7. Launch the instance and wait for it to be accessible.
  8. Once the instance is running, use an SSH Client to connect to the instance.
    • More details on how to open an SSH connection can be found here.
  9. In the SSH terminal session, navigate to the tmp directory by running cd /tmp.
  10. Download the bash script uploaded earlier by running curl {FILE_IO_URL} --output create-openssl-zip.sh.
    • Note: In the script above, replace FILE_IO_URL with the URL returned from File.io and copied in step 3.
  11. Execute the bash script by running sudo bash ./create-openssl-zip.sh. The script may take a while to complete. You may need to confirm one or more package install prompts.
  12. When the script completes, run the following command to upload the package to File.io: curl -F "file=@lambda-layer-openssl.zip" https://file.io.
  13. Copy the URL for the uploaded file from the terminal session.
  14. In the terminal session on the local development machine, run the following command to download the file: curl {FILE_IO_URL} --output lambda-layer-openssl.zip.
    • Note: In the script above, replace FILE_IO_URL with the URL returned from File.io and copied in step 13.
    • Note: If curl is not installed on your dev machine, you can also download the file manually by pasting the copied URL in the address bar of your favorite browser.
  15. Close the SSH session.
  16. In the EC2 Instances list, terminate the build-lambda-layer-openssl EC2 instance since it is not needed any longer.
  17. The OpenSSL Lambda Layer is now ready to be deployed.

For completeness, here is a portion of my serverless.yml file:

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: 'patholambda-layer-openssl.zip'
    compatibleRuntimes: 
      - nodejs10.x
      - nodejs12.x
    retain: false

...and here is how I configured PEM in the code file:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...