为了账号安全,请及时绑定邮箱和手机立即绑定

如何将 id_ed25519-cert.pub 合并到 go ssh 客户端中?

如何将 id_ed25519-cert.pub 合并到 go ssh 客户端中?

Go
冉冉说 2023-03-29 15:31:26
我可以使用两个文件通过 SSH(使用 openssh 客户端)连接到我的服务器:~/.ssh/id_ed25519{,-cert.pub}debug1: Trying private key: /home/xavier/.ssh/id_ed25519                        debug1: Authentications that can continue: publickey,keyboard-interactive      debug1: Offering ED25519-CERT public key: /home/xavier/.ssh/id_ed25519          debug1: Server accepts key: pkalg ssh-ed25519-cert-v01@openssh.com blen 441    debug1: sign_and_send_pubkey: no separate private key for certificate "/home/xavier/.ssh/id_ed25519"debug1: Authentication succeeded (publickey).我想要一个做同样事情的 go 客户端,但我不知道如何将该文件合并到https://godoc.org/golang.org/x/crypto/ssh#example-PublicKeysid_ed25519-cert.pub的示例中key, err := ioutil.ReadFile("/home/xavier/.ssh/id_ed25519")if err != nil {    log.Fatalf("unable to read private key: %v", err)}// Create the Signer for this private key.signer, err := ssh.ParsePrivateKey(key)if err != nil {    log.Fatalf("unable to parse private key: %v", err)}config := &ssh.ClientConfig{    User: "user",    Auth: []ssh.AuthMethod{        // Use the PublicKeys method for remote authentication.        ssh.PublicKeys(signer),    },}// Connect to the remote server and perform the SSH handshake.client, err := ssh.Dial("tcp", "host.com:22", config)if err != nil {    log.Fatalf("unable to connect: %v", err)}defer client.Close()部分问题是我不知道这个文件是什么(PublicKey?证书?),部分问题是即使我知道我也不明白它在这个交换中的作用。我已确认此文件是必需的:删除它会导致 ssh CLI 失败。
查看完整描述

1 回答

?
至尊宝的传说

TA贡献1789条经验 获得超10个赞

那是一个SSH证书文件,用于实现基于SSH证书的用户认证。这通过检查公钥层次结构中受信任的证书颁发机构的有效签名来验证用户登录的真实性。与标准的基于 SSH 密钥的身份验证(使用文件)相比,这种方法具有多种优势authorized_keys,例如:

  • 控制密钥文件的发布(有权访问 CA 主密钥的人必须签署新证书,而不是用户发布自己的证书ssh-keygen

  • 自动密钥文件到期

  • 添加或轮换证书时减少管理开销,因为只需要 CA 的公钥来验证证书;不再需要authorized_keys为每个主机上的每个用户填充一个文件

  • 当与用户的关系发生变化时,为证书吊销提供更简单的支持


假设您使用的是内置golang.org/x/crypto/ssh库,您可以通过以下方式实现:

  • 读入并解析您签名的公钥证书和私钥

  • 从私钥创建签名者

  • 使用读入的公钥和相应的私钥签名者创建证书签名者

OpenSSH 公钥证书的指定格式类似于文件authorized_keysParseAuthorizedKeysGo库的函数会解析这个文件,将对应的key作为接口实例返回ssh.PublicKey;对于证书,这具体是结构的一个实例ssh.Certificate

请参阅代码示例(注意:我HostKeyCallback在您的代码中添加了一个ClientConfig以实现与测试盒的连接——但是,它使用了InsecureIgnoreHostKey检查器,我不建议在生产中使用它!)。

package main


import (

    "bytes"

    "io/ioutil"

    "log"


    "golang.org/x/crypto/ssh"

)


func main() {

    key, err := ioutil.ReadFile("/tmp/mycert")

    if err != nil {

        log.Fatalf("unable to read private key: %v", err)

    }


    // Create the Signer for this private key.

    signer, err := ssh.ParsePrivateKey(key)

    if err != nil {

        log.Fatalf("unable to parse private key: %v", err)

    }


    // Load the certificate

    cert, err := ioutil.ReadFile("/tmp/mycert-cert.pub")

    if err != nil {

        log.Fatalf("unable to read certificate file: %v", err)

    }


    pk, _, _, _, err := ssh.ParseAuthorizedKey(cert)

    if err != nil {

        log.Fatalf("unable to parse public key: %v", err)

    }


    certSigner, err := ssh.NewCertSigner(pk.(*ssh.Certificate), signer)

    if err != nil {

        log.Fatalf("failed to create cert signer: %v", err)

    }


    config := &ssh.ClientConfig{

        User: "user",

        Auth: []ssh.AuthMethod{

            // Use the PublicKeys method for remote authentication.

            ssh.PublicKeys(certSigner),

        },

        HostKeyCallback: ssh.InsecureIgnoreHostKey(),

    }


    // Connect to the remote server and perform the SSH handshake.

    client, err := ssh.Dial("tcp", "host.com:22", config)

    if err != nil {

        log.Fatalf("unable to connect: %v", err)

    }

    defer client.Close()

}

如果您想编写一个更通用的支持证书和非证书的连接客户端,您显然需要额外的逻辑来处理其他类型的公钥。如所写,我希望pk.(*ssh.Certificate)非证书公钥文件的类型断言失败!(实际上,对于非证书连接,您可能根本不需要读取公钥。)


查看完整回答
反对 回复 2023-03-29
  • 1 回答
  • 0 关注
  • 88 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信