Configure ssh-known-hosts for Private GitHub Enterprise Instances with actions/checkout
To securely connect actions/checkout to a private GitHub Enterprise Server (GHES) instance over SSH, generate your host fingerprints using ssh-keyscan, store them in a GitHub secret, and supply them via the ssh-known-hosts input while setting github-server-url to your GHES endpoint.
The actions/checkout action supports SSH authentication to private GitHub Enterprise Server instances through dedicated inputs that customize SSH security policies. When you provide custom host keys through the ssh-known-hosts parameter, the action automatically constructs a temporary known-hosts file and configures Git to use it for all subsequent operations.
How the ssh-known-hosts Input Works
When you supply the ssh-known-hosts input, the action implements a multi-step authentication flow defined in the source code:
-
Collects fingerprints – The action accepts a multiline string containing SSH host key entries, typically generated with
ssh-keyscan. -
Creates a temporary known-hosts file – In
src/git-auth-helper.ts(lines 297-304), the action creates a temporary file in the runner's$RUNNER_TEMPdirectory and stores the path in thesshKnownHostsPathvariable. -
Writes host entries – The file contains the default
github.comhost key plus your user-provided GHES entries written viafs.promises.writeFile. -
Persists state – The temporary file path is saved in the action state via
state-helper.ts(lines 45-46) to ensure proper cleanup. -
Configures SSH command – The action builds a custom SSH command in
src/git-auth-helper.ts(lines 306-313) that forces Git to use the temporary file via theUserKnownHostsFileoption. By default, this command includesStrictHostKeyChecking=yesandCheckHostIP=no. -
Applies Git configuration – The command is stored in
sshCommandand applied globally usinggit config core.sshCommand, ensuring all fetch and clone operations use your specified host keys.
Configuring Your GitHub Enterprise Workflow
Generate Host Fingerprints
Before configuring the workflow, generate the SSH host key fingerprints for your GHES instance:
ssh-keyscan -t rsa,ecdsa,ed25519 my-ghes.example.com
Store the output in a GitHub secret (e.g., GHES_KNOWN_HOSTS) through the repository settings or CLI:
gh secret set GHES_KNOWN_HOSTS --repo=my-org/my-repo < known_hosts.txt
Configure Workflow Inputs
Set the following inputs in your workflow step:
github-server-url– Point to your GHES instance (declared inaction.ymllines 98-100)ssh-key– Your deploy key stored as a secretssh-known-hosts– The secret containing your generated fingerprints (declared inaction.ymllines 37-46)ssh-strict– Optional boolean to disable strict host checking
Source Code Implementation Details
The SSH authentication flow spans several key files in the repository:
-
action.yml– Defines thessh-known-hosts,ssh-strict, andgithub-server-urlinputs with their types and descriptions. -
src/input-helper.ts– Reads thessh-known-hostsvalue usingcore.getInput('ssh-known-hosts')and passes it to the authentication helper. -
src/git-auth-helper.ts– Contains theconfigureSsh()method that creates the temporary known-hosts file and constructs the SSH command with theUserKnownHostsFileparameter. -
src/state-helper.ts– Persists thesshKnownHostsPathto the action state, allowing the post-job cleanup to remove sensitive temporary files. -
src/git-command-manager.ts– Executes Git commands using the overridden SSH configuration set by the authentication helper.
Managing Strict Host Key Checking
By default, the action enforces strict host key checking when ssh-known-hosts is provided. When ssh-strict remains true (the default), the generated SSH command includes StrictHostKeyChecking=yes.
If your GHES instance uses self-signed certificates or frequently changing host keys, set ssh-strict: false. This omits the strict checking options from the SSH command while still utilizing your custom known-hosts file to prevent man-in-the-middle attacks on the initial connection.
Complete Workflow Example
# .github/workflows/checkout-ghes.yml
name: Checkout private GHES repo
on:
push:
jobs:
checkout:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Point to the GHES instance
github-server-url: https://my-ghes.example.com
# Use an SSH deploy key stored in a secret
ssh-key: ${{ secrets.GHES_SSH_KEY }}
# Provide the known-hosts entries for the GHES host
ssh-known-hosts: ${{ secrets.GHES_KNOWN_HOSTS }}
# Optional: disable strict checking for self-signed certs
# ssh-strict: false
Summary
- Store your GHES host fingerprints in a secret using
ssh-keyscanoutput before configuring the workflow. - The
ssh-known-hostsinput creates a temporary file at runtime in$RUNNER_TEMPviasrc/git-auth-helper.tsto avoid modifying the runner's global SSH configuration. - Set
github-server-urlto ensure the action targets your private GHES instance rather than GitHub.com. - The action constructs a custom SSH command with
UserKnownHostsFilepointing to the temporary file, applied throughgit config core.sshCommand. - Use
ssh-strict: falseonly when necessary for self-signed certificates, as this removesStrictHostKeyChecking=yesfrom the SSH options.
Frequently Asked Questions
How do I generate the SSH known hosts entry for my GHES server?
Run ssh-keyscan -t rsa,ecdsa,ed25519 <your-ghes-host> from a trusted network location to capture the current host keys. Store the complete output, including the host algorithm and base64-encoded key, as a repository or organization secret, then reference it in the ssh-known-hosts input.
What happens if I don't provide ssh-known-hosts for my GHES instance?
Without the ssh-known-hosts input, the SSH client may prompt to accept the host key during the workflow run, causing the job to hang indefinitely or fail with a host key verification error. You must provide the expected host keys to enable non-interactive SSH authentication to private GHES instances.
Can I use ssh-known-hosts with GitHub.com instead of GHES?
Yes, the ssh-known-hosts input works with any SSH Git remote. The action automatically includes the default github.com host key in the temporary known-hosts file, but you can provide additional entries for mirrors, proxies, or other SSH hosts accessed during checkout.
Where does the action store the temporary known-hosts file?
The action creates the file in the runner's temporary directory ($RUNNER_TEMP) using a path generated at runtime and stored in the action state via state-helper.ts. The file is automatically cleaned up after the job completes, ensuring sensitive host key configurations do not persist on the runner between workflows.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →