Compare commits

...

8 Commits

Author SHA1 Message Date
Bo-Yi Wu 7344ac6529 chore: support UseInsecureCipher (#158) 2020-05-24 10:43:11 +08:00
Bo-Yi Wu 1288a4b20d docs: update fingerprint comment.
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-05-19 14:11:26 +08:00
Bo-Yi Wu 11ec0bec7e update makefile
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-05-19 14:02:15 +08:00
Bo-Yi Wu a2c6be3c19 support Fingerprint (#157) 2020-05-19 14:01:28 +08:00
Bo-Yi Wu 923defc397 easyssh-proxy upgrade => v1.3.5
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-05-19 12:55:32 +08:00
Bo-Yi Wu ec9d02ec38 missing Ciphers config
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-04-30 15:49:00 +08:00
Bo-Yi Wu 9c9e7914ce support custom Ciphers value
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2020-04-30 15:38:46 +08:00
techknowlogick 9e205a756f Add option to use file for host info (#156) 2020-04-29 14:21:31 +08:00
6 changed files with 223 additions and 61 deletions
+3 -1
View File
@@ -117,16 +117,18 @@ endif
docker push $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag) docker push $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag)
ssh-server: ssh-server:
adduser -h /home/drone-scp -s /bin/bash -D -S drone-scp adduser -h /home/drone-scp -s /bin/sh -D -S drone-scp
echo drone-scp:1234 | chpasswd echo drone-scp:1234 | chpasswd
mkdir -p /home/drone-scp/.ssh mkdir -p /home/drone-scp/.ssh
chmod 700 /home/drone-scp/.ssh chmod 700 /home/drone-scp/.ssh
cat tests/.ssh/id_rsa.pub >> /home/drone-scp/.ssh/authorized_keys cat tests/.ssh/id_rsa.pub >> /home/drone-scp/.ssh/authorized_keys
cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
chmod 600 /home/drone-scp/.ssh/authorized_keys
chown -R drone-scp /home/drone-scp/.ssh chown -R drone-scp /home/drone-scp/.ssh
# install ssh and start server # install ssh and start server
apk add --update openssh openrc apk add --update openssh openrc
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
./tests/entrypoint.sh /usr/sbin/sshd -D & ./tests/entrypoint.sh /usr/sbin/sshd -D &
+1 -1
View File
@@ -3,7 +3,7 @@ module github.com/appleboy/drone-ssh
go 1.14 go 1.14
require ( require (
github.com/appleboy/easyssh-proxy v1.3.1 github.com/appleboy/easyssh-proxy v1.3.6
github.com/joho/godotenv v1.3.0 github.com/joho/godotenv v1.3.0
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/urfave/cli v1.22.4 github.com/urfave/cli v1.22.4
+6 -2
View File
@@ -1,8 +1,12 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ScaleFT/sshkeys v0.0.0-20181112160850-82451a803681 h1:JS2rl38kZmHgWa0xINSaSYH0Whtvem64/4+Ef0+Y5pE= github.com/ScaleFT/sshkeys v0.0.0-20181112160850-82451a803681 h1:JS2rl38kZmHgWa0xINSaSYH0Whtvem64/4+Ef0+Y5pE=
github.com/ScaleFT/sshkeys v0.0.0-20181112160850-82451a803681/go.mod h1:WfDateMPQ/55dPbZRp5Zxrux5WiEaHsjk9puUhz0KgY= github.com/ScaleFT/sshkeys v0.0.0-20181112160850-82451a803681/go.mod h1:WfDateMPQ/55dPbZRp5Zxrux5WiEaHsjk9puUhz0KgY=
github.com/appleboy/easyssh-proxy v1.3.1 h1:zj5u800KIRPziMlJouhd2R6jufz6ihGlFSmojzXYSOw= github.com/appleboy/easyssh-proxy v1.3.4 h1:yNgzsJ9qaDNGzQILDXEK4boioJMmUUaTUsxYtCTSGqo=
github.com/appleboy/easyssh-proxy v1.3.1/go.mod h1:Kk57I3w7OCafOjp5kgZFvxk2fO8Tca5CriBTOsbSbjY= github.com/appleboy/easyssh-proxy v1.3.4/go.mod h1:Kk57I3w7OCafOjp5kgZFvxk2fO8Tca5CriBTOsbSbjY=
github.com/appleboy/easyssh-proxy v1.3.5 h1:EGTCbqAVRcGKHQMFSxz30lQmb+0nXL+jUiCrg/FjHQM=
github.com/appleboy/easyssh-proxy v1.3.5/go.mod h1:Kk57I3w7OCafOjp5kgZFvxk2fO8Tca5CriBTOsbSbjY=
github.com/appleboy/easyssh-proxy v1.3.6 h1:YELdI5z/NK/hSspkkcohSa9uJQxA4/e2H+f5jDD6pGA=
github.com/appleboy/easyssh-proxy v1.3.6/go.mod h1:Kk57I3w7OCafOjp5kgZFvxk2fO8Tca5CriBTOsbSbjY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+62 -26
View File
@@ -19,7 +19,6 @@ func main() {
if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found { if filename, found := os.LookupEnv("PLUGIN_ENV_FILE"); found {
_ = godotenv.Load(filename) _ = godotenv.Load(filename)
} }
app := cli.NewApp() app := cli.NewApp()
app.Name = "Drone SSH" app.Name = "Drone SSH"
app.Usage = "Executing remote ssh commands" app.Usage = "Executing remote ssh commands"
@@ -60,9 +59,25 @@ func main() {
EnvVar: "PLUGIN_PASSWORD,SSH_PASSWORD,PASSWORD,INPUT_PASSWORD", EnvVar: "PLUGIN_PASSWORD,SSH_PASSWORD,PASSWORD,INPUT_PASSWORD",
}, },
cli.StringSliceFlag{ cli.StringSliceFlag{
Name: "host,H", Name: "ciphers",
Usage: "connect to host", Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVar: "PLUGIN_HOST,SSH_HOST,HOST,INPUT_HOST", EnvVar: "PLUGIN_CIPHERS,SSH_CIPHERS,CIPHERS,INPUT_CIPHERS",
},
cli.BoolFlag{
Name: "useInsecureCipher",
Usage: "include more ciphers with use_insecure_cipher",
EnvVar: "PLUGIN_USE_INSECURE_CIPHER,SSH_USE_INSECURE_CIPHER,USE_INSECURE_CIPHER,INPUT_USE_INSECURE_CIPHER",
},
cli.StringFlag{
Name: "fingerprint",
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
EnvVar: "PLUGIN_FINGERPRINT,SSH_FINGERPRINT,FINGERPRINT,INPUT_FINGERPRINT",
},
cli.StringSliceFlag{
Name: "host,H",
Usage: "connect to host",
EnvVar: "PLUGIN_HOST,SSH_HOST,HOST,INPUT_HOST",
FilePath: ".host",
}, },
cli.IntFlag{ cli.IntFlag{
Name: "port,p", Name: "port,p",
@@ -144,6 +159,21 @@ func main() {
Usage: "proxy connection timeout", Usage: "proxy connection timeout",
EnvVar: "PLUGIN_PROXY_TIMEOUT,PROXY_SSH_TIMEOUT,INPUT_PROXY_TIMEOUT", EnvVar: "PLUGIN_PROXY_TIMEOUT,PROXY_SSH_TIMEOUT,INPUT_PROXY_TIMEOUT",
}, },
cli.StringSliceFlag{
Name: "proxy.ciphers",
Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVar: "PLUGIN_PROXY_CIPHERS,SSH_PROXY_CIPHERS,PROXY_CIPHERS,INPUT_PROXY_CIPHERS",
},
cli.BoolFlag{
Name: "proxy.useInsecureCipher",
Usage: "include more ciphers with use_insecure_cipher",
EnvVar: "PLUGIN_PROXY_USE_INSECURE_CIPHER,SSH_PROXY_USE_INSECURE_CIPHER,PROXY_USE_INSECURE_CIPHER,INPUT_PROXY_USE_INSECURE_CIPHER",
},
cli.StringFlag{
Name: "proxy.fingerprint",
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
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",
@@ -201,29 +231,35 @@ func run(c *cli.Context) error {
} }
plugin := Plugin{ plugin := Plugin{
Config: Config{ Config: Config{
Key: c.String("ssh-key"), Key: c.String("ssh-key"),
KeyPath: c.String("key-path"), KeyPath: c.String("key-path"),
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"),
Host: c.StringSlice("host"), Fingerprint: c.String("fingerprint"),
Port: c.Int("port"), Host: c.StringSlice("host"),
Timeout: c.Duration("timeout"), Port: c.Int("port"),
CommandTimeout: c.Duration("command.timeout"), Timeout: c.Duration("timeout"),
Script: scripts, CommandTimeout: c.Duration("command.timeout"),
ScriptStop: c.Bool("script.stop"), Script: scripts,
Envs: c.StringSlice("envs"), ScriptStop: c.Bool("script.stop"),
Debug: c.Bool("debug"), Envs: c.StringSlice("envs"),
Sync: c.Bool("sync"), Debug: c.Bool("debug"),
Sync: c.Bool("sync"),
Ciphers: c.StringSlice("ciphers"),
UseInsecureCipher: c.Bool("useInsecureCipher"),
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"),
Timeout: c.Duration("proxy.timeout"),
Ciphers: c.StringSlice("proxy.ciphers"),
UseInsecureCipher: c.Bool("proxy.useInsecureCipher"),
}, },
}, },
Writer: os.Stdout, Writer: os.Stdout,
+40 -31
View File
@@ -23,21 +23,24 @@ var (
type ( type (
// Config for the plugin. // Config for the plugin.
Config struct { Config struct {
Key string Key string
Passphrase string Passphrase string
KeyPath string KeyPath string
Username string Username string
Password string Password string
Host []string Host []string
Port int Port int
Timeout time.Duration Fingerprint string
CommandTimeout time.Duration Timeout time.Duration
Script []string CommandTimeout time.Duration
ScriptStop bool Script []string
Envs []string ScriptStop bool
Proxy easyssh.DefaultConfig Envs []string
Debug bool Proxy easyssh.DefaultConfig
Sync bool Debug bool
Sync bool
Ciphers []string
UseInsecureCipher bool
} }
// Plugin structure // Plugin structure
@@ -54,23 +57,29 @@ 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,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
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,
Fingerprint: p.Config.Proxy.Fingerprint,
UseInsecureCipher: p.Config.Proxy.UseInsecureCipher,
}, },
} }
+111
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
@@ -593,3 +669,38 @@ func TestPlugin_scriptCommands(t *testing.T) {
}) })
} }
} }
func TestUseInsecureCipher(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
mkdir a/b/c
mkdir d/e/f
======END======
err: mkdir: can't create directory 'a/b/c': No such file or directory
err: mkdir: can't create directory 'd/e/f': No such file or directory
`
)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"mkdir a/b/c",
"mkdir d/e/f",
},
CommandTimeout: 10 * time.Second,
UseInsecureCipher: true,
},
Writer: &buffer,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}