我正在尝试连接到SFTP服务器并列出/ARCHIVE
文件夹中的文档。凭据存储在 .env 文件中。当我在本地计算机上运行它时,它可以工作并列出文档。
async function main (event){
let Client = require('ssh2-sftp-client');
let sftp = new Client();
const dotenv = require('dotenv');
dotenv.config();
const ftpOptions = {
host: process.env.FTP_HOST,
port: process.env.FTP_PORT,
username: process.env.FTP_USER,
password: process.env.FTP_PASSWORD,
debug: console.log
}
await sftp.connect(ftpOptions);
let documentList = await sftp.list('/ARCHIVE');
console.log(documentList);
sftp.end();
}
但是,如果我在我的 AWS lambda 函数中尝试它,它会尝试连接并超时。env 变量在执行sftp.connect(ftpOptions)
之前加载并可用。日志显示该函数正在尝试连接到服务器,但甚至无法使用凭据登录。
Function Logs:
START RequestId: 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e Version: $LATEST
2020-06-04T08:27:12.837Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO Debugging turned on
2020-06-04T08:27:12.860Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO DEBUG: Local ident: 'SSH-2.0-ssh2js0.4.10'
2020-06-04T08:27:12.898Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO DEBUG: Client: Trying ftp_foo.com on port 22 ...
2020-06-04T08:27:32.929Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO CLIENT[sftp]: Connection attempt 1 failed. Trying again.
2020-06-04T08:27:33.931Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO DEBUG: Local ident: 'SSH-2.0-ssh2js0.4.10'
2020-06-04T08:27:33.931Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO DEBUG: Client: Trying ftp_foo.com on port 22 ...
2020-06-04T08:27:53.951Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e INFO CLIENT[sftp]: Exhausted all connection attempts. Giving up
2020-06-04T08:27:53.957Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e ERROR Invoke Error {"errorType":"Error","errorMessage":"connect: Timed out while waiting for handshake after 2 attempts","code":"ERR_GENERIC_CLIENT","custom":true,"stack":["Error: connect: Timed out while waiting for handshake after 2 attempts"," at Object.formatError (/var/task/node_modules/ssh2-sftp-client/src/utils.js:62:18)"," at Client.connectErrorListener (/var/task/node_modules/ssh2-sftp-client/src/index.js:98:21)"," at Object.onceWrapper (events.js:417:26)"," at Client.emit (events.js:310:20)"," at Timeout._onTimeout (/var/task/node_modules/ssh2/lib/client.js:697:14)"," at listOnTimeout (internal/timers.js:549:17)"," at processTimers (internal/timers.js:492:7)"]}
2020-06-04T08:27:53.959Z 20d3c3b7-19d8-49cf-8997-1f2331eb0b6e ERROR Unhandled Promise Rejection {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"Error: end: No SFTP connection available","reason":{"errorType":"Error","errorMessage":"end: No SFTP connection available","code":"ERR_NOT_CONNECTED","custom":true,"stack":["Error: end: No SFTP connection available"," at formatError (/var/task/node_modules/ssh2-sftp-client/src/utils.js:62:18)"," at Object.haveConnection (/var/task/node_modules/ssh2-sftp-client/src/utils.js:612:20)"," at /var/task/node_modules/ssh2-sftp-client/src/index.js:1248:19"," at new Promise (<anonymous>)"," at SftpClient.end (/var/task/node_modules/ssh2-sftp-client/src/index.js:1236:12)"," at downloadPDFs (/var/task/index.js:40:14)"," at processTicksAndRejections (internal/process/task_queues.js:97:5)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: Error: end: No SFTP connection available"," at process.<anonymous> (/var/runtime/index.js:35:15)"," at process.emit (events.js:310:20)"," at processPromiseRejections (internal/process/promises.js:209:33)"," at processTicksAndRejections (internal/process/task_queues.js:98:32)"]}
[ERROR] [1591259273978] LAMBDA_RUNTIME Failed to post handler success response. Http response code: 403.
我的本地机器上是否发生了一些事情来提供我没有在lambda函数中实现的连接?
问题可能是您的 Lambda 函数无法访问 SFTP 主机。
此 SFTP 服务器托管在 AWS 外部还是您的账户内?
如果它托管在互联网上,而不是由您在 AWS 上托管,您可以执行以下操作:
- 创建公有 VPC [如果您已有公有 VPC,请跳过此操作]
- 在该公有 VPC 中添加 NAT 网关 [如果您已有 NAT 网关,请跳过此操作]
- 在 Lambda 函数所在的 VPC 中,添加一个路由表,通过将目标设置为
0.0.0.0/0
并将目标设置为我们在步骤 2 中创建的 NAT 网关,将流量重定向到 NAT 网关。
您可以访问此 AWS 文章,找到有关如何向 Lambda 函数添加互联网连接的详细答案:如何在 VPC 中授予对 Lambda 函数的互联网访问权限?
如果 SFTP 服务器已由您在 AWS 中托管,则只需使用 AWS 安全组添加对它的访问权限即可。
查看这篇文章,了解如何将 Lambda 与其他 AWS 服务连接(它使用 RDS,但您可以对 SFTP 服务器遵循相同的逻辑(: 配置 Lambda 函数以访问 Amazon VPC 中的 Amazon RDS
此外,请确保将 Lambda 超时设置为足够长,以允许与外部 SFTP 服务器连接和交换数据。
AWS 外部 SFTP 服务器的解决方案
正如@Atef之前提到的,问题是SFTP服务器托管在AWS之外,并且仅授予对白名单IP的访问权限。所以我使用了以下解决方法:
使用 VPC 为 Lambda 函数配置静态 IP
- 打开专有网络管理控制台
- 创建弹性 IP
- 使用向导创建 VPC("具有私有子网和公有子网"(
- 将弹性 IP 附加到 VPC("弹性 IP 分配 ID"(
- 使用路由表将您的私有子网和公有子网从 0.0.0.0/0 路由到弹性 IP
- 创建互联网网关并将其附加到 VPC
- 将 Lambda 函数附加到专有网络
- 为您的 lambda 服务的角色授予权限
AWSLambdaVPCAccessExecutionRole
和AmazonEC2FullAccess
- 为您的 lambda 服务的角色授予权限
您可以通过从函数调用 ipify API 并检查 HTTP 响应中提供的 ip 来测试这一点。它应该与您的弹性 IP 相同。现在,您可以将此 IP 列入白名单以访问 SFTP 服务器。
有关详细信息,另请参阅此文章。
我通过谷歌提出了这个问题,但即使在查看了Alex Strutz和Atef的答案后仍然被困住了。
如果您在已预先配置的环境中工作,则除了确保 NAT、安全组和互联网网关存在之外,您还需要检查 Lambda ENI 正在使用的子网和 NAT 网关所在的子网上存在的网络 ACL。
如果您仍然遇到问题,那么我建议您使用 AWS 可达性分析器来帮助您进行调试 - 这是一个很好的工具,可以一次性检查配置的多个部分。我已经在我的网站上写过如何将可达性分析器与 Lambda 一起使用(太长了,无法在此处包含(。