Ssh-Keygen Accepting Stdin

ssh-keygen accepting stdin


echo $pubkey | ssh-keygen -lf /dev/stdin
/dev/stdin is not a public key file.

/dev/stdin is actually a unix pipe, not a regular file, so ssh-keygen fails to open the file

ssh-keygen -lf /dev/stdin  <<<$key
1024 92:6a:3f:5c:1f:78:.....

/dev/stdin refers to a regular file, created by using a bash heredoc. You can verify this:

# ls -l /dev/stdin <<<$pubkey
lrwxrwxrwx 1 root root 15 Feb 11 08:07 /dev/stdin -> /proc/self/fd/0
# ls -l /proc/self/fd/0 <<<$pubkey
lr-x------ 1 juergen juergen 64 Apr 14 13:31 /proc/self/fd/0 -> /tmp/sh-thd-1271250023 (deleted)

How to execute ssh-keygen without prompt

We need to accomplish two steps automatically:

  1. Enter a passphrase. Use the -N flag (void string for this example):

    ssh-keygen -t rsa -N ''

  2. Overwrite the key file:

Use -f to enter the path (in this example id_rsa) plus a here-string to answer yes to the following question:

ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa <<<y >/dev/null 2>&1

Or, under a bash like shell, If you certainly want to overwrite the previous one, use just a here-string to feed the command with all the need input:

ssh-keygen -q -t rsa -N '' <<< $'\ny' >/dev/null 2>&1

From ssh-keygen man page:

  -N new_passphrase provides the new passphrase.
-q silence ssh-keygen.
-f filename specifies the filename of the key file.

Step by step explanation

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/klashxx/.ssh/id_rsa):

1) To avoid entering the key use -f:

$ ssh-keygen -t rsa -f ~/.ssh/id_rsa
Generating public/private rsa key pair.
/home/klashxx/.ssh/id_rsa already exists.
Overwrite (y/n)?

ATTENTION: If you don't care about the RSA file name and certainly want to overwrite the previous one, check the instructions below point four.

2) Now we need to answer "y" automatically to the overwrite question (let's use a here-string for that job):

$ ssh-keygen -t rsa -f ~/.ssh/id_rsa <<< y
Generating public/private rsa key pair.
/home/klashxx/.ssh/id_rsa already exists.
Overwrite (y/n)? Enter passphrase (empty for no passphrase):

3) Finally we're going to use the -N flag to enter a void pass:

$ ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa <<< y
Generating public/private rsa key pair.
/home/klashxx/.ssh/id_rsa already exists.
Overwrite (y/n)? Your identification has been saved in /home/klashxx/.ssh/id_rsa.
Your public key has been saved in /home/klashxx/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Xo0t6caMB/8TSsigxfY28JIfqYjyqxRZrFrPncx5yiU klashxx@server
The key's randomart image is:
+---[RSA 2048]----+
| |
| . |
| o . |
| + * = |
| +. + BSo= o |
|...o.+o+XO... |
|.. .o.E==+B. . |
|o . ...=.o... |
|.+o. o .. |
+----[SHA256]-----+

4) Extra ball, cleanup the output, just check the return code:

$ ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa <<<y >/dev/null 2>&1
$ echo $?
0

An alternative path to overwrite the previous RSA file (no -f flag needed)

NOTE: Only bash like shells.

If you don't care about the RSA name and just want to overwrite it, we need to answer these two questions automatically:

  1. Enter file in which to save the key: /example/path/.ssh/id_rsa already exists.

  2. Overwrite (y/n)?

If we do this by hand, for the first question we just need to hit enter, and for the second, type y and press enter.

We can simulate these actions by using the following here-string:

$'\ny'

From the bash man page:

Words of the form $'string' are treated specially. The word expands to
"string", with backslash-escaped characters replaced as specified by
the ANSI C standard.

\n new line

So, if we use od to analyze our string:

cat - <<< $'\ny' | od -c
0000000 \n y \n

We see that we're getting just what we need to answer the questions.

Points 1 and 2 can be summarized into:

ssh-keygen -q -t rsa  <<< $'\ny'

And the final command will be:

