ssl - SSH:无法使用 Go 使用 Hashicorp Vault 签名的 key 进行身份验证

标签 ssl go ssh hashicorp-vault

我已使用 Hashicorp 的 Vault 签署了我的公钥,并将生成的证书保存在 ~/.ssh/id_rsa-cert.pub 它工作得很好,我可以执行 ssh -i ~/.ssh/id_rsa-cert.pub user@hostname ,它让我进入。

当我尝试在 Go 中实现这一点时,我的问题就开始了。

这是我的代码:

package main

import (
"encoding/base64"
"fmt"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"net"
"os"
)

func main() {
pubKey := "AAAAB3NzaC1yc2EAAAADAQABA..."
signedKey := "AAAAHHNzaC1yc2EtY2VydC..."
pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKey)
if err != nil {
    panic(err)
}
pk, err := ssh.ParsePublicKey(pubKeyBytes)
if err != nil {
    panic(err)
}
fmt.Printf("%T\n", pk)

signedKeyBytes, err := base64.StdEncoding.DecodeString(signedKey)
if err != nil {
    panic(err)
}
fmt.Printf("%T\n", pk)
sk, err := ssh.ParsePublicKey(signedKeyBytes)
if err != nil {
    panic(err)
}
fmt.Printf("%T\n", sk)

conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
    panic(err)
}
sshAgent := agent.NewClient(conn)
signers, err := sshAgent.Signers()
if err != nil {
    panic(err)
}

c := &ssh.Certificate{
    Key:          pk,
    SignatureKey: sk,
}

signer, err := ssh.NewCertSigner(c, signers[0])
if err != nil {
    panic(err)
}

auths := []ssh.AuthMethod{ssh.PublicKeys(signer)}
sshClient, err := ssh.Dial("tcp", "10.0.0.150:22", &ssh.ClientConfig{
    User: "user1",
    /*The signed key is signed against user2's public key, and should allow him to log in.
    It works via command line; user2@localhost: ssh -i id_rsa-cert.pub <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f386809681c2b3c2c3ddc3ddc2c6c3" rel="noreferrer noopener nofollow">[email protected]</a>*/
    Auth:            auths,
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
fmt.Println(sshClient, err) /*This does not work*/

sshClient2, err := ssh.Dial("tcp", "10.0.0.150:22", &ssh.ClientConfig{
    User: "user2",
    /*User2 is allowed to connect with his basic keypair
    user2@localhost: ssh <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="384d4b5d4a0a7809081608160816090d08" rel="noreferrer noopener nofollow">[email protected]</a>*/
    Auth: []ssh.AuthMethod{
        ssh.PublicKeysCallback(sshAgent.Signers),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
fmt.Println(sshClient2, err) /*This works fine*/
}

我得到的错误是:

ssh: handshake failed: ssh: unable to authenticate, attempted methods [publickey none],
no supported methods remain

以及来自相关服务器的 sshd 日志:

 sshd[7149]: error: Unknown certificate type 0 sshd[7149]: error:
 key_from_blob: can't parse cert data sshd[7149]: error:
 userauth_pubkey: cannot decode key: <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3a4949521748495b17595f484e174c0a0b7a554a5f5449495214595557" rel="noreferrer noopener nofollow">[email protected]</a>

我需要在这里做什么才能使其正常工作?

最佳答案

我花了几个小时才解决这个问题。

解决方案是使用您的私钥和证书并首先创建签名者,然后创建证书签名者并将两者结合起来。下面是按预期工作的工作代码。

package main

import (
    "bytes"
    "golang.org/x/crypto/ssh"
    "io/ioutil"
    "log"
)

func main() {
    authorizedKeysBytes, _ := ioutil.ReadFile("/home/wooh/.ssh/signed-cert.pub")
    pcert, _, _, _, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)

    privkeyBytes, _ := ioutil.ReadFile("/home/wooh/.ssh/id_rsa")
    upkey, err := ssh.ParseRawPrivateKey(privkeyBytes)

    if err != nil {
        log.Printf("Failed to load authorized_keys, err: %v", err)
    }

    usigner, err := ssh.NewSignerFromKey(upkey)
    if err != nil {
        log.Printf("Failed to create new signer, err: %v", err)
    }
    log.Printf("signer: %v", usigner)

    ucertSigner, err := ssh.NewCertSigner(pcert.(*ssh.Certificate), usigner)

    if err != nil {
        log.Printf("Failed to create new signer, err: %v", err)
    }

    sshConfig := &ssh.ClientConfig{
        User:            "wooh",
        Auth:            []ssh.AuthMethod{ssh.PublicKeys(ucertSigner)},
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    client, err := ssh.Dial("tcp", "127.0.0.1:22", sshConfig)

    if err != nil {
        log.Fatalf("Failed to dial, err: %v", err)
    }

    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()

    var b bytes.Buffer
    session.Stdout = &b
    if err := session.Run("/usr/bin/whoami"); err != nil {
        log.Fatal("Failed to run: " + err.Error())
    }
    log.Println(b.String())
}

关于ssl - SSH:无法使用 Go 使用 Hashicorp Vault 签名的 key 进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44314924/

相关文章:

Python 在另一个脚本上引用数据库连接

java - 拒绝 HostKey : when deploying JAR with gradle ssh plugin

linux - ssh 忽略特殊字符

Facebook Canvas 应用程序 : Force SSL

c++ - 如何优雅地关闭 boost asio ssl 客户端?

Java/SSL - 未处理异常 :java. security.NoSuchAlgorithmException

PHPMailer 不会使用 SSL 发送,但 Outlook 会

来自 Go 的 Android API

excel - 在 Google App Engine 上打开 Tealeg xlsx 用 Go 语言创建的 XLSX 文件时出错

for-loop - 您如何遍历函数产生的所有值?