How actions/checkout Handles SSH Known Hosts and Strict Host Key Checking
When you provide an SSH deploy key, actions/checkout constructs a temporary known-hosts file and exports a custom GIT_SSH_COMMAND that enforces strict host-key verification when the ssh-strict input is enabled.
The actions/checkout GitHub Action manages SSH authentication securely by generating isolated configuration files rather than modifying the runner's global SSH settings. When using the ssh-key input, the action implements a multi-step process in src/git-auth-helper.ts to handle known hosts and strict host-key checking without persisting sensitive data to the runner's default ~/.ssh directory.
SSH Authentication Architecture
The Known Hosts File Construction
In src/git-auth-helper.ts, the configureSsh() function creates a temporary known-hosts file that consolidates three distinct sources:
- The runner's existing
~/.ssh/known_hostsfile (if present) - Additional host entries provided via the
ssh-known-hostsinput - An implicit entry for
github.comthat ships with the action
The concatenated content is written to a unique path under $RUNNER_TEMP (e.g., $RUNNER_TEMP/a1b2c3_known_hosts). This path is immediately registered via stateHelper.setSshKnownHostsPath() to ensure the file can be located and deleted during the post-action cleanup phase.
Building the GIT_SSH_COMMAND
The action constructs a custom SSH command string that enforces specific security policies. It locates the system SSH binary using io.which('ssh'), then builds the command with the following components:
-i "$RUNNER_TEMP/<key-file>": Points to the temporary private key file-o "UserKnownHostsFile=$RUNNER_TEMP/<known-hosts-file>": Isolates host verification to the temporary file- Strict host-key checking: When
ssh-strictistrue, the action appends-o StrictHostKeyChecking=yes -o CheckHostIP=noas documented inadrs/0153-checkout-v2.md
This complete command string is exported as the GIT_SSH_COMMAND environment variable, ensuring all subsequent Git operations (git clone, git fetch, submodule updates) use these exact SSH settings.
Configuration Inputs and Workflow Usage
The action.yml file defines three inputs that control SSH behavior:
ssh-key: The private SSH key for authenticationssh-known-hosts: Additional known hosts entries in standard SSH formatssh-strict: Boolean flag to enable strict host-key checking
When persist-credentials: true, the action also writes the SSH command to the repository's local Git config under core.sshCommand. This ensures submodule operations inherit the same authentication settings as the parent repository.
Example workflow configuration:
steps:
- uses: actions/checkout@v4
with:
ssh-key: ${{ secrets.DEPLOY_SSH_KEY }}
ssh-known-hosts: |
my.custom.host ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...
ssh-strict: true
This generates an environment variable similar to:
GIT_SSH_COMMAND="ssh -i \"$RUNNER_TEMP/8f2c3a\" \
-o StrictHostKeyChecking=yes -o CheckHostIP=no \
-o \"UserKnownHostsFile=$RUNNER_TEMP/8f2c3a_known_hosts\""
Cleanup and Security
The action implements secure cleanup through the removeAuth() function in src/git-auth-helper.ts, which invokes removeSsh() to delete both the temporary private key and known-hosts files from $RUNNER_TEMP. It also clears the core.sshCommand Git configuration to prevent credential leakage to subsequent workflow steps.
The combination of StrictHostKeyChecking=yes with CheckHostIP=no ensures that host keys are verified against the provided known-hosts file while avoiding IP-based verification that could fail in dynamic cloud environments.
Summary
- Temporary known-hosts file: Concatenates system, user-provided, and built-in GitHub entries into an isolated file under
$RUNNER_TEMP. - Strict host-key checking: Enabled via
ssh-strict: true, adding-o StrictHostKeyChecking=yesto the SSH command as implemented insrc/git-auth-helper.ts. - GIT_SSH_COMMAND: Exported environment variable ensures all Git operations use the custom key and verification settings.
- Automatic cleanup: Temporary files and Git configurations are removed via
stateHelperwhen the action completes.
Frequently Asked Questions
Does actions/checkout verify GitHub's host key by default?
Yes. The action includes a built-in known-hosts entry for github.com that is automatically appended to the temporary known-hosts file, ensuring verification occurs even if the runner's global ~/.ssh/known_hosts does not contain GitHub's key.
What happens when ssh-strict is set to false?
When ssh-strict is disabled, the action omits the -o StrictHostKeyChecking=yes flag from the SSH command. This allows connections to proceed without strict verification, though the UserKnownHostsFile option still points to the temporary file containing any explicitly provided host keys.
How does the action handle SSH keys for submodules?
When persist-credentials: true, the action writes the SSH command to the repository's Git config under core.sshCommand. This configuration persists for submodule operations, ensuring they use the same SSH key and known-hosts settings as the parent repository.
Where are the temporary SSH files stored?
The action stores temporary files in the directory specified by $RUNNER_TEMP, generating unique filenames for both the private key and known-hosts file. These paths are tracked via stateHelper.setSshKnownHostsPath() and stateHelper.setSshKeyPath() to ensure reliable cleanup during the post-action phase.
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 →