2019-05-15 00:32:43 +02:00
# 🚀 SSH for GitHub Actions
2019-05-14 18:31:53 +02:00
2023-03-03 03:45:48 +01:00
[繁體中文 ](./README.zh-tw.md )
2019-09-30 05:35:28 +02:00
[GitHub Action ](https://github.com/features/actions ) for executing remote ssh commands.
2019-05-15 00:32:43 +02:00
2019-09-29 05:09:26 +02:00
![ssh workflow ](./images/ssh-workflow.png )
[![Actions Status ](https://github.com/appleboy/ssh-action/workflows/remote%20ssh%20command/badge.svg )](https://github.com/appleboy/ssh-action/actions)
2019-05-15 00:36:27 +02:00
2020-06-05 03:05:02 +02:00
**Important**: Only support **Linux** [docker ](https://www.docker.com/ ) container.
2020-05-08 13:05:47 +02:00
2023-04-04 11:56:49 +02:00
This thing is built using [Golang ](https://go.dev ) and [drone-ssh ](https://github.com/appleboy/drone-ssh ). 🚀
2021-04-03 23:59:44 +02:00
## 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`
2023-03-03 03:22:51 +01:00
* `key` - content of ssh private key. ex raw content of ~/.ssh/id_rsa, remember include the BEGIN and END lines
2021-04-03 23:59:44 +02:00
* `key_path` - path of ssh private key
* `fingerprint` - fingerprint SHA256 of the host public key, default is to skip verification
* `script` - execute commands
* `script_stop` - stop script after first failure
* `envs` - pass environment variable to shell script
* `debug` - enable debug mode
* `use_insecure_cipher` - include more ciphers with use_insecure_cipher (see [#56 ](https://github.com/appleboy/ssh-action/issues/56 ))
* `cipher` - the allowed cipher algorithms. If unspecified then a sensible
2023-04-13 05:15:42 +02:00
* `envs_format` - flexible configuration of environment value transfer. default is `export {NAME}={VALUE}`
2021-04-03 23:59:44 +02:00
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
* `proxy_fingerprint` - fingerprint SHA256 of the proxy host public key, default is to skip verification
* `proxy_use_insecure_cipher` - include more ciphers with use_insecure_cipher (see [#56 ](https://github.com/appleboy/ssh-action/issues/56 ))
* `proxy_cipher` - the allowed cipher algorithms. If unspecified then a sensible
2019-05-15 00:32:43 +02:00
## Usage
2019-05-15 00:36:27 +02:00
Executing remote ssh commands.
2019-05-15 00:32:43 +02:00
2019-09-29 05:09:26 +02:00
```yaml
2019-09-29 08:16:47 +02:00
name: remote ssh command
on: [push]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: executing remote ssh commands using password
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-09-29 08:16:47 +02:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
script: whoami
2019-05-15 00:32:43 +02:00
```
2019-09-29 05:09:26 +02:00
output:
```sh
======CMD======
whoami
======END======
out: ** *
2019-11-20 16:49:31 +01:00
==============================================
✅ Successfully executed commands to all host.
==============================================
2019-05-15 00:32:43 +02:00
```
2021-04-03 23:59:44 +02:00
### Setting up a SSH Key
2019-05-15 00:32:43 +02:00
2021-04-03 23:59:44 +02:00
Make sure to follow the below steps while creating SSH Keys and using them.
The best practice is create the SSH Keys on local machine not remote machine.
Login with username specified in Github Secrets. Generate a RSA Key-Pair:
2019-05-15 00:47:53 +02:00
2023-03-03 03:26:23 +01:00
### Generate rsa key
2019-05-15 00:47:53 +02:00
2021-04-03 23:59:44 +02:00
```bash
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```
2019-12-07 13:05:02 +01:00
2023-03-03 03:26:23 +01:00
### Generate ed25519 key
2020-08-12 19:06:27 +02:00
2021-04-03 23:59:44 +02:00
```bash
ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"
```
2020-08-12 19:06:27 +02:00
Add newly generated key into Authorized keys. Read more about authorized keys [here ](https://www.ssh.com/ssh/authorized_keys/ ).
2023-03-03 03:26:23 +01:00
### Add rsa key into Authorized keys
2021-04-03 23:59:44 +02:00
2020-08-12 19:06:27 +02:00
```bash
2020-10-31 00:03:29 +01:00
cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys'
2020-08-12 19:06:27 +02:00
```
2023-03-03 03:26:23 +01:00
### Add ed25519 key into Authorized keys
2021-04-03 23:59:44 +02:00
```bash
cat .ssh/id_ed25519.pub | ssh b@B 'cat >> .ssh/authorized_keys'
```
2020-08-12 19:06:27 +02:00
Copy Private Key content and paste in Github Secrets.
2023-03-03 03:26:23 +01:00
### Copy rsa Private key
2021-04-03 23:59:44 +02:00
2020-08-12 19:06:27 +02:00
```bash
clip < ~/.ssh/id_rsa
```
2023-03-03 03:26:23 +01:00
### Copy ed25519 Private key
2021-04-03 23:59:44 +02:00
```bash
clip < ~/.ssh/id_ed25519
```
2021-05-09 15:11:10 +02:00
See the detail information about [SSH login without password ](http://www.linuxproblem.org/art_9.html ).
**A note** from one of our readers: Depending on your version of SSH you might also have to do the following changes:
* Put the public key in `.ssh/authorized_keys2`
* Change the permissions of `.ssh` to 700
* Change the permissions of `.ssh/authorized_keys2` to 640
2020-08-12 19:06:27 +02:00
2022-07-29 14:58:30 +02:00
### If you are using OpenSSH
2022-07-29 15:24:53 +02:00
2022-07-29 14:58:30 +02:00
If you are currently using OpenSSH and are getting the following error:
```bash
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]
```
2023-03-03 03:22:51 +01:00
Make sure that your key algorithm of choice is supported. On Ubuntu 20.04 or later you must explicitly allow the use of the ssh-rsa algorithm. Add the following line to your OpenSSH daemon file (which is either `/etc/ssh/sshd_config` or a drop-in file under `/etc/ssh/sshd_config.d/` ):
2022-07-29 14:58:30 +02:00
2022-07-29 15:24:53 +02:00
```bash
2022-07-29 14:58:30 +02:00
CASignatureAlgorithms +ssh-rsa
```
Alternatively, `ed25519` keys are accepted by default in OpenSSH. You could use this instead of rsa if needed:
2022-07-29 15:24:53 +02:00
2022-07-29 14:58:30 +02:00
```bash
ssh-keygen -t ed25519 -a 200 -C "your_email@example.com"
```
2019-09-29 05:09:26 +02:00
### Example
2019-05-15 00:47:53 +02:00
2021-04-03 23:59:44 +02:00
#### Executing remote ssh commands using password
2019-09-29 05:09:26 +02:00
```yaml
- name: executing remote ssh commands using password
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-09-29 05:09:26 +02:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
2019-09-29 05:45:42 +02:00
script: whoami
2019-05-15 00:47:53 +02:00
```
2021-04-03 23:59:44 +02:00
#### Using private key
2019-05-15 00:47:53 +02:00
2019-09-29 05:09:26 +02:00
```yaml
- name: executing remote ssh commands using ssh key
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-09-29 05:09:26 +02:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: whoami
2019-05-15 00:47:53 +02:00
```
2021-04-03 23:59:44 +02:00
#### Multiple Commands
2019-05-15 00:52:59 +02:00
2019-09-29 05:09:26 +02:00
```yaml
- name: multiple command
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-09-29 05:09:26 +02:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
whoami
ls -al
2019-05-15 00:52:59 +02:00
```
2019-09-29 05:09:26 +02:00
![result ](./images/output-result.png )
2019-05-15 00:59:18 +02:00
2021-04-03 23:59:44 +02:00
#### Multiple Hosts
2019-05-15 01:13:49 +02:00
2019-09-29 05:09:26 +02:00
```diff
2019-11-20 16:49:31 +01:00
- name: multiple host
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-11-20 16:49:31 +01:00
with:
- host: "foo.com"
+ host: "foo.com,bar.com"
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
whoami
ls -al
2019-05-15 01:13:49 +02:00
```
2019-09-29 05:23:40 +02:00
2021-04-03 23:59:44 +02:00
#### Multiple hosts with different port
2020-11-17 03:51:06 +01:00
```diff
- name: multiple host
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2020-11-17 03:51:06 +01:00
with:
- host: "foo.com"
+ host: "foo.com:1234,bar.com:5678"
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
script: |
whoami
ls -al
```
2021-04-03 23:59:44 +02:00
#### Synchronous execution on multiple hosts
2020-01-30 15:40:33 +01:00
```diff
- name: multiple host
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2020-01-30 15:40:33 +01:00
with:
host: "foo.com,bar.com"
+ sync: true
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
whoami
ls -al
```
2021-04-03 23:59:44 +02:00
#### Pass environment variable to shell script
2019-09-29 05:23:40 +02:00
```diff
2019-11-20 16:49:31 +01:00
- name: pass environment
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-11-20 16:49:31 +01:00
+ env:
+ FOO: "BAR"
2019-12-08 00:16:30 +01:00
+ BAR: "FOO"
2020-02-09 04:37:56 +01:00
+ SHA: ${{ github.sha }}
2019-11-20 16:49:31 +01:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
2022-07-29 15:19:55 +02:00
+ envs: FOO,BAR,SHA
2019-11-20 16:49:31 +01:00
script: |
echo "I am $FOO"
echo "I am $BAR"
2020-02-09 04:37:56 +01:00
echo "sha: $SHA"
2019-09-29 05:23:40 +02:00
```
2019-09-29 06:02:21 +02:00
2020-07-08 10:46:24 +02:00
_Inside `env` object, you need to pass every environment variable as a string, passing `Integer` data type or any other may output unexpected results._
2021-04-03 23:59:44 +02:00
#### Stop script after first failure
> ex: missing `abc` folder
2019-09-29 06:02:21 +02:00
2019-11-20 16:49:31 +01:00
```diff
- name: stop script if command error
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-11-20 16:49:31 +01:00
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
2019-09-29 06:02:21 +02:00
```
2019-12-07 13:05:02 +01:00
2021-04-03 23:59:44 +02:00
#### How to connect remote server using `ProxyCommand`?
2019-12-07 13:05:02 +01:00
```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
```
2021-04-03 23:59:44 +02:00
#### How to convert to YAML format of GitHubActions
2019-12-07 13:05:02 +01:00
```diff
- name: ssh proxy command
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-12-07 13:05:02 +01:00
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
```
2019-12-30 12:54:28 +01:00
2021-04-03 23:59:44 +02:00
#### Protecting a Private Key
The purpose of the passphrase is usually to encrypt the private key.
2022-07-29 15:24:53 +02:00
This makes the key file by itself useless to an attacker.
2021-04-03 23:59:44 +02:00
It is not uncommon for files to leak from backups or decommissioned hardware, and hackers commonly exfiltrate files from compromised systems.
2019-12-30 12:54:28 +01:00
```diff
- name: ssh key passphrase
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2019-12-30 12:54:28 +01:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
+ passphrase: ${{ secrets.PASSPHRASE }}
script: |
whoami
ls -al
```
2021-04-03 23:59:44 +02:00
2021-05-15 17:05:07 +02:00
#### Using host fingerprint verification
Setting up SSH host fingerprint verification can help to prevent Person-in-the-Middle attacks. Before setting this up, run the command below to get your SSH host fingerprint. Remember to replace `ed25519` with your appropriate key type (`rsa`, `dsa` , etc.) that your server is using and `example.com` with your host.
In modern OpenSSH releases, the _default_ key types to be fetched are `rsa` (since version 5.1), `ecdsa` (since version 6.0), and `ed25519` (since version 6.7).
2022-02-06 08:15:00 +01:00
```sh
2021-05-15 17:05:07 +02:00
ssh example.com ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub | cut -d ' ' -f2
```
Now you can adjust you config:
```diff
- name: ssh key passphrase
2023-04-04 11:37:29 +02:00
uses: appleboy/ssh-action@v0.1.9
2021-05-15 17:05:07 +02:00
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
+ fingerprint: ${{ secrets.FINGERPRINT }}
script: |
whoami
ls -al
```
2021-04-03 23:59:44 +02:00
## Contributing
2022-02-06 08:15:00 +01:00
2021-04-03 23:59:44 +02:00
We would love for you to contribute to `appleboy/ssh-action` , pull requests are welcome!
## License
2022-02-06 08:15:00 +01:00
2021-04-03 23:59:44 +02:00
The scripts and documentation in this project are released under the [MIT License ](LICENSE )