douhui9380 2017-06-01 18:46
浏览 121

SSH:无法通过Go使用Hashicorp Vault签名的密钥进行身份验证

I have signed my public key using Hashicorp's Vault, and saved the generated certificiate in ~/.ssh/id_rsa-cert.pub It works just fine, I can do ssh -i ~/.ssh/id_rsa-cert.pub user@hostname and it lets me in.

My problems start when I try to implement this in Go.

This is my code:

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
", pk)

signedKeyBytes, err := base64.StdEncoding.DecodeString(signedKey)
if err != nil {
    panic(err)
}
fmt.Printf("%T
", pk)
sk, err := ssh.ParsePublicKey(signedKeyBytes)
if err != nil {
    panic(err)
}
fmt.Printf("%T
", 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 user1@10.0.150*/
    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 user2@10.0.0.150*/
    Auth: []ssh.AuthMethod{
        ssh.PublicKeysCallback(sshAgent.Signers),
    },
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
fmt.Println(sshClient2, err) /*This works fine*/
}

The errors I get are:

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

And the sshd logs from the server in question:

 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: ssh-rsa-cert-v01@openssh.com

What do I need to do here to get this to work?

  • 写回答

1条回答 默认 最新

  • duanbangzhou7809 2017-11-16 02:30
    关注

    I spent a few hours to figure this out.

    The solution is to use your private key and your cert and make a signer first, then a certsigner and combine the two. Below is the working code which works as expected.

    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())
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献