# How to Configure SSH Keys for Checkout in GitHub Actions: A Complete Guide

> Learn how to configure SSH keys for checkout in GitHub Actions using the ssh key input to securely access private repositories. Follow this guide for seamless integration.

- Repository: [GitHub Actions/checkout](https://github.com/actions/checkout)
- Tags: how-to-guide
- Published: 2026-07-18

---

**To configure SSH keys for repository checkout in GitHub Actions, provide your private key via the `ssh-key` input in `actions/checkout`, which automatically writes the credential to a temporary file, configures Git's `core.sshCommand`, and securely removes all sensitive data after job completion.**

The `actions/checkout` action provides native support for SSH authentication, enabling secure access to private repositories and submodules without manual credential management on runners. When you configure SSH keys for checkout in GitHub Actions using the dedicated inputs, the action handles temporary file creation, host verification, and automatic cleanup according to GitHub's security model.

## SSH Authentication Inputs

The action exposes four inputs specifically for SSH configuration, defined in [`action.yml`](https://github.com/actions/checkout/blob/main/action.yml) and consumed by [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts).

### The Four Key Inputs

- **`ssh-key`**: The private SSH key content, typically stored as an encrypted GitHub Secret. This key is written to a temporary file in `$RUNNER_TEMP` during execution.
- **`ssh-known-hosts`**: Additional SSH host keys to trust, formatted as you would see in a standard `known_hosts` file. Use `ssh-keyscan` to generate entries for internal Git servers.
- **`ssh-strict`**: Boolean flag defaulting to `true`. When enabled, the SSH command includes `StrictHostKeyChecking=yes` and `CheckHostIP=no` to prevent man-in-the-middle attacks.
- **`ssh-user`**: The username for SSH connections, defaulting to `git` for standard GitHub repositories.

## How the Action Processes SSH Credentials

The implementation spans two critical source files that handle input parsing and authentication configuration.

### Input Parsing in input-helper.ts

In [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts), the `getInputs()` function reads workflow inputs and populates the `IGitSourceSettings` interface:

```typescript
// Conceptual representation based on source implementation
result.sshKey = core.getInput('ssh-key')
result.sshKnownHosts = core.getInput('ssh-known-hosts')
result.sshStrict = core.getBooleanInput('ssh-strict')
result.sshUser = core.getInput('ssh-user') || 'git'

```

### SSH Configuration in git-auth-helper.ts

The [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts) file contains the `configureAuth()` method, which calls `configureSsh()` to establish the authentication context. This process performs four critical operations:

1. Writes the private key from `ssh-key` to a temporary file with restricted permissions (0600)
2. Writes known hosts data to `$RUNNER_TEMP` if provided via `ssh-known-hosts`
3. Constructs an SSH command string combining the key path, user, and strictness options
4. Executes `git config core.sshCommand` to persist the settings for all subsequent Git operations

When `ssh-strict` is `true` (default), the generated command resembles:

```bash
ssh -i "$RUNNER_TEMP/ssh-key-random-id" -o StrictHostKeyChecking=yes -o CheckHostIP=no -o "UserKnownHostsFile=$RUNNER_TEMP/known_hosts" -l git

```

When `ssh-strict` is `false`, the `StrictHostKeyChecking` and `CheckHostIP` options are omitted, allowing connections to hosts not present in `known_hosts`.

### Temporary File Handling and Cleanup

The action generates unique temporary filenames for SSH keys to prevent collisions between concurrent jobs. After job completion, a post-step defined in the action metadata removes:

- The temporary private key file from `$RUNNER_TEMP`
- The temporary known-hosts file (if created)
- The `core.sshCommand` Git configuration entry

This ensures no SSH credentials persist on self-hosted or GitHub-hosted runners after the workflow finishes.

## Step-by-Step Workflow Configuration

### Basic SSH Checkout Example

Store your SSH private key as a repository secret (typically named `SSH_PRIVATE_KEY`), then reference it in your workflow:

```yaml
name: Checkout with SSH
on: [push]

jobs:
  checkout:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout private repository
        uses: actions/checkout@v4
        with:
          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}

```

This minimal configuration uses defaults: strict host checking enabled, `git` as the user, and GitHub's pre-installed host keys.

### Advanced Configuration with Known Hosts

For internal Git servers or enhanced security pinning, provide explicit host keys:

```yaml
      - name: Checkout with custom hosts
        uses: actions/checkout@v4
        with:
          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
          ssh-known-hosts: |
            github.com ssh-rsa AAAAB3NzaC1yc2EAAA...
            git.company.internal ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
          ssh-user: git

```

Generate host keys using `ssh-keyscan git.company.internal` locally before adding them to your secret or workflow file.

### Disabling Strict Host Checking

For testing environments or dynamically provisioned hosts where host keys change frequently, disable strict checking:

```yaml
      - name: Checkout without strict verification
        uses: actions/checkout@v4
        with:
          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
          ssh-strict: false

```

**Security Warning**: Setting `ssh-strict: false` removes protection against man-in-the-middle attacks. Only use this in isolated, trusted network environments.

## Security and Implementation Details

### Why core.sshCommand Instead of GIT_SSH_COMMAND

The action configures Git's `core.sshCommand` rather than the `GIT_SSH_COMMAND` environment variable. According to the `actions/checkout` source code, this approach ensures:

- **Persistence across subprocesses**: Submodule fetches and subsequent `git` commands inherit the SSH configuration automatically
- **Isolation**: Settings are scoped to the repository context rather than the entire shell environment
- **Cleanup**: Git configuration entries are easier to reset than environment variables in action post-processing

This method ensures that nested Git operations (like recursive submodule updates) authenticate correctly without exposing credentials to parent processes.

## Summary

- The `actions/checkout` action accepts four SSH-related inputs (`ssh-key`, `ssh-known-hosts`, `ssh-strict`, and `ssh-user`) processed in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts) and applied via [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts)
- SSH keys are written to temporary files in `$RUNNER_TEMP` with `0600` permissions, and `core.sshCommand` is configured to use these credentials for all Git operations
- Strict host checking (`ssh-strict: true`) adds `StrictHostKeyChecking=yes` and `CheckHostIP=no` to prevent connection to untrusted hosts, while `false` allows connections to any host
- Automatic post-job cleanup removes temporary key files and Git configuration entries, ensuring no credentials leak between jobs or persist on runners
- Use `ssh-known-hosts` to pin specific host keys for internal repositories, or set `ssh-strict: false` for testing environments (with security trade-offs)

## Frequently Asked Questions

### Where should I store the SSH private key in GitHub Actions?

Store the SSH private key as an encrypted repository secret or organization secret, then reference it via `${{ secrets.SECRET_NAME }}` in the `ssh-key` input. Never hardcode SSH keys directly in workflow files. The action writes this key to a temporary file during execution and deletes it immediately after the job completes according to the cleanup logic in [`git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/git-auth-helper.ts).

### What is the difference between ssh-strict true and false?

When `ssh-strict` is `true` (default), the action includes `StrictHostKeyChecking=yes` and `CheckHostIP=no` in the SSH command, requiring the host to exist in `known_hosts` and preventing DNS spoofing attacks. When `false`, these options are omitted from the `core.sshCommand` configuration, allowing connections to hosts whose keys haven't been cached, which carries security risks but enables connections to new or dynamically provisioned hosts.

### How does actions/checkout clean up SSH keys after the job?

The action registers a post-step that executes after your job finishes, calling cleanup functions in [`git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/git-auth-helper.ts) that delete the temporary private key file and known-hosts file from `$RUNNER_TEMP`, then unset the repository's `core.sshCommand` configuration. This ensures ephemeral credentials never persist on the runner for subsequent jobs or workflow runs.

### Can I use SSH authentication for submodules?

Yes. When you configure SSH keys using the `ssh-key` input, the `core.sshCommand` configuration persists for all Git operations in the repository, including recursive submodule fetches. If your submodules reside in different repositories requiring different SSH keys, you must configure authentication separately after the initial checkout or use deploy keys with access to multiple repositories.