🚀 SSH for GitHub Actions
GitHub Action for executing remote ssh commands.
Important: Only support Linux docker container.
This thing is built using Golang and drone-ssh.
Input variables
See action.yml for more detailed information.
Input Parameter | Description | Default Value |
---|---|---|
host | SSH host address | |
port | SSH port number | 22 |
passphrase | SSH key passphrase | |
username | SSH username | |
password | SSH password | |
sync | Enable synchronous execution if multiple hosts | false |
use_insecure_cipher | Include more ciphers with use_insecure_cipher | false |
cipher | Allowed cipher algorithms. If unspecified, a sensible default | |
timeout | Timeout duration for SSH to host | 30s |
command_timeout | Timeout duration for SSH command | 10m |
key | Content of SSH private key. e.g., raw content of ~/.ssh/id_rsa | |
key_path | Path of SSH private key | |
fingerprint | SHA256 fingerprint of the host public key | |
proxy_host | SSH proxy host | |
proxy_port | SSH proxy port | 22 |
proxy_username | SSH proxy username | |
proxy_password | SSH proxy password | |
proxy_passphrase | SSH proxy key passphrase | |
proxy_timeout | Timeout for SSH to proxy host | 30s |
proxy_key | Content of SSH proxy private key | |
proxy_key_path | Path of SSH proxy private key | |
proxy_fingerprint | SHA256 fingerprint of the proxy host public key | |
proxy_cipher | Allowed cipher algorithms for the proxy | |
proxy_use_insecure_cipher | Include more ciphers with use_insecure_cipher for the proxy | false |
script | Execute commands | |
script_stop | Stop script after first failure | false |
envs | Pass environment variables to shell script | |
envs_format | Flexible configuration of environment value transfer | |
debug | Enable debug mode | false |
allenvs | Pass all environment variables to shell script | false |
Usage
Executing remote ssh commands.
name: remote ssh command
on: [push]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: executing remote ssh commands using password
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
script: whoami
output:
======CMD======
whoami
======END======
out: ***
==============================================
✅ Successfully executed commands to all host.
==============================================
Setting up a SSH Key
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:
Generate rsa key
ssh-keygen -t rsa -b 4096 -C "[email protected]"
Generate ed25519 key
ssh-keygen -t ed25519 -a 200 -C "[email protected]"
Add newly generated key into Authorized keys. Read more about authorized keys here.
Add rsa key into Authorized keys
cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys'
Add ed25519 key into Authorized keys
cat .ssh/id_ed25519.pub | ssh b@B 'cat >> .ssh/authorized_keys'
Copy Private Key content and paste in Github Secrets.
Copy rsa Private key
clip < ~/.ssh/id_rsa
Copy ed25519 Private key
clip < ~/.ssh/id_ed25519
See the detail information about SSH login without password.
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
If you are using OpenSSH
If you are currently using OpenSSH and are getting the following error:
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey]
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/
):
CASignatureAlgorithms +ssh-rsa
Alternatively, ed25519
keys are accepted by default in OpenSSH. You could use this instead of rsa if needed:
ssh-keygen -t ed25519 -a 200 -C "[email protected]"
Example
Executing remote ssh commands using password
- name: executing remote ssh commands using password
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
script: whoami
Using private key
- name: executing remote ssh commands using ssh key
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: whoami
Multiple Commands
- name: multiple command
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
whoami
ls -al
Multiple Hosts
- name: multiple host
uses: appleboy/[email protected]
with:
- host: "foo.com"
+ host: "foo.com,bar.com"
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
whoami
ls -al
Multiple hosts with different port
- name: multiple host
uses: appleboy/[email protected]
with:
- host: "foo.com"
+ host: "foo.com:1234,bar.com:5678"
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
script: |
whoami
ls -al
Synchronous execution on multiple hosts
- name: multiple host
uses: appleboy/[email protected]
with:
host: "foo.com,bar.com"
+ sync: true
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
whoami
ls -al
Pass environment variable to shell script
- name: pass environment
uses: appleboy/[email protected]
+ 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"
echo "I am $BAR"
echo "sha: $SHA"
Inside env
object, you need to pass every environment variable as a string, passing Integer
data type or any other may output unexpected results.
Stop script after first failure
ex: missing
abc
folder
- name: stop script if command error
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
+ script_stop: true
script: |
mkdir abc/def
ls -al
output:
======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
ProxyCommand
?
How to connect remote server using +--------+ +----------+ +-----------+
| Laptop | <--> | Jumphost | <--> | FooServer |
+--------+ +----------+ +-----------+
in your ~/.ssh/config
, you will see the following.
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
- name: ssh proxy command
uses: appleboy/[email protected]
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.
- name: ssh key passphrase
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
+ passphrase: ${{ secrets.PASSPHRASE }}
script: |
whoami
ls -al
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).
ssh example.com ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub | cut -d ' ' -f2
Now you can adjust you config:
- name: ssh key passphrase
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
+ fingerprint: ${{ secrets.FINGERPRINT }}
script: |
whoami
ls -al
Contributing
We would love for you to contribute to appleboy/ssh-action
, pull requests are welcome!
License
The scripts and documentation in this project are released under the MIT License