add remote signer api and e2e test of it (#320)
This commit is contained in:
parent
d8b345eeb7
commit
82ac6a5fff
3 changed files with 72 additions and 4 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue