diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index c0cb928f5..0cda21c2f 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -82,6 +82,11 @@ func init() { Only PEM encrypted key files (old OpenSSH format) are supported. Encrypted keys in the new OpenSSH format can't be used.`, IsPassword: true, + }, { + Name: "pubkey_file", + Help: `Optional path to public key file. + +Set this if you have a signed certificate you want to use for authentication.` + env.ShellExpandHelp, }, { Name: "key_use_agent", Help: `When set forces the usage of the ssh-agent. @@ -190,6 +195,7 @@ type Options struct { KeyPem string `config:"key_pem"` KeyFile string `config:"key_file"` KeyFilePass string `config:"key_file_pass"` + PubKeyFile string `config:"pubkey_file"` KeyUseAgent bool `config:"key_use_agent"` UseInsecureCipher bool `config:"use_insecure_cipher"` DisableHashCheck bool `config:"disable_hashcheck"` @@ -438,6 +444,7 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) { } keyFile := env.ShellExpand(opt.KeyFile) + pubkeyFile := env.ShellExpand(opt.PubKeyFile) //keyPem := env.ShellExpand(opt.KeyPem) // Add ssh agent-auth if no password or file or key PEM specified if (opt.Pass == "" && keyFile == "" && !opt.AskPassword && opt.KeyPem == "") || opt.KeyUseAgent { @@ -507,7 +514,38 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) { if err != nil { return nil, errors.Wrap(err, "failed to parse private key file") } - sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeys(signer)) + + // If a public key has been specified then use that + if pubkeyFile != "" { + certfile, err := ioutil.ReadFile(pubkeyFile) + if err != nil { + return nil, errors.Wrap(err, "unable to read cert file") + } + + pk, _, _, _, err := ssh.ParseAuthorizedKey(certfile) + if err != nil { + return nil, errors.Wrap(err, "unable to parse cert file") + } + + // And the signer for this, which includes the private key signer + // This is what we'll pass to the ssh client. + // Normally the ssh client will use the public key built + // into the private key, but we need to tell it to use the user + // specified public key cert. This signer is specific to the + // cert and will include the private key signer. Now ssh + // knows everything it needs. + cert, ok := pk.(*ssh.Certificate) + if !ok { + return nil, errors.New("public key file is not a certificate file: " + pubkeyFile) + } + pubsigner, err := ssh.NewCertSigner(cert, signer) + if err != nil { + return nil, errors.Wrap(err, "error generating cert signer") + } + sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeys(pubsigner)) + } else { + sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeys(signer)) + } } // Auth from password if specified diff --git a/docs/content/sftp.md b/docs/content/sftp.md index bc13b1909..a354c29e2 100644 --- a/docs/content/sftp.md +++ b/docs/content/sftp.md @@ -102,7 +102,7 @@ excess files in the directory. The SFTP remote supports three authentication methods: * Password - * Key file + * Key file, including certificate signed keys * ssh-agent Key files should be PEM-encoded private key files. For instance `/home/$USER/.ssh/id_rsa`. @@ -128,6 +128,26 @@ Using an ssh-agent is the only way to load encrypted OpenSSH keys at the moment. If you set the `--sftp-ask-password` option, rclone will prompt for a password when needed and no password has been configured. +If you have a certificate then you can provide the path to the public key that contains the certificate. For example: + +``` +[remote] +type = sftp +host = example.com +user = sftpuser +key_file = ~/id_rsa +pubkey_file = ~/id_rsa-cert.pub +```` + +If you concatenate a cert with a private key then you can specify the +merged file in both places. + +Note: the cert must come first in the file. e.g. + +``` +cat id_rsa-cert.pub id_rsa > merged_key +``` + ### ssh-agent on macOS ### Note that there seem to be various problems with using an ssh-agent on @@ -234,6 +254,18 @@ in the new OpenSSH format can't be used. - Type: string - Default: "" +#### --sftp-pubkey-file + +Optional path to public key file; set this if you have a signed certificate you want to use for authentication. + +Leading `~` will be expanded in the file name as will environment variables such as `${RCLONE_CONFIG_DIR}`. + + +- Config: pubkey_file +- Env Var: RCLONE_SFTP_PUBKEY_FILE +- Type: string +- Default: "" + #### --sftp-key-use-agent When set forces the usage of the ssh-agent.