Skip to content

Commit 61da9cd

Browse files
committed
Add options to authenticate using a private key
1 parent 8a0c92a commit 61da9cd

File tree

2 files changed

+81
-9
lines changed

2 files changed

+81
-9
lines changed

DOCS.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ You can override the default configuration with the following parameters:
55
* `port` - Server port, default to 22
66
* `username` - Server username, default to blank
77
* `password` - Password for password-based authentication
8+
* `key` - Private key for public-key-based authentication
9+
* `key_path` - Private key path for public-key-based authentication
10+
* `passphrase` - Passphrase of your key for public-key-based authentication (optional)
811
* `destination_path` - Target path on the server, default to '/'
912
* `files` - List of files to upload
1013

1114
All file paths must be relative to current project sources
1215

13-
## Example
16+
## Examples
1417

15-
The following is a sample configuration in your .drone.yml file:
18+
Sample configuration using a password in your .drone.yml file:
1619

1720
```yaml
1821
publish:
@@ -21,6 +24,21 @@ publish:
2124
port: 2222
2225
username: user
2326
password: pa$$word
24-
files:
27+
files:
28+
- *.nupkg
29+
```
30+
31+
Sample configuration using a private key saved as a secret in your .drone.yml file:
32+
33+
```yaml
34+
publish:
35+
sftp:
36+
host: sftp.company.com
37+
port: 2222
38+
username: user
39+
key:
40+
from_secret: sftp_private_key
41+
passphrase: my_passphrase
42+
files:
2543
- *.nupkg
2644
```

plugin/plugin.go

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ type (
3737
Port int `envconfig:"PLUGIN_PORT"`
3838
Username string `envconfig:"PLUGIN_USERNAME"`
3939
Password string `envconfig:"PLUGIN_PASSWORD"`
40+
Key string `envconfig:"PLUGIN_KEY"`
41+
KeyPath string `envconfig:"PLUGIN_KEY_PATH"`
42+
Passphrase string `envconfig:"PLUGIN_PASSPHRASE"`
4043
Files []string `envconfig:"PLUGIN_FILES"`
4144
Destination string `envconfig:"PLUGIN_DESTINATION_PATH"`
4245
}
@@ -130,8 +133,8 @@ func verifyArgs(args *Args) error {
130133
return fmt.Errorf("no username provided: %w", errConfiguration)
131134
}
132135

133-
if args.Password == "" {
134-
return fmt.Errorf("no password provided: %w", errConfiguration)
136+
if args.Password == "" && args.Key == "" && args.KeyPath == "" {
137+
return fmt.Errorf("no password or key provided: %w", errConfiguration)
135138
}
136139

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

173176
func createSftpClient(args *Args) (*sftp.Client, error) {
177+
authMethods, err := createSftpAuthMethods(args)
178+
if err != nil {
179+
return nil, err
180+
}
181+
174182
server := fmt.Sprintf("%s:%d", args.Host, args.Port)
175183
config := &ssh.ClientConfig{
176-
User: args.Username,
177-
Auth: []ssh.AuthMethod{
178-
ssh.Password(args.Password),
179-
},
184+
User: args.Username,
185+
Auth: authMethods,
180186
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
181187
}
182188

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

206+
func createSftpAuthMethods(args *Args) ([]ssh.AuthMethod, error) {
207+
var methods []ssh.AuthMethod
208+
209+
if args.Password != "" {
210+
methods = append(methods, ssh.Password(args.Password))
211+
}
212+
213+
if args.Key != "" {
214+
signer, err := parsePrivateKey([]byte(args.Key), []byte(args.Passphrase))
215+
if err != nil {
216+
return nil, err
217+
}
218+
methods = append(methods, ssh.PublicKeys(signer))
219+
}
220+
221+
if args.KeyPath != "" {
222+
buffer, err := os.ReadFile(args.KeyPath)
223+
if err != nil {
224+
return nil, fmt.Errorf("could not read private key: %w", err)
225+
}
226+
signer, err := parsePrivateKey(buffer, []byte(args.Passphrase))
227+
if err != nil {
228+
return nil, err
229+
}
230+
methods = append(methods, ssh.PublicKeys(signer))
231+
}
232+
233+
if len(methods) > 0 {
234+
return methods, nil
235+
} else {
236+
return nil, fmt.Errorf("could not determinate an sftp auth method")
237+
}
238+
}
239+
240+
func parsePrivateKey(key []byte, passphrase []byte) (ssh.Signer, error) {
241+
var signer ssh.Signer
242+
var err error
243+
if len(passphrase) > 0 {
244+
signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
245+
} else {
246+
signer, err = ssh.ParsePrivateKey(key)
247+
}
248+
if err != nil {
249+
return nil, fmt.Errorf("could not parse private key: %w", err)
250+
}
251+
return signer, nil
252+
}
253+
200254
func createDirectory(client *sftp.Client, directory string) error {
201255
if directory == defaultDirectory {
202256
return nil

0 commit comments

Comments
 (0)