support Fingerprint (#157)

This commit is contained in:
Bo-Yi Wu 2020-05-19 14:01:28 +08:00 committed by GitHub
parent 923defc397
commit a2c6be3c19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 118 additions and 27 deletions

30
main.go
View File

@ -65,6 +65,11 @@ func main() {
EnvVar: "PLUGIN_CIPHERS,SSH_CIPHERS,CIPHERS,INPUT_CIPHERS", EnvVar: "PLUGIN_CIPHERS,SSH_CIPHERS,CIPHERS,INPUT_CIPHERS",
Value: &defaultCiphers, Value: &defaultCiphers,
}, },
cli.StringFlag{
Name: "fingerprint",
Usage: "fingerprint as unpadded base64 encoded sha256 hash.",
EnvVar: "PLUGIN_FINGERPRINT,SSH_FINGERPRINT,FINGERPRINT,INPUT_FINGERPRINT",
},
cli.StringSliceFlag{ cli.StringSliceFlag{
Name: "host,H", Name: "host,H",
Usage: "connect to host", Usage: "connect to host",
@ -157,6 +162,11 @@ func main() {
EnvVar: "PLUGIN_PROXY_CIPHERS,SSH_PROXY_CIPHERS,PROXY_CIPHERS,INPUT_PROXY_CIPHERS", EnvVar: "PLUGIN_PROXY_CIPHERS,SSH_PROXY_CIPHERS,PROXY_CIPHERS,INPUT_PROXY_CIPHERS",
Value: &defaultCiphers, Value: &defaultCiphers,
}, },
cli.StringFlag{
Name: "proxy.fingerprint",
Usage: "fingerprint as unpadded base64 encoded sha256 hash.",
EnvVar: "PLUGIN_PROXY_FINGERPRINT,SSH_PROXY_FINGERPRINT,PROXY_FINGERPRINT,INPUT_PROXY_FINGERPRINT",
},
cli.StringSliceFlag{ cli.StringSliceFlag{
Name: "envs", Name: "envs",
Usage: "pass environment variable to shell script", Usage: "pass environment variable to shell script",
@ -219,6 +229,7 @@ func run(c *cli.Context) error {
Username: c.String("user"), Username: c.String("user"),
Password: c.String("password"), Password: c.String("password"),
Passphrase: c.String("ssh-passphrase"), Passphrase: c.String("ssh-passphrase"),
Fingerprint: c.String("fingerprint"),
Host: c.StringSlice("host"), Host: c.StringSlice("host"),
Port: c.Int("port"), Port: c.Int("port"),
Timeout: c.Duration("timeout"), Timeout: c.Duration("timeout"),
@ -230,15 +241,16 @@ func run(c *cli.Context) error {
Sync: c.Bool("sync"), Sync: c.Bool("sync"),
Ciphers: c.StringSlice("ciphers"), Ciphers: c.StringSlice("ciphers"),
Proxy: easyssh.DefaultConfig{ Proxy: easyssh.DefaultConfig{
Key: c.String("proxy.ssh-key"), Key: c.String("proxy.ssh-key"),
KeyPath: c.String("proxy.key-path"), KeyPath: c.String("proxy.key-path"),
User: c.String("proxy.username"), User: c.String("proxy.username"),
Password: c.String("proxy.password"), Password: c.String("proxy.password"),
Passphrase: c.String("proxy.ssh-passphrase"), Passphrase: c.String("proxy.ssh-passphrase"),
Server: c.String("proxy.host"), Fingerprint: c.String("proxy.fingerprint"),
Port: c.String("proxy.port"), Server: c.String("proxy.host"),
Timeout: c.Duration("proxy.timeout"), Port: c.String("proxy.port"),
Ciphers: c.StringSlice("proxy.ciphers"), Timeout: c.Duration("proxy.timeout"),
Ciphers: c.StringSlice("proxy.ciphers"),
}, },
}, },
Writer: os.Stdout, Writer: os.Stdout,

View File

@ -30,6 +30,7 @@ type (
Password string Password string
Host []string Host []string
Port int Port int
Fingerprint string
Timeout time.Duration Timeout time.Duration
CommandTimeout time.Duration CommandTimeout time.Duration
Script []string Script []string
@ -55,25 +56,27 @@ func escapeArg(arg string) string {
func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) { func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
// Create MakeConfig instance with remote username, server address and path to private key. // Create MakeConfig instance with remote username, server address and path to private key.
ssh := &easyssh.MakeConfig{ ssh := &easyssh.MakeConfig{
Server: host, Server: host,
User: p.Config.Username, User: p.Config.Username,
Password: p.Config.Password, Password: p.Config.Password,
Port: strconv.Itoa(p.Config.Port), Port: strconv.Itoa(p.Config.Port),
Key: p.Config.Key, Key: p.Config.Key,
KeyPath: p.Config.KeyPath, KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase, Passphrase: p.Config.Passphrase,
Timeout: p.Config.Timeout, Timeout: p.Config.Timeout,
Ciphers: p.Config.Ciphers, Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
Proxy: easyssh.DefaultConfig{ Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server, Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User, User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password, Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port, Port: p.Config.Proxy.Port,
Key: p.Config.Proxy.Key, Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath, KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase, Passphrase: p.Config.Proxy.Passphrase,
Timeout: p.Config.Proxy.Timeout, Timeout: p.Config.Proxy.Timeout,
Ciphers: p.Config.Proxy.Ciphers, Ciphers: p.Config.Proxy.Ciphers,
Fingerprint: p.Config.Proxy.Fingerprint,
}, },
} }

View File

@ -3,6 +3,7 @@ package main
import ( import (
"bytes" "bytes"
"io" "io"
"io/ioutil"
"os" "os"
"reflect" "reflect"
"strings" "strings"
@ -11,6 +12,7 @@ import (
"github.com/appleboy/easyssh-proxy" "github.com/appleboy/easyssh-proxy"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/crypto/ssh"
) )
func TestMissingHostOrUser(t *testing.T) { func TestMissingHostOrUser(t *testing.T) {
@ -384,6 +386,80 @@ func TestCommandOutput(t *testing.T) {
assert.Equal(t, unindent(expected), unindent(buffer.String())) assert.Equal(t, unindent(expected), unindent(buffer.String()))
} }
func TestWrongFingerprint(t *testing.T) {
var (
buffer bytes.Buffer
)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"whoami",
},
Fingerprint: "wrong",
},
Writer: &buffer,
}
err := plugin.Exec()
assert.NotNil(t, err)
}
func getHostPublicKeyFile(keypath string) (ssh.PublicKey, error) {
var pubkey ssh.PublicKey
var err error
buf, err := ioutil.ReadFile(keypath)
if err != nil {
return nil, err
}
pubkey, _, _, _, err = ssh.ParseAuthorizedKey(buf)
if err != nil {
return nil, err
}
return pubkey, nil
}
func TestFingerprint(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
whoami
======END======
out: drone-scp
`
)
hostKey, err := getHostPublicKeyFile("/etc/ssh/ssh_host_rsa_key.pub")
assert.NoError(t, err)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"whoami",
},
Fingerprint: ssh.FingerprintSHA256(hostKey),
CommandTimeout: 10 * time.Second,
},
Writer: &buffer,
}
err = plugin.Exec()
assert.Nil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func TestScriptStop(t *testing.T) { func TestScriptStop(t *testing.T) {
var ( var (
buffer bytes.Buffer buffer bytes.Buffer