With my team, we need to share a few private keys and we store them in a pass repository.

So instead of extracting the key and storing it in cleartext on the filesystem, I am looking for a way to only keep the decrypted version shortly in memory:

$ sftp -i <(pass foo) user@host
Warning: Identity file /dev/fd/63 not accessible: No such file or directory.

Any idea why sftp is unable to read the temporary file descriptor? How to fix it?


Any idea why sftp is unable to read the temporary file descriptor?

Few facts:

  • the <(pass foo) process substitution will cause bash to create a pipe, run the pass foo command asynchronously with its output connected to the writing end of the pipe and replace the <(...) with a path of the form /dev/fd/63, where 63 is the file descriptor referring to the reading end of the pipe.
  • the /dev/fd/63 is a special path which allows a process to stat() and re-open the file referred by one of its file descriptors.
  • the shell forks + execs sftp, then sftp itself forks and execs ssh, causing the 63 file descriptor to be passed down via inheritance.
  • ssh will close all its file descriptors except 0, 1, 2 using the closefrom() function. That will also close fd 63.

Since 63 is no longer an open file descriptor in the ssh process, a stat() on /dev/fd/63 will fail with the error from the OP.

How to fix it?

Temporarily store the key in a filesystem in memory. In my Debian systemd provides me tmpfs under /run/user/<myUID>. The mountpoint is inaccessible to anyone but me (and root, of course).

Note a rogue process running under your user (or root) can read the file. But such process could also read from sshd's file descriptor 63 in your original approach.

Alternatively, when there is no safe tmpfs available:

  1. Create a temporary fifo. Note mktemp cannot do this directly. The safe way is to create a temporary private directory and then mkfifo in it.

  2. Make sure the permissions of the fifo itself are narrow, otherwise ssh will complain.

  3. Run

    sftp -i "/temp_dir/the_fifo" user@host
  4. In parallel run pass foo > "/temp_dir/the_fifo". A quirk: you need to do this twice; at least in my Debian ssh reads the key twice. The following command seems to work in my tests: cat ~/.ssh/id_rsa > "/temp_dir/the_fifo" && cat ~/.ssh/id_rsa > "/temp_dir/the_fifo". Probably a similar duplicated command will work for you:

    pass foo > "/temp_dir/the_fifo" && pass foo > "/temp_dir/the_fifo"

    You can run it in the background just before sftp (unless pass is interactive, I'm not familiar with the tool at all).

  5. At the end remove the fifo and the directory.

Still, a rogue process running under your user (or root) can read from the fifo before ssh does.

  • Thank you very much for your answer. Especially the "sftp itself forks and execs ssh" part, I should have thought about that! Regarding the fix, especially wanted to avoid storing it somewhere it could be stolen by someone who owns the machine. But it would still be better than storing a copy on the filesystem. – Philippe Feb 23 '19 at 4:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.