Skip to main content
Guides

SSH access

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.

How it works

When you grant SSH access:

  1. Moat starts an SSH agent proxy inside the container
  2. The proxy connects to your host’s SSH agent (SSH_AUTH_SOCK)
  3. Key listing and signing requests are forwarded to your real SSH agent
  4. Only keys mapped to granted hosts are visible to the container
  5. Private keys never enter the container—only signature requests are proxied

Prerequisites

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_ed25519

List loaded keys:

$ ssh-add -l

256 SHA256:abc123... user@host (ED25519)

Granting SSH access

Grant access to a specific host:

$ moat grant ssh --host github.com

Using key: user@host (SHA256:abc123...)
Granted SSH access to github.com

Grant access to multiple hosts:

$ moat grant ssh --host github.com
$ moat grant ssh --host gitlab.com
$ moat grant ssh --host bitbucket.org

Using SSH in runs

Via CLI flag

$ moat run --grant ssh:github.com -- git clone git@github.com:org/repo.git

Via agent.yaml

grants:
  - ssh:github.com
  - ssh:gitlab.com

Then:

$ moat run -- git clone git@github.com:org/repo.git

Example: Clone and work with a private repository

  1. Ensure SSH agent is running with your key:

    $ ssh-add -l
  2. Grant SSH access:

    $ moat grant ssh --host github.com
  3. 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.
    ...
  4. Work with the repository:

    $ moat run --grant ssh:github.com -- sh -c "cd private-repo && git pull"

Combining SSH and HTTPS credentials

For workflows that use both SSH (for git) and HTTPS (for APIs):

grants:
  - github         # HTTPS API access
  - ssh:github.com # SSH git access
$ moat run -- sh -c "
  git clone git@github.com:org/repo.git
  cd repo
  # Use GitHub API via HTTPS (token injected)
  curl -s https://api.github.com/repos/org/repo/pulls
"

Host-specific key mapping

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.com

Inside 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).

Interactive SSH sessions

For interactive SSH (not just git), use interactive mode:

$ moat run -i --grant ssh:myserver.com -- ssh user@myserver.com

Revoking SSH access

Remove SSH access for a host:

$ moat revoke ssh:github.com

Troubleshooting

”SSH_AUTH_SOCK not set”

Your SSH agent is not running. Start it:

$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519

Add to your shell profile to start automatically.

”Permission denied (publickey)”

  1. Verify the key is loaded:

    $ ssh-add -l
  2. Verify the host is granted:

    $ moat run --grant ssh:github.com -- env | grep SSH
  3. Test SSH from outside Moat:

    $ ssh -T git@github.com

“Could not read from remote repository”

The SSH grant may be missing. Add it:

$ moat run --grant ssh:github.com -- git clone git@github.com:org/repo.git

Or in agent.yaml:

grants:
  - ssh:github.com

Key not being used

If 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_gitlab

Security considerations

What 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 agent.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"