使用 Elastic Beanstalk EB 在 AWS 上使用 pysftp 和 paramiko 的 SFTP known_hosts

SFTP with pysftp and paramiko on AWS using Elastic Beanstalk EB known_hosts

所以我正在构建一个 Flask 微服务来连接两个 API。 API 之一要求所有通信都通过 SFTP 来移动 XML 文件(耶!)。

在 Windows 上,经过相当多的摆弄后,我才能够让它工作。问题是,除非我使用 FileZilla 登录并接受主机密钥,否则 pysftp/paramiko 无法连接。

为了解决这个问题,我编写了一个函数来检查“C:/Users/{user}/.ssh/known_hosts”中的 known_hosts 文件,如果该站点缺少密钥,我使用paramiko获取密钥。

from pysftp import known_hosts
import paramiko


def check_for_host_key(hostname):
    """
    Checks for host key in known_hosts file
    If it is not found, it will get it and add it to known_hosts
    """
    
    KNOWN_HOSTS = known_hosts()  # this fn returns a string looking like 'C:/Users/{user}/.ssh/known_hosts' but is OS agnostic and works fine under Linux.

    if os.path.isfile(KNOWN_HOSTS):
        pass
    else:
        # if known_hosts doesn't exist, create it in default directory
        try:
            open(KNOWN_HOSTS, 'a+').close()
        except FileNotFoundError:
            KNOWN_HOSTS = "/home/ec2-user/.ssh/known_hosts"
            open(KNOWN_HOSTS, 'a+').close()

    # check if host key is present
    if open(KNOWN_HOSTS, 'r').read().find(hostname) != -1:
        return

    # if not get it...
    print(f"host key not found in known_hosts({KNOWN_HOSTS})\ngetting host key")
    transport = paramiko.Transport(hostname)
    transport.connect()
    key = transport.get_remote_server_key()
    transport.close()

    # and save it
    hostfile = paramiko.HostKeys(filename=KNOWN_HOSTS)
    hostfile.add(hostname=hostname, key=key, keytype=key.get_name())
    hostfile.save(filename=KNOWN_HOSTS)
    print(f"host key saved to known_hosts({KNOWN_HOSTS})")
    return

上面的函数在 Windows 上工作得很好,我希望它在 LInux 服务器上部署到 AWS 时能正常工作,因为我最初看到的代码是修改 known_hosts文件是为 Linux 编写的(如果没记错...)。但是当我部署到 Elastic Beanstalk(使用 EB CLI)时,我不断收到 502 错误。

检查 AWS 日志我可以看到在启动期间调用 check_for_host_key 函数时出现特定错误(因此是 502):

Jul 15 21:15:21 ip-172-31-19-61 web: Traceback (most recent call last):
Jul 15 21:15:21 ip-172-31-19-61 web: File "/var/app/current/app/config.py", line 16, in Config
Jul 15 21:15:21 ip-172-31-19-61 web: open(KNOWN_HOSTS, 'a+').close()
Jul 15 21:15:21 ip-172-31-19-61 web: FileNotFoundError: [Errno 2] No such file or directory: '/home/webapp/.ssh/known_hosts'
.......
Jul 15 21:15:21 ip-172-31-19-61 web: open(KNOWN_HOSTS, 'a+').close()
Jul 15 21:15:21 ip-172-31-19-61 web: PermissionError: [Errno 13] Permission denied: '/home/ec2-user/.ssh/known_hosts'

第一个错误是真正的错误,FileNotFoundError: [Errno 2] No such file or directory: '/home/webapp/.ssh/known_hosts'

为什么我的 python 应用程序找不到相关目录?如果在 Windows 上缺少相关代码行,那么它实际上会创建文件,我的理解是它应该在 Linux.

上执行相同的操作

第二个错误是我尝试排除故障并使用不同的用户主文件夹,但由于权限错误而失败。

接下来,我在 Powershell 终端中使用 eb ssh 通过 SSH 连接到我的应用程序实例(这会自动以 ec2-user 身份登录),然后我开始浏览文件夹结构。我发现我根本无法进入 /home/webapp/ 目录,同样是由于权限错误。确切的错误是:

[ec2-user@ip-172-31-19-61 home]$ cd ./webapp
-bash: cd: ./webapp: Permission denied

据我所知,从 AWS 成功启动 SFTP 连接的唯一方法是将主机密钥存储在 known_hosts 中(我知道自动执行此操作的 MITM 含义,但这在这里不是问题)但这似乎不是一个选项,无论是通过 SSH 还是从应用程序实例。

我可能需要对 IAM 角色做些什么吗?我认为这可以解释 SSH 配置文件无法浏览 /home/webapp/ 目录,但我不确定这对应用程序本身有何帮助。

总而言之,我完全迷失了。我是 AWS 的新手,我也不是 Linux 专家,所以我真的很感激任何帮助。

谢谢

用户和文件夹似乎有些混乱。

您的应用程序在 webapp 用户下执行。因此,您的应用程序将无法在您尝试修改属于 ec2-user 的任何文件夹时:

KNOWN_HOSTS = "/home/ec2-user/.ssh/known_hosts"

创建这样的 /home/webapp/.ssh/known_hosts 文件也会失败,因为默认文件夹 /home/webapp/.ssh/ 不存在 。必须先创建它,然后才能将 known_hosts 添加到其中。