forked from TrueCloudLab/rclone
sftp: add support for using ssh key files #1494
Update docs about macOS and ssh-agent #1218
This commit is contained in:
parent
b44d0ea088
commit
d55f8f0492
2 changed files with 67 additions and 20 deletions
|
@ -21,17 +21,14 @@ Here is an example of making a SFTP configuration. First run
|
|||
|
||||
rclone config
|
||||
|
||||
This will guide you through an interactive setup process. You will
|
||||
need your account number (a short hex number) and key (a long hex
|
||||
number) which you can get from the SFTP control panel.
|
||||
This will guide you through an interactive setup process.
|
||||
|
||||
```
|
||||
No remotes found - make a new one
|
||||
n) New remote
|
||||
r) Rename remote
|
||||
c) Copy remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
n/r/c/s/q> n
|
||||
n/s/q> n
|
||||
name> remote
|
||||
Type of storage to configure.
|
||||
Choose a number from below, or type in your own value
|
||||
|
@ -63,6 +60,8 @@ Choose a number from below, or type in your own value
|
|||
\ "sftp"
|
||||
14 / Yandex Disk
|
||||
\ "yandex"
|
||||
15 / http Connection
|
||||
\ "http"
|
||||
Storage> sftp
|
||||
SSH host to connect to
|
||||
Choose a number from below, or type in your own value
|
||||
|
@ -70,21 +69,24 @@ Choose a number from below, or type in your own value
|
|||
\ "example.com"
|
||||
host> example.com
|
||||
SSH username, leave blank for current username, ncw
|
||||
user>
|
||||
user> sftpuser
|
||||
SSH port, leave blank to use default (22)
|
||||
port>
|
||||
SSH password, leave blank to use ssh-agent
|
||||
SSH password, leave blank to use ssh-agent.
|
||||
y) Yes type in my own password
|
||||
g) Generate random password
|
||||
n) No leave this optional password blank
|
||||
y/g/n> n
|
||||
Path to unencrypted PEM-encoded private key file, leave blank to use ssh-agent.
|
||||
key_file>
|
||||
Remote config
|
||||
--------------------
|
||||
[remote]
|
||||
host = example.com
|
||||
user =
|
||||
user = sftpuser
|
||||
port =
|
||||
pass =
|
||||
key_file =
|
||||
--------------------
|
||||
y) Yes this is OK
|
||||
e) Edit this remote
|
||||
|
@ -111,6 +113,34 @@ excess files in the directory.
|
|||
|
||||
rclone sync /home/local/directory remote:directory
|
||||
|
||||
### SSH Authentication ###
|
||||
|
||||
The SFTP remote supports 3 authentication methods
|
||||
|
||||
* Password
|
||||
* Key file
|
||||
* ssh-agent
|
||||
|
||||
Key files should be unencrypted PEM-encoded private key files. For
|
||||
instance `/home/$USER/.ssh/id_rsa`.
|
||||
|
||||
If you don't specify `pass` or `key_file` then it will attempt to
|
||||
contact an ssh-agent.
|
||||
|
||||
### ssh-agent on macOS ###
|
||||
|
||||
Note that there seem to be various problems with using an ssh-agent on
|
||||
macOS due to recent changes in the OS. The most effective work-around
|
||||
seems to be to start an ssh-agent in each session, eg
|
||||
|
||||
eval `ssh-agent -s` && ssh-add -A
|
||||
|
||||
And then at the end of the session
|
||||
|
||||
eval `ssh-agent -k`
|
||||
|
||||
These commands can be used in scripts of course.
|
||||
|
||||
### Modified time ###
|
||||
|
||||
Modified times are stored on the server to 1 second precision.
|
||||
|
|
39
sftp/sftp.go
39
sftp/sftp.go
|
@ -6,6 +6,7 @@ package sftp
|
|||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
@ -40,9 +41,13 @@ func init() {
|
|||
Optional: true,
|
||||
}, {
|
||||
Name: "pass",
|
||||
Help: "SSH password, leave blank to use ssh-agent",
|
||||
Help: "SSH password, leave blank to use ssh-agent.",
|
||||
Optional: true,
|
||||
IsPassword: true,
|
||||
}, {
|
||||
Name: "key_file",
|
||||
Help: "Path to unencrypted PEM-encoded private key file, leave blank to use ssh-agent.",
|
||||
Optional: true,
|
||||
}},
|
||||
}
|
||||
fs.Register(fsi)
|
||||
|
@ -79,6 +84,7 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||
host := fs.ConfigFileGet(name, "host")
|
||||
port := fs.ConfigFileGet(name, "port")
|
||||
pass := fs.ConfigFileGet(name, "pass")
|
||||
keyFile := fs.ConfigFileGet(name, "key_file")
|
||||
if user == "" {
|
||||
user = os.Getenv("USER")
|
||||
}
|
||||
|
@ -91,7 +97,9 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
Timeout: fs.Config.ConnectTimeout,
|
||||
}
|
||||
if pass == "" {
|
||||
|
||||
// Add ssh agent-auth if no password or file specified
|
||||
if pass == "" && keyFile == "" {
|
||||
sshAgentClient, _, err := sshagent.New()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "couldn't connect to ssh-agent")
|
||||
|
@ -100,22 +108,31 @@ func NewFs(name, root string) (fs.Fs, error) {
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "couldn't read ssh agent signers")
|
||||
}
|
||||
/*
|
||||
for i, signer := range signers {
|
||||
if 2*i < len(signers) {
|
||||
signers[i] = signers[len(signers)-i-1]
|
||||
signers[len(signers)-i-1] = signer
|
||||
}
|
||||
}
|
||||
*/
|
||||
config.Auth = append(config.Auth, ssh.PublicKeys(signers...))
|
||||
} else {
|
||||
}
|
||||
|
||||
// Load key file if specified
|
||||
if keyFile != "" {
|
||||
key, err := ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read private key file")
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse private key file")
|
||||
}
|
||||
config.Auth = append(config.Auth, ssh.PublicKeys(signer))
|
||||
}
|
||||
|
||||
// Auth from password if specified
|
||||
if pass != "" {
|
||||
clearpass, err := fs.Reveal(pass)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Auth = append(config.Auth, ssh.Password(clearpass))
|
||||
}
|
||||
|
||||
sshClient, err := ssh.Dial("tcp", host+":"+port, config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "couldn't connect ssh")
|
||||
|
|
Loading…
Add table
Reference in a new issue