$ ssh-keygen -q -t rsa -N '' <<< $'\ny' >/dev/null 2>&1
$ echo $?
0

Kudos

@lukasz-dynowski, @redochka, @mellow-yellow, @yeti and the rest of the folks in this thread.

ssh-keygen - create public key file from private key file stored in s3

After looking other related question, found that fifo or named pipes can have permissions, so I tried this and worked as expected, hope it helps anyone.

  1. create named pipe with permission (pipe with name fifo)

    mkfifo -m 600 fifo
  2. run command pointing that pipe

    curl -s https://bucket.s3.amazonaws.com/private-key.pem > fifo | ssh-keygen -y -f fifo >> ~/.ssh/authorized_keys
  3. all in one command

    mkfifo -m 600 fifo && curl -s https://bucket.s3.amazonaws.com/private-key.pem > fifo | ssh-keygen -y -f fifo >> ~/.ssh/authorized_keys

Specify private key in SSH as string

There is no such switch - as it would leak sensitive information. If there were, anyone could get your private key by doing a simple ps command.

EDIT: (because of theg added details in comment)

You really should store the key in to a temporary file. Make sure you set the permissions correctly before writing to the file, if you do not use command like mktemp to create the temporary file.


Make sure you run the broker (or agent in case of OpenSSH) process and load the key using <whatever command you use to fetch it form the database> | ssh-add -

Add SSH key from variable


ssh-add - <<< "${SSH_PRIVATE_KEY}"

How to make ssh receive the password from stdin

You can't with most SSH clients. You can work around it with by using SSH API's, like Paramiko for Python. Be careful not to overrule all security policies.

Why doesn't SSH work with a piped password on stdin?

As mentioned in the other answer, security is the reason.

From technical point of view, by doing echo password | ssh user@host, you push the string to pipe and the characters are waiting on the ssh side to be read. But most of password prompts truncate this input before showing prompt (and modifying it to not-show the characters -- described later).

To answer the final question about difference, both are some kind of pipes, but when you have terminal on the other side, you can communicate with this side using control characters and you can reading/setting specific properties of the terminal, which both obviously fails on normal pipe from echo.

The error message is caused by the fact, that when you read the password from terminal, you modify terminal properties, so it will not show characters written (so called raw mode). And if the ssh program can't communicate with the terminal it fails like this.

How to answer the ssh-keygen passphrase prompt from Python?

ssh-keygen has -P switch to provide a passphrase:

command = "ssh-keygen -y -f {} -P \"{}\"".format(key1, passphrase)

It's ok to use an empty passphrase (-P ""), when the key is not encrypted.

And if you use a wrong/empty passphrase (-P "wrong"), for an encrypted key, ssh-keygen will fail – it won't prompt you for a good passphrase again.

How to pass an ssh key passphrase via environment variable

So there are actually a few things that is important for what you are trying to do:

  1. DISPLAY must be set
  2. it must not have a terminal associated with it
  3. on some machines it may be necessary to redirect the input from /dev/null (mine is one of them).
  4. SSH_ASKPASS must contain an executable which outputs the passphrase on stdout.

So for an example of getting it to work (for me, should work on other linux also I guess):

Create dummy key:

ssh-keygen -t rsa -C se-so-38354773 -f /tmp/se-so-38354773.key -N 'se-so-38354773-pp'

Create askpass script to echo password files:

cat > /tmp/se-so-38354773-askpass <<EOF
#!/usr/bin/env bash
echo "${0}:${@} : this is for debugging to see if the echo script runs" 1>&2
echo "se-so-38354773-pp"
EOF
chmod +x /tmp/se-so-38354773-askpass

I placed this file in /tmp/ - but this is not a good for security unless you also change permissions on the file before writing to it to ensure that nobody else can read it (or set umask).

Then you can do ssh-add as follow:

DISPLAY=":0.0" SSH_ASKPASS="/tmp/se-so-38354773-askpass" setsid ssh-add /tmp/se-so-38354773.key </dev/null

The setsid dissociates it from your terminal if there is one - This is not needed on my computer though - but yeah - I think it may be needed in some other contexts.

And when you are done testing do clean up:

