Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add options to authenticate using a private key #155

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ You can override the default configuration with the following parameters:
* `port` - Server port, default to 22
* `username` - Server username, default to blank
* `password` - Password for password-based authentication
* `key` - Private key for public-key-based authentication
* `key_path` - Private key path for public-key-based authentication
* `passphrase` - Passphrase of your key for public-key-based authentication (optional)
* `destination_path` - Target path on the server, default to '/'
* `files` - List of files to upload

All file paths must be relative to current project sources

## Example
## Examples

The following is a sample configuration in your .drone.yml file:
Sample configuration using a password in your .drone.yml file:

```yaml
publish:
Expand All @@ -21,6 +24,21 @@ publish:
port: 2222
username: user
password: pa$$word
files:
files:
- *.nupkg
```

Sample configuration using a private key saved as a secret in your .drone.yml file:

```yaml
publish:
sftp:
host: sftp.company.com
port: 2222
username: user
key:
from_secret: sftp_private_key
passphrase: my_passphrase
files:
- *.nupkg
```
66 changes: 60 additions & 6 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type (
Port int `envconfig:"PLUGIN_PORT"`
Username string `envconfig:"PLUGIN_USERNAME"`
Password string `envconfig:"PLUGIN_PASSWORD"`
Key string `envconfig:"PLUGIN_KEY"`
KeyPath string `envconfig:"PLUGIN_KEY_PATH"`
Passphrase string `envconfig:"PLUGIN_PASSPHRASE"`
Files []string `envconfig:"PLUGIN_FILES"`
Destination string `envconfig:"PLUGIN_DESTINATION_PATH"`
}
Expand Down Expand Up @@ -130,8 +133,8 @@ func verifyArgs(args *Args) error {
return fmt.Errorf("no username provided: %w", errConfiguration)
}

if args.Password == "" {
return fmt.Errorf("no password provided: %w", errConfiguration)
if args.Password == "" && args.Key == "" && args.KeyPath == "" {
return fmt.Errorf("no password or key provided: %w", errConfiguration)
}

if args.Host == "" {
Expand Down Expand Up @@ -171,12 +174,15 @@ func findFileUploads(args *Args) ([]string, error) {
}

func createSftpClient(args *Args) (*sftp.Client, error) {
authMethods, err := createSftpAuthMethods(args)
if err != nil {
return nil, err
}

server := fmt.Sprintf("%s:%d", args.Host, args.Port)
config := &ssh.ClientConfig{
User: args.Username,
Auth: []ssh.AuthMethod{
ssh.Password(args.Password),
},
User: args.Username,
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

Expand All @@ -197,6 +203,54 @@ func createSftpClient(args *Args) (*sftp.Client, error) {
return client, nil
}

func createSftpAuthMethods(args *Args) ([]ssh.AuthMethod, error) {
var methods []ssh.AuthMethod

if args.Password != "" {
methods = append(methods, ssh.Password(args.Password))
}

if args.Key != "" {
signer, err := parsePrivateKey([]byte(args.Key), []byte(args.Passphrase))
if err != nil {
return nil, err
}
methods = append(methods, ssh.PublicKeys(signer))
}

if args.KeyPath != "" {
buffer, err := os.ReadFile(args.KeyPath)
if err != nil {
return nil, fmt.Errorf("could not read private key: %w", err)
}
signer, err := parsePrivateKey(buffer, []byte(args.Passphrase))
if err != nil {
return nil, err
}
methods = append(methods, ssh.PublicKeys(signer))
}

if len(methods) > 0 {
return methods, nil
} else {
return nil, fmt.Errorf("could not determinate an sftp auth method")
}
}

func parsePrivateKey(key []byte, passphrase []byte) (ssh.Signer, error) {
var signer ssh.Signer
var err error
if len(passphrase) > 0 {
signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
} else {
signer, err = ssh.ParsePrivateKey(key)
}
if err != nil {
return nil, fmt.Errorf("could not parse private key: %w", err)
}
return signer, nil
}

func createDirectory(client *sftp.Client, directory string) error {
if directory == defaultDirectory {
return nil
Expand Down