java - 在 Camel 中使用公钥身份验证配置 SCP 路由的正确方法是什么?

标签 java apache-camel jsch

我目前正在利用 Apache Camel(撰写本文时为 2.20.2 版)作为更大 ETL 流程的一部分,将已处理的文件从 Camel box 复制到另一台机器。

但是,我在处理 SCP 配置方面遇到了麻烦。这样做的目的是为了让我不必提供私钥所在位置和已知主机所在位置之外的太多信息。

以下是示例路线。样例路线仅供交流;它可能不准确,但这里的目的不是将上游部分显示为“工作”。由于我为它编写了 上游 测试,我确信文件生成部分正在运行。


有效的方法:

如果我指定我的用户名和密码并且禁用严格的主机 key 检查,我的路由就可以工作。

from("direct:init")
    .to("file:///tmp")
    .to("scp://my.server.local?username=makoto&password=XXXXXX" + 
                              "&preferredAuthentications=password" +
                              "&strictHostKeyChecking=no");

当然,由于政策原因,不进行严格的主机检查是绝对不可能的。

什么不起作用:

  • 如果我指定我的用户名和密码并禁用严格的主机 key 检查,我会收到此错误:

    com.jcraft.jsch.JSchException: reject HostKey: my.server.local
        at com.jcraft.jsch.Session.checkHost(Session.java:789) ~[jsch-0.1.54.jar:na]
        at com.jcraft.jsch.Session.connect(Session.java:345) ~[jsch-0.1.54.jar:na]
        at org.apache.camel.component.scp.ScpOperations.createSession(ScpOperations.java:284) [camel-jsch-2.20.2.jar:2.20.2]
        at org.apache.camel.component.scp.ScpOperations.connect(ScpOperations.java:179) [camel-jsch-2.20.2.jar:2.20.2]
    
  • 如果我指定我的用户名和密码,请不要禁用严格的主机 key 检查并不要 将我的首选身份验证类型指定为“密码”,我得到与上述相同的错误。

  • 如果我省略我的密码以指定私钥的路径, 我禁用严格的主机 key 检查,我收到此错误:

    com.jcraft.jsch.JSchException: Auth cancel
        at com.jcraft.jsch.Session.connect(Session.java:518) ~[jsch-0.1.54.jar:na]
        at org.apache.camel.component.scp.ScpOperations.createSession(ScpOperations.java:284) [camel-jsch-2.20.2.jar:2.20.2]
    
  • 如果我执行上述所有操作并且将公钥作为我的首选身份验证,我会收到此错误:

    com.jcraft.jsch.JSchException: Auth fail
        at com.jcraft.jsch.Session.connect(Session.java:519) ~[jsch-0.1.54.jar:na]
        at org.apache.camel.component.scp.ScpOperations.createSession(ScpOperations.java:284) [camel-jsch-2.20.2.jar:2.20.2]
        at org.apache.camel.component.scp.ScpOperations.connect(ScpOperations.java:179) [camel-jsch-2.20.2.jar:2.20.2]
    

    在这种情况下,Camel 似乎完全无视我的用户,并选择使用自己的用户:

    2018-02-19 10:46:15.142 DEBUG 23940 --- [obfuscated-route] o.a.camel.component.scp.ScpOperations    : Passphrase for camel-jsch
    2018-02-19 10:46:15.142  WARN 23940 --- [obfuscated-route] o.a.camel.component.scp.ScpOperations    : Private Key authentication not supported
    2018-02-19 10:46:15.142 DEBUG 23940 --- [obfuscated-route] o.a.camel.component.scp.ScpOperations    : Passphrase for camel-jsch
    2018-02-19 10:46:15.142  WARN 23940 --- [obfuscated-route] o.a.camel.component.scp.ScpOperations    : Private Key authentication not supported
    

不用说,这里的错误消息并没有给我太多可以解决的问题,因为:

  • 他们因情况而异
  • 它们是特定于配置的;就好像每一个配置都缺少了什么

考虑到这一点,正确的配置方法是什么? Camel 邮件列表上的零散文档没有产生任何具体内容,并且 the SCP documentation对于这些情况几乎没有实际帮助。

其他一些环境注意事项:

  • 我既不“控制”Camel 所在的机器,也不“控制”接收文件的机器。
  • 我正在我的机器上进行本地测试,我的公钥绝对包含在主机的 authorized_keys 文件中。
  • 我机器上的 known_hosts 条目经过哈希处理/模糊处理。

最佳答案

这感觉非常倒退和错误,但我相信我已经解决了我自己的问题。

执行摘要:

  • JSch 正在寻找与您的散列主机名匹配的内容。
  • 如果它无法通过您计算机上的所有身份找到匹配项,它将把存储库标记为“不包括”。
  • 如果存储库未标记为“OK”并且启用了严格的主机 key 检查,它将注册为失败。

执行方案:

  • 必须将主机 key 添加到您的系统(通过使用 ssh-keyscan -t rsa -H <hostname> )。仅在目标机器上拥有主机 key 是不够的。
  • 如果您的私钥有密码,您仍然有义务提供它。

有趣的是,Camel 似乎使用自己的用户和身份连接到服务器这一事实有点确凿。这让我从异常的角度来观察代码流。

我观察到的第一是在 JSch 迭代的身份 vector 中无处找不到散列主机。这意味着,尽管我之前已经通过 SSH 连接到这台机器,但 JSch 却一无所获,并且不知道它的存在。

所以我从this Server Fault question中找到了一些灵​​感,因为我需要将新的哈希主机添加到我自己的身份文件中。

实际上,我利用了 this answer因为这似乎是最实用和最安全的方法:

  • ssh-keyscan -t rsa -H my.server.local
  • 从该命令的输出中明确复制仅 RSA 散列(我相信最多可以有 3 行)并将其附加到我的已知主机文件的末尾

但是,我确实发现身份验证仍然莫名其妙地失败了。为了调试和诊断正在发生的事情,我选择保留私钥的路径,并将私钥的密码添加到系统中,以便 JSch 可以使用它。

我可以承认所需的密码是我的疏忽,但它无法选择一个合理的私钥来使用这一事实让我感到惊讶,特别是考虑到普通的 SSH 将遍历它们。

现在完成了,完整的路线看起来是这样的:

from("direct:init")
    .to("file:///tmp")
    .to("scp://my.server.local?username=makoto&privateKeyFilePassphrase=XXXXXX" + 
                          "&preferredAuthentications=publickey" +
                          "&privateKeyFile=/path/to/.ssh/id_rsa");

关于java - 在 Camel 中使用公钥身份验证配置 SCP 路由的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48871079/

相关文章:

java - Camel从http获取数据

java - 在 JSch 中使用连接池

java - JSP错误 "Illegal start of type"

java - Hibernate 不生成更新的 sql 代码

java - 如何从 ArrayList 在 ListView 上显示员工详细信息?

java - 错误: Multiple RestConsumerFactory found on classpath

java - JTable刷新数据不显示

java - 如何将 apache-camel DSL 与线程池一起使用?

android - JSch - 如何使用 Session 和 UserInfo

java - 如何使用 channel.connect(); 对远程数据库执行 “insert into” 查询;