add remote signer api and e2e test of it (#320)

This commit is contained in:
Boshi Lian 2024-02-11 01:54:55 -08:00 committed by GitHub
parent d8b345eeb7
commit 82ac6a5fff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 72 additions and 4 deletions

View file

@ -1,6 +1,12 @@
package e2e_test package e2e_test
import ( import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@ -110,11 +116,30 @@ func createRpcServer(r *rpcServer) net.Listener {
func TestPlugin(t *testing.T) { func TestPlugin(t *testing.T) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("failed to generate private key: %v", err)
}
privKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privKeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privKeyBytes,
},
)
sshkey, err := ssh.NewSignerFromKey(privateKey)
if err != nil {
t.Fatalf("failed to create ssh signer: %v", err)
}
sshsvr := createFakeSshServer(&ssh.ServerConfig{ sshsvr := createFakeSshServer(&ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
if string(pass) != "rpcpassword" { if !bytes.Equal(key.Marshal(), sshkey.PublicKey().Marshal()) {
return nil, fmt.Errorf("invalid password") return nil, fmt.Errorf("public key mismatch")
} }
return nil, nil return nil, nil
}, },
}) })
@ -152,6 +177,8 @@ func TestPlugin(t *testing.T) {
sshsvr.Addr().String(), sshsvr.Addr().String(),
"--rpcserver", "--rpcserver",
rpcsvr.Addr().String(), rpcsvr.Addr().String(),
"--testremotekey",
base64.StdEncoding.EncodeToString(privKeyPem),
) )
if err != nil { if err != nil {

View file

@ -8,6 +8,7 @@ import (
"net" "net"
"os" "os"
"github.com/tg123/remotesigner/grpcsigner"
"github.com/tg123/sshpiper/libplugin/ioconn" "github.com/tg123/sshpiper/libplugin/ioconn"
"google.golang.org/grpc" "google.golang.org/grpc"
codes "google.golang.org/grpc/codes" codes "google.golang.org/grpc/codes"
@ -60,6 +61,8 @@ type SshPiperPluginConfig struct {
PipeStartCallback func(conn ConnMetadata) PipeStartCallback func(conn ConnMetadata)
PipeErrorCallback func(conn ConnMetadata, err error) PipeErrorCallback func(conn ConnMetadata, err error)
GrpcRemoteSignerFactory grpcsigner.SignerFactory
} }
type SshPiperPlugin interface { type SshPiperPlugin interface {
@ -99,6 +102,14 @@ func NewFromGrpc(config SshPiperPluginConfig, grpc *grpc.Server, listener net.Li
RegisterSshPiperPluginServer(s.grpc, s) RegisterSshPiperPluginServer(s.grpc, s)
if config.GrpcRemoteSignerFactory != nil {
gs, err := grpcsigner.NewSignerServer(config.GrpcRemoteSignerFactory)
if err != nil {
return nil, err
}
grpcsigner.RegisterSignerServer(s.grpc, gs)
}
return s, nil return s, nil
} }

View file

@ -3,10 +3,14 @@
package main package main
import ( import (
"crypto"
"encoding/base64"
"fmt"
"net/rpc" "net/rpc"
"github.com/tg123/sshpiper/libplugin" "github.com/tg123/sshpiper/libplugin"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/crypto/ssh"
) )
func main() { func main() {
@ -23,6 +27,10 @@ func main() {
Name: "testsshserver", Name: "testsshserver",
Required: true, Required: true,
}, },
&cli.StringFlag{
Name: "testremotekey",
Required: true,
},
}, },
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) { CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
@ -36,6 +44,21 @@ func main() {
return nil, err return nil, err
} }
keydata, err := base64.StdEncoding.DecodeString(c.String("testremotekey"))
if err != nil {
return nil, err
}
key, err := ssh.ParseRawPrivateKey(keydata)
if err != nil {
return nil, err
}
_, ok := key.(crypto.Signer)
if !ok {
return nil, fmt.Errorf("key format not supported")
}
return &libplugin.SshPiperPluginConfig{ return &libplugin.SshPiperPluginConfig{
NewConnectionCallback: func(conn libplugin.ConnMetadata) error { NewConnectionCallback: func(conn libplugin.ConnMetadata) error {
return rpcclient.Call("TestPlugin.NewConnection", "", nil) return rpcclient.Call("TestPlugin.NewConnection", "", nil)
@ -56,10 +79,17 @@ func main() {
return &libplugin.Upstream{ return &libplugin.Upstream{
Host: host, Host: host,
Port: int32(port), Port: int32(port),
Auth: libplugin.CreatePasswordAuthFromString(newpass), Auth: libplugin.CreateRemoteSignerAuth("testplugin"),
IgnoreHostKey: true, IgnoreHostKey: true,
}, nil }, nil
}, },
GrpcRemoteSignerFactory: func(metadata string) crypto.Signer {
if metadata != "testplugin" {
panic("metadata mismatch")
}
return key.(crypto.Signer)
},
}, nil }, nil
}, },
}) })