2017-06-01 82 views
0
通过Hashicorp库签名密钥,认证

我已经签署了使用Hashicorp跳马我的公钥,并在~/.ssh/id_rsa-cert.pub 保存生成的certificiate它工作得很好,我可以做ssh -i ~/.ssh/id_rsa-cert.pub [email protected],它让我在SSH:无法使用转到

当我尝试在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; [email protected]: ssh -i id_rsa-cert.pub [email protected]*/ 
    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 
    [email protected]: ssh [email protected]*/ 
    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: [email protected] 

我需要什么在这里做什么来获得这个工作?

+0

显然使用了'ssh.InsecureIgnoreHostKey()',你当你的服务器要求使用ssh.InsecureIgnoreHostKey认证 –

+0

的一种或至少一种方法,我的印象是无视键()会接受任何主机密钥?这是不正确的? –

+0

Alex:您是否找到了解决问题的方案?我仍然有同样的问题,我很想有一个golang实现来授权签名密钥。 –

回答

0

我花了几个小时弄清楚了这一点。

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

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