Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
ad6643f705 | |||
26dd2b3a38 | |||
122f35dca5 | |||
03b5d10ad6 | |||
fcfb760891 | |||
fd81fae289 | |||
242a8e2e57 | |||
cfe9c45db6 | |||
73767290ca | |||
e5c07fceef | |||
d690bdebf8 | |||
f478af9b34 | |||
d520c19f4f | |||
0dee98b334 | |||
9085f3ea5b | |||
696aab4627 | |||
a88f6f2013 | |||
6f091cd9e3 | |||
aa1ecdd19a | |||
bffdd4e1f4 | |||
f4890bec77 | |||
9aaf218321 | |||
a2d5832a97 | |||
49e81b4a32 | |||
04535147e0 | |||
533a062133 | |||
ef697c0ac1 | |||
480ff5e05e | |||
ccece0c886 | |||
7e0bb7cd75 | |||
dc9ae8e2e3 | |||
d0bd170212 | |||
54eb169e33 | |||
1a6f86cece | |||
917a1df2a4 | |||
b87ddeff00 | |||
4f7d6491f3 | |||
1f7ce4dfab | |||
46adad98f2 | |||
215a0580d7 | |||
b305709c8d | |||
fd26aa3ca7 |
45
.github/main.workflow
vendored
45
.github/main.workflow
vendored
@ -1,45 +0,0 @@
|
||||
workflow "Remote ssh commands" {
|
||||
on = "push"
|
||||
resolves = [
|
||||
"Executing remote ssh commands",
|
||||
"Support Private Key",
|
||||
"Multiple Commands",
|
||||
]
|
||||
}
|
||||
|
||||
action "Executing remote ssh commands" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"HOST",
|
||||
"PASSWORD",
|
||||
]
|
||||
args = [
|
||||
"--user", "actions",
|
||||
"--script", "whoami",
|
||||
]
|
||||
}
|
||||
|
||||
action "Support Private Key" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"HOST",
|
||||
"KEY",
|
||||
]
|
||||
args = [
|
||||
"--user", "actions",
|
||||
"--script", "'ls -al'",
|
||||
]
|
||||
}
|
||||
|
||||
action "Multiple Commands" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"HOST",
|
||||
"KEY",
|
||||
]
|
||||
args = [
|
||||
"--user", "actions",
|
||||
"--script", "'whoami'",
|
||||
"--script", "'ls -al'",
|
||||
]
|
||||
}
|
94
.github/workflows/ci.yml
vendored
Normal file
94
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
name: remote ssh command
|
||||
on: [push]
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: executing remote ssh commands using password
|
||||
uses: ./
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
password: ${{ secrets.PASSWORD }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: whoami
|
||||
|
||||
- name: executing remote ssh commands using ssh key
|
||||
uses: ./
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: whoami
|
||||
|
||||
- name: multiple command
|
||||
uses: ./
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
whoami
|
||||
ls -al
|
||||
|
||||
# - name: stop script if command error
|
||||
# uses: ./
|
||||
# with:
|
||||
# host: ${{ secrets.HOST }}
|
||||
# username: ${{ secrets.USERNAME }}
|
||||
# key: ${{ secrets.KEY }}
|
||||
# port: ${{ secrets.PORT }}
|
||||
# script_stop: true
|
||||
# script: |
|
||||
# mkdir abc/def
|
||||
# ls -al
|
||||
|
||||
- name: pass environment
|
||||
uses: ./
|
||||
env:
|
||||
FOO: "BAR"
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
envs: FOO
|
||||
script: |
|
||||
echo "I am $FOO, thanks"
|
||||
echo "I am $BAR, thanks"
|
||||
|
||||
- name: pass multiple environment
|
||||
uses: ./
|
||||
env:
|
||||
FOO: "BAR"
|
||||
BAR: "FOO"
|
||||
SHA: ${{ github.sha }}
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
envs: FOO,BAR,SHA
|
||||
script: |
|
||||
echo "I am $FOO, thanks"
|
||||
echo "I am $BAR, thanks"
|
||||
echo "sha: $SHA"
|
||||
|
||||
- name: ssh key passphrase
|
||||
uses: ./
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.SSH2 }}
|
||||
port: ${{ secrets.PORT }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
script: |
|
||||
whoami
|
||||
ls -al
|
13
Dockerfile
13
Dockerfile
@ -1,15 +1,4 @@
|
||||
FROM appleboy/drone-ssh:1.5.1-linux-amd64
|
||||
|
||||
# Github labels
|
||||
LABEL "com.github.actions.name"="SSH Commands"
|
||||
LABEL "com.github.actions.description"="Executing remote ssh commands"
|
||||
LABEL "com.github.actions.icon"="terminal"
|
||||
LABEL "com.github.actions.color"="gray-dark"
|
||||
|
||||
LABEL "repository"="https://github.com/appleboy/ssh-action"
|
||||
LABEL "homepage"="https://github.com/appleboy"
|
||||
LABEL "maintainer"="Bo-Yi Wu <appleboy.tw@gmail.com>"
|
||||
LABEL "version"="0.0.2"
|
||||
FROM appleboy/drone-ssh:1.5.7-linux-amd64
|
||||
|
||||
ADD entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
322
README.md
322
README.md
@ -1,132 +1,258 @@
|
||||
# 🚀 SSH for GitHub Actions
|
||||
|
||||
[GitHub Action](https://developer.github.com/actions/) for executing remote ssh commands.
|
||||
[GitHub Action](https://github.com/features/actions) for executing remote ssh commands.
|
||||
|
||||
<img src="./images/ssh-workflow.png">
|
||||

|
||||
|
||||
[](https://github.com/appleboy/ssh-action/actions)
|
||||
|
||||
## Usage
|
||||
|
||||
Executing remote ssh commands.
|
||||
|
||||
```
|
||||
action "Executing remote ssh commands" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"HOST",
|
||||
"PASSWORD",
|
||||
]
|
||||
args = [
|
||||
"--user", "actions",
|
||||
"--script", "whoami",
|
||||
]
|
||||
}
|
||||
```yaml
|
||||
name: remote ssh command
|
||||
on: [push]
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: executing remote ssh commands using password
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
password: ${{ secrets.PASSWORD }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: whoami
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
output:
|
||||
|
||||
* HOST - ssh server host
|
||||
* PORT - ssh server port
|
||||
* USERNAME - ssh server username
|
||||
* PASSWORD - ssh server password
|
||||
* KEY - ssh server private key
|
||||
* SCRIPT - execute the scripts
|
||||
```sh
|
||||
======CMD======
|
||||
whoami
|
||||
======END======
|
||||
out: ***
|
||||
==============================================
|
||||
✅ Successfully executed commands to all host.
|
||||
==============================================
|
||||
```
|
||||
|
||||
## Input variables
|
||||
|
||||
See [action.yml](./action.yml) for more detailed information.
|
||||
|
||||
* host - ssh host
|
||||
* port - ssh port, default is `22`
|
||||
* username - ssh username
|
||||
* password - ssh password
|
||||
* passphrase - the passphrase is usually to encrypt the private key
|
||||
* sync - synchronous execution if multiple hosts, default is false
|
||||
* timeout - timeout for ssh to remote host, default is `30s`
|
||||
* command_timeout - timeout for ssh command, default is `10m`
|
||||
* key - content of ssh private key. ex raw content of ~/.ssh/id_rsa
|
||||
* key_path - path of ssh private key
|
||||
* script - execute commands
|
||||
* script_stop - stop script after first failure
|
||||
* envs - pass environment variable to shell script
|
||||
* debug - enable debug mode
|
||||
|
||||
SSH Proxy Setting:
|
||||
|
||||
* proxy_host - proxy host
|
||||
* proxy_port - proxy port, default is `22`
|
||||
* proxy_username - proxy username
|
||||
* proxy_password - proxy password
|
||||
* proxy_passphrase - the passphrase is usually to encrypt the private key
|
||||
* proxy_timeout - timeout for ssh to proxy host, default is `30s`
|
||||
* proxy_key - content of ssh proxy private key.
|
||||
* proxy_key_path - path of ssh proxy private key
|
||||
|
||||
### Example
|
||||
|
||||
Executing remote ssh commands.
|
||||
Executing remote ssh commands using password.
|
||||
|
||||
```
|
||||
action "Executing remote ssh commands" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"PASSWORD",
|
||||
]
|
||||
args = [
|
||||
"--host", "foo.com"
|
||||
"--user", "bar",
|
||||
"--script", "whoami",
|
||||
]
|
||||
}
|
||||
```yaml
|
||||
- name: executing remote ssh commands using password
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
password: ${{ secrets.PASSWORD }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: whoami
|
||||
```
|
||||
|
||||
Using private key
|
||||
|
||||
```
|
||||
action "Support Private Key" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"HOST",
|
||||
"KEY",
|
||||
]
|
||||
args = [
|
||||
"--user", "actions",
|
||||
"--script", "'ls -al'",
|
||||
]
|
||||
}
|
||||
```yaml
|
||||
- name: executing remote ssh commands using ssh key
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: whoami
|
||||
```
|
||||
|
||||
Multiple Commands
|
||||
|
||||
```
|
||||
action "Multiple Commands" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"HOST",
|
||||
"KEY",
|
||||
]
|
||||
args = [
|
||||
"--user", "actions",
|
||||
"--script", "'whoami'",
|
||||
"--script", "'ls -al'",
|
||||
]
|
||||
}
|
||||
```yaml
|
||||
- name: multiple command
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
whoami
|
||||
ls -al
|
||||
```
|
||||
|
||||
<img src="./images/multiple-command-result.png">
|
||||

|
||||
|
||||
Multiple Hosts
|
||||
|
||||
```
|
||||
action "Multiple Hosts" {
|
||||
uses = "appleboy/ssh-action@master"
|
||||
secrets = [
|
||||
"KEY",
|
||||
]
|
||||
args = [
|
||||
"--host", "foo.com",
|
||||
"--host", "bar.com",
|
||||
"--user", "actions",
|
||||
"--script", "'whoami'",
|
||||
"--script", "'ls -al'",
|
||||
"--script", "'cat test.txt'",
|
||||
]
|
||||
}
|
||||
```diff
|
||||
- name: multiple host
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
- host: "foo.com"
|
||||
+ host: "foo.com,bar.com"
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
whoami
|
||||
ls -al
|
||||
```
|
||||
|
||||
see the detail of `drone-ssh` command
|
||||
Synchronous execution on multiple hosts
|
||||
|
||||
```
|
||||
--ssh-key value private ssh key [$PLUGIN_SSH_KEY, $PLUGIN_KEY, $SSH_KEY, $KEY]
|
||||
--key-path value, -i value ssh private key path [$PLUGIN_KEY_PATH, $SSH_KEY_PATH, $PATH]
|
||||
--username value, --user value, -u value connect as user (default: "root") [$PLUGIN_USERNAME, $PLUGIN_USER, $SSH_USERNAME, $USERNAME]
|
||||
--password value, -P value user password [$PLUGIN_PASSWORD, $SSH_PASSWORD, $PASSWORD]
|
||||
--host value, -H value connect to host [$PLUGIN_HOST, $SSH_HOST, $HOST]
|
||||
--port value, -p value connect to port (default: 22) [$PLUGIN_PORT, $SSH_PORT, $PORT]
|
||||
--sync sync mode [$PLUGIN_SYNC, $SYNC]
|
||||
--timeout value, -t value connection timeout (default: 0s) [$PLUGIN_TIMEOUT, $SSH_TIMEOUT, $TIMEOUT]
|
||||
--command.timeout value, -T value command timeout (default: 1m0s) [$PLUGIN_COMMAND_TIMEOUT, $SSH_COMMAND_TIMEOUT, $COMMAND_TIMEOUT]
|
||||
--script value, -s value execute commands [$PLUGIN_SCRIPT, $SSH_SCRIPT, $SCRIPT]
|
||||
--script.stop stop script after first failure [$PLUGIN_SCRIPT_STOP, $STOP]
|
||||
--proxy.ssh-key value private ssh key of proxy [$PLUGIN_PROXY_SSH_KEY, $PLUGIN_PROXY_KEY, $PROXY_SSH_KEY]
|
||||
--proxy.key-path value ssh private key path of proxy [$PLUGIN_PROXY_KEY_PATH, $PROXY_SSH_KEY_PATH]
|
||||
--proxy.username value connect as user of proxy (default: "root") [$PLUGIN_PROXY_USERNAME, $PLUGIN_PROXY_USER, $PROXY_SSH_USERNAME]
|
||||
--proxy.password value user password of proxy [$PLUGIN_PROXY_PASSWORD, $PROXY_SSH_PASSWORD]
|
||||
--proxy.host value connect to host of proxy [$PLUGIN_PROXY_HOST, $PROXY_SSH_HOST]
|
||||
--proxy.port value connect to port of proxy (default: "22") [$PLUGIN_PROXY_PORT, $PROXY_SSH_PORT]
|
||||
--proxy.timeout value proxy connection timeout (default: 0s) [$PLUGIN_PROXY_TIMEOUT, $PROXY_SSH_TIMEOUT]
|
||||
```diff
|
||||
- name: multiple host
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: "foo.com,bar.com"
|
||||
+ sync: true
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
whoami
|
||||
ls -al
|
||||
```
|
||||
|
||||
## Secrets
|
||||
Pass environment variable to shell script
|
||||
|
||||
* `PASSWORD` - ssh server password
|
||||
* `KEY` - ssh server private key
|
||||
```diff
|
||||
- name: pass environment
|
||||
uses: appleboy/ssh-action@master
|
||||
+ env:
|
||||
+ FOO: "BAR"
|
||||
+ BAR: "FOO"
|
||||
+ SHA: ${{ github.sha }}
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
+ envs: FOO,BAR
|
||||
script: |
|
||||
echo "I am $FOO"
|
||||
echo "I am $BAR"
|
||||
echo "sha: $SHA"
|
||||
```
|
||||
|
||||
Stop script after first failure. ex: missing `abc` folder
|
||||
|
||||
```diff
|
||||
- name: stop script if command error
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
+ script_stop: true
|
||||
script: |
|
||||
mkdir abc/def
|
||||
ls -al
|
||||
```
|
||||
|
||||
output:
|
||||
|
||||
```sh
|
||||
======CMD======
|
||||
mkdir abc/def
|
||||
ls -al
|
||||
|
||||
======END======
|
||||
2019/11/21 01:16:21 Process exited with status 1
|
||||
err: mkdir: cannot create directory ‘abc/def’: No such file or directory
|
||||
##[error]Docker run failed with exit code 1
|
||||
```
|
||||
|
||||
How to connect remote server using `ProxyCommand`?
|
||||
|
||||
```bash
|
||||
+--------+ +----------+ +-----------+
|
||||
| Laptop | <--> | Jumphost | <--> | FooServer |
|
||||
+--------+ +----------+ +-----------+
|
||||
```
|
||||
|
||||
in your `~/.ssh/config`, you will see the following.
|
||||
|
||||
```bash
|
||||
Host Jumphost
|
||||
HostName Jumphost
|
||||
User ubuntu
|
||||
Port 22
|
||||
IdentityFile ~/.ssh/keys/jump_host.pem
|
||||
|
||||
Host FooServer
|
||||
HostName FooServer
|
||||
User ubuntu
|
||||
Port 22
|
||||
ProxyCommand ssh -q -W %h:%p Jumphost
|
||||
```
|
||||
|
||||
How to convert to YAML format of GitHubActions.
|
||||
|
||||
```diff
|
||||
- name: ssh proxy command
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
+ proxy_host: ${{ secrets.PROXY_HOST }}
|
||||
+ proxy_username: ${{ secrets.PROXY_USERNAME }}
|
||||
+ proxy_key: ${{ secrets.PROXY_KEY }}
|
||||
+ proxy_port: ${{ secrets.PROXY_PORT }}
|
||||
script: |
|
||||
mkdir abc/def
|
||||
ls -al
|
||||
```
|
||||
|
||||
Protecting a Private Key. The purpose of the passphrase is usually to encrypt the private key. This makes the key file by itself useless to an attacker. It is not uncommon for files to leak from backups or decommissioned hardware, and hackers commonly exfiltrate files from compromised systems.
|
||||
|
||||
```diff
|
||||
- name: ssh key passphrase
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
+ passphrase: ${{ secrets.PASSPHRASE }}
|
||||
script: |
|
||||
whoami
|
||||
ls -al
|
||||
```
|
||||
|
63
action.yml
Normal file
63
action.yml
Normal file
@ -0,0 +1,63 @@
|
||||
name: 'SSH Remote Commands'
|
||||
description: 'Executing remote ssh commands'
|
||||
author: 'Bo-Yi Wu'
|
||||
inputs:
|
||||
host:
|
||||
description: 'ssh host'
|
||||
port:
|
||||
description: 'ssh port'
|
||||
default: 22
|
||||
passphrase:
|
||||
description: 'ssh key passphrase'
|
||||
username:
|
||||
description: 'ssh username'
|
||||
password:
|
||||
description: 'ssh password'
|
||||
sync:
|
||||
description: 'synchronous execution if multiple hosts'
|
||||
default: false
|
||||
timeout:
|
||||
description: 'timeout for ssh to host'
|
||||
default: "30s"
|
||||
command_timeout:
|
||||
description: 'timeout for ssh command'
|
||||
default: "10m"
|
||||
key:
|
||||
description: 'content of ssh private key. ex raw content of ~/.ssh/id_rsa'
|
||||
key_path:
|
||||
description: 'path of ssh private key'
|
||||
proxy_host:
|
||||
description: 'ssh proxy host'
|
||||
proxy_port:
|
||||
description: 'ssh proxy port'
|
||||
default: 22
|
||||
proxy_username:
|
||||
description: 'ssh proxy username'
|
||||
proxy_password:
|
||||
description: 'ssh proxy password'
|
||||
proxy_passphrase:
|
||||
description: 'ssh proxy key passphrase'
|
||||
proxy_timeout:
|
||||
description: 'timeout for ssh to proxy host'
|
||||
default: "30s"
|
||||
proxy_key:
|
||||
description: 'content of ssh proxy private key. ex raw content of ~/.ssh/id_rsa'
|
||||
proxy_key_path:
|
||||
description: 'path of ssh proxy private key'
|
||||
script:
|
||||
description: 'execute commands'
|
||||
script_stop:
|
||||
description: 'stop script after first failure'
|
||||
default: false
|
||||
envs:
|
||||
description: 'pass environment variable to shell script'
|
||||
debug:
|
||||
description: 'enable debug mode'
|
||||
default: false
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
|
||||
branding:
|
||||
icon: 'terminal'
|
||||
color: 'gray-dark'
|
Binary file not shown.
Before Width: | Height: | Size: 104 KiB |
BIN
images/output-result.png
Normal file
BIN
images/output-result.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 193 KiB |
Reference in New Issue
Block a user