ssh-add -d /tmp/se-so-38354773.key
rm /tmp/se-so-38354773*

Example output on my computer:

iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ ssh-keygen -t rsa -C se-so-38354773 -f /tmp/se-so-38354773.key -N 'se-so-38354773-pp'
Generating public/private rsa key pair.
Your identification has been saved in /tmp/se-so-38354773.key.
Your public key has been saved in /tmp/se-so-38354773.key.pub.
The key fingerprint is:
SHA256:s+jVUPEyb2DzRM5y+Hm3XDzVRREKn5yU2d0hk61hIQ0 se-so-38354773
The key's randomart image is:
+---[RSA 2048]----+
| .E+=B=O|
| B*B*o=|
| X B*o o|
| o % o ..|
| S * ..+|
| . = . ...+|
| . o . o |
| . . |
| . |
+----[SHA256]-----+
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ cat > /tmp/se-so-38354773-askpass <<EOF
> #!/usr/bin/env bash
> echo "${0}:${@} : this is for debugging to see if the echo script runs" 1>&2
> echo "se-so-38354773-pp"
> EOF
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ chmod +x /tmp/se-so-38354773-askpass
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ DISPLAY=":0.0" SSH_ASKPASS="/tmp/se-so-38354773-askpass" setsid ssh-add /tmp/se-so-38354773.key </dev/null
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$
bash: : this is for debugging to see if the echo script runs
Identity added: /tmp/se-so-38354773.key (/tmp/se-so-38354773.key)
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ ssh-add -d /tmp/se-so-38354773.key
Identity removed: /tmp/se-so-38354773.key (se-so-38354773)
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ rm /tmp/se-so-38354773*

Batch script pass variable to stdin with git and ssh keys

Here is a way to acheive the same effect, but with different steps than what you hinted in your question:

  1. Start ssh-agent
  2. Add your key with ssh-add (it will ask for the password, just once)
  3. Launch as many git clone <url> as you need
  4. Clean up

Step two will ask for a password, instead of using set /p. The following batch file is somewhat of a port of github's ssh key guidelines. I tested it with a ssh connection to gitorious, running git version 1.7.6.msysgit.0 under cmd.exe in Windows Vista.

@rem Do not use "echo off" to not affect any child calls.
@setlocal

@:: Find out where is git installed
@where git > __wheregit.txt

@:: Under XP, there is no where command. Use this (thanks to Raymond Chen)
@:: http://blogs.msdn.com/b/oldnewthing/archive/2005/01/20/357225.aspx
@:: (for %%e in (%PATHEXT%) do @for %%i in (git%%e) do @if NOT "%%~$PATH:i"=="" echo %%~$PATH:i) > __wheregit.txt

@:: Move it to a environment variable, we will need to manipulate the string
@set /p wheregit= <__wheregit.txt
@del __wheregit.txt

@:: Parse the full file name of git.cmd to find the the path
@for /F "delims=" %%I in ("%wheregit:~0,-7%..") do @set git_install_root=%%~fI
@set PATH=%git_install_root%\bin;%git_install_root%\mingw\bin;%PATH%

@:: The keys are in the home directory.
@if not exist "%HOME%" @set HOME=%HOMEDRIVE%%HOMEPATH%
@if not exist "%HOME%" @set HOME=%USERPROFILE%

@ ::start ssh-agent, and save its output
@ssh-agent > __ssh-agent.out

@ ::parse the output and set environment vars needed by ssh-add
@FOR /F "eol=; tokens=1* delims=;" %%i in ('findstr /v echo __ssh-agent.out') do @set %%i
@del __ssh-agent.out

@ ::add the key to the agent (this will ask for the password)
@ssh-add %HOME%\.ssh\id_rsa

@ ::Call git. When it's time to use the key, its password will be provided by ssh-agent
@ ::Obviously you will put your git clone url here
@call git clone git@gitorious.org:siaki-sso/siaki-sp.git
@call git clone git@gitorious.org:siaki-sso/siaki-idp.git

@ ::Kill ssh-agent
@ssh-agent -k

@endlocal


Related Topics



Leave a reply



Submit