Git Permission Denied (publickey): Fix SSH for Agents, CI and Deployments
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
The Git server did not accept any SSH identity offered by the current process. On a developer laptop that may be a missing key. In a coding-agent container or CI runner, it is often the wrong identity, an unavailable agent socket, an untrusted host key or a deploy key without repository access.
Do not solve this by copying your personal private key into an agent or pipeline.
Diagnose before changing keys
git remote -v
ssh -T git@github.com
ssh -vT git@github.com
Verbose output shows which configuration and keys SSH considered. Look for Offering public key and the final failure. Then inspect the current environment:
ssh-add -l
ls -la ~/.ssh
git config --show-origin --get core.sshCommand
printf '%s\n' "$SSH_AUTH_SOCK"
In CI, verify whether checkout uses SSH at all. Many hosted runners use a temporary HTTPS token instead.
Local developer fix
Generate a modern Ed25519 key and protect it with a passphrase:
ssh-keygen -t ed25519 -C "developer@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Add only id_ed25519.pub to the Git provider. Never upload or paste the private key. Test again with ssh -T git@github.com.
If the repository remote uses HTTPS, keep that authentication flow or deliberately switch it:
git remote set-url origin git@github.com:ORG/REPOSITORY.git
Multiple Git identities
Map each identity to a distinct SSH alias:
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
Then use the alias:
git remote set-url origin git@github-work:company/repository.git
IdentitiesOnly yes prevents SSH from offering unrelated keys before the serverโs authentication limit is reached.
Coding agents and remote workspaces
A coding agent may run in a container, worktree, VM or remote sandbox. Check whether it sees the same SSH configuration and agent socket as your interactive shell.
Choose one deliberate model:
- Forward a constrained agent socket only into a trusted environment.
- Use a dedicated bot or app identity scoped to specific repositories.
- Use the platformโs short-lived HTTPS token for checkout and pull requests.
- Mount a read-only deploy key only when the task truly needs SSH.
Avoid mounting your entire ~/.ssh directory into agent containers. A compromised process may use keys even when it cannot print them.
CI runner fix
First decide whether SSH is necessary. A GitHub Actions workflow can normally use its temporary token with explicit permissions:
permissions:
contents: read
If a private dependency or deployment target requires SSH, create a dedicated key for that purpose. Store the private half in the CI secret store, register the public half with minimum access, and create known_hosts from a verified source.
Do not disable host verification with StrictHostKeyChecking=no. That converts an authentication repair into a man-in-the-middle risk.
Common failure patterns
The key is accepted but repository access is denied
Authentication to the provider and authorization to a repository are separate. The account or deploy key may lack access to the repository, organization or submodule.
Key permissions are rejected
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
It works interactively but fails in automation
The process may have a different home directory, no SSH_AUTH_SOCK, another known_hosts, or no secret access. Print paths and fingerprintsโnot secret valuesโto diagnose it.
A host key changed
Do not automatically delete the old entry. Verify whether the provider or server legitimately rotated its key and compare the published fingerprint.
Safe access design
- Give agents a separate, revocable identity.
- Prefer pull-request creation over direct branch writes.
- Scope repository and organization permissions narrowly.
- Keep production SSH credentials separate from source-control credentials.
- Rotate deploy keys when a runner or integration is retired.
- Record which identity created each automated commit.
Place this within the Git foundation for coding agents, apply GitHub controls for coding agents, and compare governance in GitHub vs GitLab. For server access, see how SSH works for AI servers and AI Security & Credentials.