| title | SSH access | ||||||
|---|---|---|---|---|---|---|---|
| description | Grant agents SSH access to specific hosts without exposing private keys. | ||||||
| keywords |
|
This guide covers granting agents SSH access to specific hosts. Moat proxies SSH agent requests so agents can authenticate via SSH without your private keys entering the container.
When you grant SSH access:
- Moat starts an SSH agent proxy inside the container
- The proxy connects to your host's SSH agent (
SSH_AUTH_SOCK) - Key listing and signing requests are forwarded to your real SSH agent
- Only keys mapped to granted hosts are visible to the container
- Private keys never enter the container—only signature requests are proxied
Your SSH agent must be running with keys loaded:
# Check if SSH agent is running
$ echo $SSH_AUTH_SOCK
# If not set, start the agent
$ eval "$(ssh-agent -s)"
# Add your key
$ ssh-add ~/.ssh/id_ed25519List loaded keys:
$ ssh-add -l
256 SHA256:abc123... user@host (ED25519)Grant access to a specific host:
$ moat grant ssh --host github.com
Using key: user@host (SHA256:abc123...)
Granted SSH access to mygithub.libinneed.workers.devGrant access to multiple hosts:
$ moat grant ssh --host github.com
$ moat grant ssh --host gitlab.com
$ moat grant ssh --host bitbucket.org$ moat run --grant ssh:github.com -- git clone git@github.com:org/repo.gitgrants:
- ssh:github.com
- ssh:gitlab.comThen:
$ moat run -- git clone git@github.com:org/repo.git-
Ensure SSH agent is running with your key:
$ ssh-add -l
-
Grant SSH access:
$ moat grant ssh --host github.com
-
Clone a private repository:
$ moat run --grant ssh:github.com -- git clone git@github.com:my-org/private-repo.git Cloning into 'private-repo'... remote: Enumerating objects: 1234, done. remote: Counting objects: 100% (1234/1234), done. ... -
Work with the repository:
$ moat run --grant ssh:github.com -- sh -c "cd private-repo && git pull"
For workflows that use both SSH (for git) and HTTPS (for APIs):
grants:
- github # HTTPS API access
- ssh:github.com # SSH git accessWhen both github and ssh:github.com grants are active, Moat automatically
configures git to use SSH instead of HTTPS for github.com. This means
git clone https://github.com/org/repo.git is transparently rewritten to use
git@github.com:org/repo.git. This avoids authentication issues caused by the
proxy's TLS interception conflicting with git's HTTPS transport.
To disable the rewrite and use HTTPS for GitHub even when an SSH grant is active, set MOAT_GIT_SSH_GITHUB=0 in moat.yaml under env: or pass it via --env.
$ moat run -- sh -c "
# This uses SSH under the hood (automatic rewrite)
git clone https://github.com/org/repo.git
cd repo
# Use GitHub API via HTTPS (token injected)
curl -s https://api.github.com/repos/org/repo/pulls
"SSH grants are host-specific. Each grant maps your SSH key to one host:
$ moat grant ssh --host github.com
$ moat grant ssh --host gitlab.comInside the container, only keys for granted hosts are visible:
# With only github.com granted:
$ moat run --grant ssh:github.com -- ssh -T git@github.com
Hi user! You've successfully authenticated...
$ moat run --grant ssh:github.com -- ssh -T git@gitlab.com
Permission denied (publickey).For interactive SSH (not just git), use interactive mode:
$ moat run -i --grant ssh:myserver.com -- ssh user@myserver.comSSH credentials are stored separately from other grants. To remove SSH access for a host, re-grant it to overwrite, or delete the SSH mapping file directly:
$ rm ~/.moat/credentials/ssh.jsonThis removes all SSH host mappings. To remove a single host, edit the file and delete the corresponding entry.
Your SSH agent is not running. Start it:
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519Add to your shell profile to start automatically.
-
Verify the key is loaded:
$ ssh-add -l
-
Verify the host is granted:
$ moat run --grant ssh:github.com -- env | grep SSH -
Test SSH from outside Moat:
$ ssh -T git@github.com
The SSH grant may be missing. Add it:
$ moat run --grant ssh:github.com -- git clone git@github.com:org/repo.gitOr in moat.yaml:
grants:
- ssh:mygithub.libinneed.workers.devIf you have multiple keys, the SSH agent proxy uses the first key that was loaded. Load your preferred key first:
$ ssh-add ~/.ssh/id_ed25519_github
$ ssh-add ~/.ssh/id_ed25519_gitlabWhat this protects:
- Private keys never enter the container filesystem
- Keys are only usable for granted hosts
- Signing operations are logged in the audit trail
What this does not protect:
- A malicious agent could make any git operation on granted hosts
- The agent has full access to repositories it can clone
- Commits are made with whatever git identity is configured
Configure git identity in your moat.yaml if needed:
env:
GIT_AUTHOR_NAME: "My Agent"
GIT_AUTHOR_EMAIL: "agent@example.com"
GIT_COMMITTER_NAME: "My Agent"
GIT_COMMITTER_EMAIL: "agent@example.com"- Running Claude Code — Use SSH with Claude Code
- Credential management — How credential injection works