Skip to content

fix(docker): mount --ssh keys outside /root for --host shells - #20

Merged
visciang merged 1 commit into
athonet-open:mainfrom
meox:fix/ssh-key-mount-host
Jul 2, 2026
Merged

fix(docker): mount --ssh keys outside /root for --host shells#20
visciang merged 1 commit into
athonet-open:mainfrom
meox:fix/ssh-key-mount-host

Conversation

@meox

@meox meox commented Jul 1, 2026

Copy link
Copy Markdown

Problem

pix shell --host drops privileges to a non-root user whose UID matches the
host user (so bind-mounted files keep correct ownership). However,
--ssh <id>=<key> mounts the key under /root/.ssh/<name> and pins
GIT_SSH_COMMAND=ssh -i /root/.ssh/<name> -o IdentitiesOnly=yes ....

/root is mode 0700, so the dropped user cannot even traverse into it:

Warning: Identity file /root/.ssh/id_ed25519_hpe not accessible: Permission denied.
git@github.com: Permission denied (publickey).

IdentitiesOnly=yes additionally prevents SSH from falling back to the
forwarded agent, so mix deps.get (and any git-over-SSH) fails inside
pix shell --host even though both the key and the agent are available.

Fix

Mount user-provided SSH keys under /pix/ssh/<name> instead of
/root/.ssh/<name>. Docker creates the intermediate mount directories as
world-traversable 0755, and the mounted key keeps its host ownership
(matching the host UID under --host), so:

  • the dropped non-root user can read the key (owner match + traversable parents), and
  • root can still read it in the default (non---host) shell.

IdentitiesOnly=yes is intentionally preserved, so pix keeps using exactly the
specified key (avoiding "too many authentication failures" when the agent holds
many keys). Only the mount location changes.

Testing

  • mix format --check-formatted, mix compile --warnings-as-errors, and
    mix credo --strict all pass.
  • Reproduced the exact failing setup in a container (non-root user matching the
    host UID, IdentitiesOnly=yes, no agent fallback):
    • key at /root/.sshPermission denied (before)
    • key at /pix/ssh → readable, and ssh -T git@github.com authenticates
      successfully (after)

`pix shell --host` drops privileges to a non-root user matching the host
UID, but `--ssh <id>=<key>` mounted the key under /root/.ssh (mode 0700),
which that user cannot traverse. git then failed with "Identity file not
accessible: Permission denied", and because GIT_SSH_COMMAND pins
IdentitiesOnly=yes it could not fall back to the forwarded agent either
("Permission denied (publickey)").

Mount user-provided keys under /pix/ssh instead. Docker creates the
intermediate mount dirs as world-traversable 0755, and the key keeps its
host ownership (matching the host UID under --host), so the dropped user
can read it while root still can too. IdentitiesOnly=yes is preserved.
@meox

meox commented Jul 1, 2026

Copy link
Copy Markdown
Author

--ssh behavior after this change

Only the location of an explicit-key mount changes (/root/.ssh/<key>/pix/ssh/<key>).
The agent-only --ssh default path is untouched — it forwards the agent socket exactly as
before (parse_ssh_key_paths("default") returns [], so no key is mounted and no
GIT_SSH_COMMAND is set).

--ssh spec Agent forwarded Key mounted GIT_SSH_COMMAND Affected by this PR
default yes no no no (unchanged)
default=<key> yes /pix/ssh/<key> -i /pix/ssh/<key> -o IdentitiesOnly=yes yes (mount path only)
id=<key> no /pix/ssh/<key> same yes (mount path only)
/path/to/key no /pix/ssh/<key> same yes (mount path only)

@meox
meox force-pushed the fix/ssh-key-mount-host branch from c0887d4 to cad0c5d Compare July 2, 2026 11:50
@visciang
visciang merged commit 4208018 into athonet-open:main Jul 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants