Skip to content

Commit

Permalink
Add functionality to skip host key verification
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklasfrahm committed Dec 11, 2021
1 parent 56a6854 commit f29ea1d
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 40 deletions.
49 changes: 25 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,30 +77,31 @@ jobs:
## Input variables
See [action.yml](./action.yml) for more detailed information.
- `host` - ssh host
- `port` - ssh port, default is `22`
- `username` - ssh username, default is `root`
- `passphrase` - ssh passphrase
- `insecure_password` - ssh password
- `timeout` - timeout for ssh to remote host, default is `30s`
- `action_timeout` - timeout for action, default is `10m`
- `key` - content of ssh private key, raw content of `~/.ssh/id_rsa`
- `fingerprint` - fingerprint SHA256 of the host public key, see [Using host fingerprint verification](#using-host-fingerprint-verification)
- `source` - a list of files to copy
- `target` - a folder to copy to, default is `.`
- `direction` - either _upload_ or _download_

SSH Proxy Settings:

- `proxy_host` - proxy host
- `proxy_port` - proxy port, default is `22`
- `proxy_username` - proxy username, default is `root`
- `passphrase` - ssh proxy passphrase
- `insecure_proxy_password` - ssh proxy password
- `proxy_key` - content of ssh proxy private key.
- `proxy_fingerprint` - fingerprint SHA256 of the proxy host public key, see [Using host fingerprint verification](#using-host-fingerprint-verification)
See [action.yml](./action.yml) for more detailed information. **Please note that all input variables must have string values. It is thus recommend to always use quotes.**
| Input variable | Default value | Description |
| ----------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `host` | _required_ | SSH host |
| `port` | `22` | SSH port |
| `username` | `root` | SSH username |
| `passphrase` | _none_ | SSH passphrase |
| `insecure_password` | _none_ | SSH password, not recommended for security reasons |
| `timeout` | `30s` | Timeout for SSH connection to remote host |
| `action_timeout` | `10m` | Timeout for action |
| `key` | _none_ | Content of ssh private key, raw content of `~/.ssh/id_rsa` |
| `fingerprint` | _none_ | Fingerprint SHA256 of the host public key, see [Using host fingerprint verification](#using-host-fingerprint-verification) |
| `insecure_ignore_fingerprint` | `false` | Skip fingerprint verification of the host public key, not recommended for security reasons |
| `source` | _required_ | A list of files to copy |
| `target` | `.` | A folder to copy to |
| `direction` | _none_ | Transfer direction, must be either `upload` or `download` |
| `proxy_host` | _none_ | SSH proxy host |
| `proxy_port` | `22` | SSH proxy port |
| `proxy_username` | `root` | SSH proxy username |
| `passphrase` | _none_ | SSH proxy passphrase |
| `insecure_proxy_password` | _none_ | SSH proxy password |
| `proxy_key` | _none_ | Content of SSH proxy private key |
| `proxy_fingerprint` | _none_ | Fingerprint SHA256 of the proxy host public key, see [Using host fingerprint verification](#using-host-fingerprint-verification) |
| `insecure_proxy_ignore_fingerprint` | _none_ | Skip fingerprint verification of the proxy host public key, not recommended for security reasons |

## Using host fingerprint verification

Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ inputs:
fingerprint:
description: "sha256 fingerprint of the host public key"
required: yes
insecure_ignore_fingerprint:
description: "skip fingerprint verification of the host public key"
default: "false"
proxy_host:
description: "ssh proxy host"
proxy_port:
Expand All @@ -56,6 +59,9 @@ inputs:
description: "content of ssh proxy private key. ex raw content of ~/.ssh/id_rsa"
proxy_fingerprint:
description: "sha256 fingerprint of the proxy host public key"
insecure_proxy_ignore_fingerprint:
description: "skip fingerprint verification of the proxy host public key"
default: "false"

runs:
using: "docker"
Expand All @@ -73,13 +79,15 @@ runs:
INSECURE_PASSWORD: ${{ inputs.insecure_password }}
KEY: ${{ inputs.key }}
FINGERPRINT: ${{ inputs.fingerprint }}
INSECURE_IGNORE_FINGERPRINT: ${{ inputs.insecure_ignore_fingerprint }}
PROXY_HOST: ${{ inputs.proxy_host }}
PROXY_PORT: ${{ inputs.proxy_port }}
PROXY_USERNAME: ${{ inputs.proxy_username }}
PROXY_PASSPHRASE: ${{ inputs.proxy_passphrase }}
INSECURE_PROXY_PASSWORD: ${{ inputs.insecure_proxy_password }}
PROXY_KEY: ${{ inputs.proxy_key }}
PROXY_FINGERPRINT: ${{ inputs.proxy_fingerprint }}
INSECURE_PROXY_IGNORE_FINGERPRINT: ${{ inputs.insecure_proxy_ignore_fingerprint }}

branding:
icon: "copy"
Expand Down
41 changes: 25 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func main() {
Timeout: timeout,
User: os.Getenv("USERNAME"),
Auth: ConfigureAuthentication(os.Getenv("KEY"), os.Getenv("PASSPHRASE"), os.Getenv("INSECURE_PASSWORD")),
HostKeyCallback: VerifyFingerprint(os.Getenv("FINGERPRINT")),
HostKeyCallback: ConfigureHostKeyCallback(os.Getenv("FINGERPRINT"), os.Getenv("INSECURE_IGNORE_FINGERPRINT")),
}

// Configure target address.
Expand All @@ -77,7 +77,7 @@ func main() {
Timeout: timeout,
User: os.Getenv("PROXY_USERNAME"),
Auth: ConfigureAuthentication(os.Getenv("PROXY_KEY"), os.Getenv("PROXY_PASSPHRASE"), os.Getenv("INSECURE_PROXY_PASSWORD")),
HostKeyCallback: VerifyFingerprint(os.Getenv("PROXY_FINGERPRINT")),
HostKeyCallback: ConfigureHostKeyCallback(os.Getenv("PROXY_FINGERPRINT"), os.Getenv("INSECURE_PROXY_IGNORE_FINGERPRINT")),
}

// Establish SSH session to proxy host.
Expand Down Expand Up @@ -110,18 +110,6 @@ func main() {
Copy(targetClient)
}

// VerifyFingerprint takes an ssh key fingerprint as an argument and verifies it against and SSH public key.
func VerifyFingerprint(expected string) ssh.HostKeyCallback {
return func(hostname string, remote net.Addr, pubKey ssh.PublicKey) error {
fingerprint := ssh.FingerprintSHA256(pubKey)
if fingerprint != expected {
return errors.New("fingerprint mismatch: server fingerprint: " + fingerprint)
}

return nil
}
}

// Copy transfers files between remote host and local machine.
func Copy(client *ssh.Client) {
sourceFiles := strings.Split(os.Getenv("SOURCE"), "\n")
Expand Down Expand Up @@ -171,11 +159,11 @@ func Copy(client *ssh.Client) {
func ConfigureAuthentication(key string, passphrase string, password string) []ssh.AuthMethod {
// Create signer for public key authentication method.
auth := make([]ssh.AuthMethod, 1)

if key != "" {
var err error
var targetSigner ssh.Signer

if passphrase != "" {
targetSigner, err = ssh.ParsePrivateKeyWithPassphrase([]byte(key), []byte(passphrase))
} else {
Expand All @@ -199,3 +187,24 @@ func ConfigureAuthentication(key string, passphrase string, password string) []s

return auth
}

// ConfigureHostKeyCallback configures the SSH host key verification callback.
// Unless the `skip` option is set to `string("true")` it will return a function,
// which verifies the host key against the specified ssh key fingerprint.
func ConfigureHostKeyCallback(expected string, skip string) ssh.HostKeyCallback {
if skip == "true" {
log.Println("⚠️ Skipping host key verification is insecure!")
log.Println("⚠️ This allows for person-in-the-middle attacks!")
log.Println("⚠️ Please consider using host key verification!")
return ssh.InsecureIgnoreHostKey()
}

return func(hostname string, remote net.Addr, pubKey ssh.PublicKey) error {
fingerprint := ssh.FingerprintSHA256(pubKey)
if fingerprint != expected {
return errors.New("fingerprint mismatch: server fingerprint: " + fingerprint)
}

return nil
}
}

0 comments on commit f29ea1d

Please sign in to comment.