Configure SSH access to private servers through a bastion/jump host inside GitHub Actions workflows.
This action creates an SSH configuration with ProxyJump support and allows secure access to internal/private infrastructure from GitHub-hosted runners.
- Supports bastion/jump host SSH access
- Supports custom SSH ports
- Works with private/internal servers
- Supports configurable strict host checking
- Supports secure known-host verification mode
- Simple reusable composite GitHub Action
- Compatible with GitHub-hosted runners
Use this mode when convenience is preferred and strict SSH host verification is not required.
name: Deploy Application
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout your code
uses: actions/checkout@v6
- name: Setup SSH
uses: rishav2404/setup-bastion-ssh@v1
with:
ssh-private-key: ${{ secrets.SSH_KEY }}
bastion-host: ${{ secrets.BASTION_HOST }}
bastion-user: ${{ secrets.BASTION_USER }}
bastion-port: "9222"
server-host: ${{ secrets.SERVER_HOST }}
server-user: ${{ secrets.SERVER_USER }}
- name: Perform SSH action
run: |
ssh target 'cd /xyz && ./deploy.sh'| Name | Required | Default | Description |
|---|---|---|---|
ssh-private-key |
Yes | - | SSH private key used for authentication |
bastion-host |
Yes | - | Bastion/jump host IP or hostname |
bastion-user |
Yes | - | SSH username for bastion host |
bastion-port |
No | 22 |
SSH port for bastion host |
bastion-known-host |
No | - | Known-host line for bastion host, required in secure mode |
server-host |
Yes | - | Target/internal server IP or hostname |
server-user |
Yes | - | SSH username for target server |
server-port |
No | 22 |
SSH port for target server |
server-known-host |
No | - | Known-host line for target server, required in secure mode |
strict-host-checking |
No | no |
SSH StrictHostKeyChecking option |
Generate an SSH key pair:
ssh-keygen -t ed25519Add the public key to:
~/.ssh/authorized_keys
on:
- bastion host
- target server
Store the private key inside GitHub Secrets:
SSH_KEY
If you set:
strict-host-checking: "yes"then you must also provide:
bastion-known-hostserver-known-host
These values are written into known_hosts before the SSH connection is attempted.
This enables proper SSH host verification and protects against man-in-the-middle attacks.
Run this from your local machine:
ssh-keyscan -p <BASTION_PORT> <BASTION_HOST>Example:
ssh-keyscan -p 9222 bastion.example.com
OR
ssh-keyscan -p 4222 15.xx.xx.xxOutput:
[14.139.240.89]:9222 ssh-ed25519 ABZZC8NlmC4jHJL1NTE5BBBA...
Store this line as GitHub Secret:
BASTION_KNOWN_HOST
Run this from the bastion host or from a machine that can access the target server:
ssh-keyscan -p <SERVER_PORT> <SERVER_HOST>Example:
ssh-keyscan -p 22 172.xx.xx.108Output:
172.xx.xx.108 ssh-ed25519 ABZZC8NlmC4jHJL1NTE5BBBA...
Store this line as GitHub Secret:
SERVER_KNOWN_HOST
name: Deploy Application
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout your code
uses: actions/checkout@v6
- name: Setup SSH
uses: rishav2404/setup-bastion-ssh@v1
with:
ssh-private-key: ${{ secrets.SSH_KEY }}
bastion-host: ${{ secrets.BASTION_HOST }}
bastion-user: ${{ secrets.BASTION_USER }}
bastion-port: "9222"
bastion-known-host: ${{ secrets.BASTION_KNOWN_HOST }}
server-host: ${{ secrets.SERVER_HOST }}
server-user: ${{ secrets.SERVER_USER }}
server-known-host: ${{ secrets.SERVER_KNOWN_HOST }}
strict-host-checking: "yes"
- name: Perform SSH action
run: |
ssh target 'cd /xyz && ./deploy.sh'GitHub Actions Runner
|
v
Bastion Host
|
v
Private Server
By default:
StrictHostKeyChecking=no
is used for convenience and compatibility with ephemeral CI runners.
For production environments, enable:
strict-host-checking: "yes"and provide:
bastion-known-hostserver-known-host
This enables proper SSH host verification.
Ensure:
-
the correct SSH private key is stored in
SSH_KEY -
the corresponding public key exists in:
~/.ssh/authorized_keyson:
- bastion host
- target server
If using:
strict-host-checking: "yes"ensure:
bastion-known-hostis providedserver-known-hostis provided- fingerprints are correct
Ensure:
- bastion host is reachable from the internet
- SSH port is open
- target server is reachable from bastion
- SSH access enabled on bastion and target hosts
- Bastion host reachable from the internet
- Target server reachable from the bastion
- OpenSSH installed on target systems
Apache 2.0