How to Configure SSH Key Authentication for actions/checkout: A Complete Guide

Set the ssh-key input to provide a private SSH key, and the action automatically configures GIT_SSH_COMMAND with a temporary key file and combined known_hosts to authenticate git operations without exposing credentials in your workspace.

The actions/checkout action supports SSH key authentication as an alternative to the default GITHUB_TOKEN for cloning private repositories and submodules. When you configure SSH key authentication for actions/checkout, the action handles secure key storage, host verification, and automatic cleanup through its internal git authentication helper. This implementation ensures your private keys never persist in the repository workspace beyond the job execution.

How SSH Authentication Works Internally

When you provide the ssh-key input, the action executes a multi-step authentication sequence defined in src/git-auth-helper.ts. The configureSsh() method orchestrates this process, creating temporary files and environment variables that git uses for subsequent operations.

Secure Key Storage

The action writes your private key to a unique temporary file in $RUNNER_TEMP with strict permissions. According to the source code in src/git-auth-helper.ts (lines 55-63), the file is created with mode 0600 (read/write for owner only) and stored outside the workspace to prevent accidental commits. This temporary path is then referenced in subsequent SSH commands.

Host Verification Setup

The action builds a combined known_hosts file that merges three sources (lines 78-99):

  • The runner's existing ~/.ssh/known_hosts (if present)
  • Any user-provided hosts from the ssh-known-hosts input
  • An implicit entry for github.com added automatically by the action

This merged file is written to $RUNNER_TEMP, ensuring that strict host key checking can be enforced without modifying the runner's permanent SSH configuration.

GIT_SSH_COMMAND Construction

The action constructs a custom SSH command that forces git to use the temporary credentials. As implemented in lines 103-113 of src/git-auth-helper.ts:

this.sshCommand = `"${sshPath}" -i "$RUNNER_TEMP/${path.basename(this.sshKeyPath)}"`
if (this.settings.sshStrict) {
  this.sshCommand += ' -o StrictHostKeyChecking=yes -o CheckHostIP=no'
}
this.sshCommand += ` -o "UserKnownHostsFile=$RUNNER_TEMP/${path.basename(this.sshKnownHostsPath)}"`

This command is exported as the GIT_SSH_COMMAND environment variable for the remainder of the step. When persist-credentials: true (the default), the action additionally stores this configuration in the local repository's .git/config via git config core.sshCommand (lines 115-117), enabling subsequent git commands in later steps to use the same authentication.

Automatic Cleanup

After the job completes, the removeSsh() method (lines 336-366) removes the temporary key file, the temporary known_hosts file, and clears any core.sshCommand entries from the git configuration. This ensures credentials are not left on the runner after the workflow finishes.

Configuration Inputs and Parameters

The following inputs in action.yml control SSH authentication behavior:

  • ssh-key: The private SSH key (typically stored as a repository secret) used for authentication. When provided, the action bypasses the default GITHUB_TOKEN authentication.
  • ssh-known-hosts: Additional SSH host keys to trust, useful for self-hosted Git servers or enterprise environments. These are merged with the runner's existing known hosts and the implicit github.com entry.
  • ssh-strict: When set to true, adds StrictHostKeyChecking=yes and CheckHostIP=no to the SSH command, preventing connections to hosts with unrecognized keys.
  • ssh-user: Overrides the default git user for the remote URL, used when constructing URL rewrite rules in the git configuration.
  • persist-credentials: When true (default), stores the SSH command in .git/config for use by subsequent steps. When false, credentials are only available for the initial checkout.

Security Considerations

The implementation in src/git-auth-helper.ts incorporates several security measures:

  • File Permissions: The private key is written with 0600 permissions, ensuring only the current user can read the file.
  • Temporary Storage: All sensitive files are stored in $RUNNER_TEMP, which is isolated from the repository workspace and cleaned up after the job.
  • Credential Persistence: The raw key is never written to .git/config; only the core.sshCommand path reference is stored when persist-credentials is enabled.
  • Submodule Isolation: When checking out submodules, the action configures SSH authentication individually for each submodule to maintain credential isolation.

Practical Configuration Examples

Basic SSH Checkout for Private Repositories

Provide the SSH private key as a repository secret to authenticate the checkout:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
          ssh-strict: true
          persist-credentials: true

In this configuration, the action writes the key to $RUNNER_TEMP, constructs the GIT_SSH_COMMAND, and persists the configuration for later git operations in the workflow.

SSH Authentication with Custom Known Hosts

For self-hosted Git servers or additional security hardening, provide custom host keys:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
          ssh-known-hosts: |
            git.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDIhz2GK/XCYzP8L4e8...
            git.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...
          ssh-strict: true

The action merges these entries with the existing known_hosts and the default github.com entry.

SSH Authentication for Submodules

When checking out repositories with private submodules, the SSH configuration is automatically propagated to submodule operations:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
          submodules: recursive
          persist-credentials: true

The configureSubmoduleAuth method (lines 215-229 in src/git-auth-helper.ts) ensures that each submodule receives the same core.sshCommand configuration, allowing recursive checkout of private submodules without additional authentication steps.

Summary

  • Primary Method: Use the ssh-key input to enable SSH authentication; the action handles all configuration through src/git-auth-helper.ts.
  • Temporary Credentials: Keys are stored in $RUNNER_TEMP with 0600 permissions and never touch the workspace directly.
  • Host Verification: The ssh-known-hosts input and automatic github.com entry provide secure host key verification when combined with ssh-strict: true.
  • Persistence: Set persist-credentials: true to enable subsequent git commands to use the same SSH configuration via .git/config entries.
  • Cleanup: The removeSsh() method automatically removes all temporary files and configuration after the job completes.

Frequently Asked Questions

How do I configure SSH key authentication for actions/checkout with a passphrase-protected key?

Passphrase-protected keys are not supported directly by the action. You must provide the unencrypted private key as the ssh-key input. Store the key as a GitHub Secret and use OpenSSL to decrypt it in a previous step if necessary, or generate a new key pair without a passphrase specifically for GitHub Actions automation.

Where does actions/checkout store the SSH key during workflow execution?

The action writes the SSH key to a unique file in $RUNNER_TEMP (the runner's temporary directory) with permissions set to 0600. This location is outside the repository workspace and is automatically cleaned up after the job completes, as implemented in the removeSsh() method in src/git-auth-helper.ts.

Can I use SSH key authentication for actions/checkout with submodules?

Yes. When you provide the ssh-key input and set submodules: recursive or submodules: true, the action configures SSH authentication for each submodule individually. The configureSubmoduleAuth function in src/git-auth-helper.ts sets the core.sshCommand configuration in each submodule's .git/config, enabling authentication for nested private repositories.

What is the difference between using ssh-key and GITHUB_TOKEN for authentication?

The ssh-key input uses SSH protocol authentication with a private key, while the default GITHUB_TOKEN uses HTTPS with a temporary personal access token. SSH keys are required for accessing repositories outside the current GitHub instance or when specific SSH-based workflows are mandated. The GITHUB_TOKEN is automatically scoped to the current repository and its forks, whereas SSH keys provide broader access depending on the key's configuration.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →