Is there a simple way to get a list of all fingerprints entered in the .ssh/authorized_keys || .ssh/authorized_keys2 file?

ssh-keygen -l -f .ssh/authorized_keys 

will only return fingerprint of first line / entry / publickey

hack with awk:

awk 'BEGIN { 
    while (getline < ".ssh/authorized_keys") {
        if ($1!~"ssh-(r|d)sa") {continue}
        print "Fingerprint for "$3
        system("echo " "\""$0"\"> /tmp/authorizedPublicKey.scan; \
            ssh-keygen -l -f /tmp/authorizedPublicKey.scan; \
            rm /tmp/authorizedPublicKey.scan"
        )
    }
}'

but is there an easier way or ssh command I didn't find?

  • To do this reliably you have to consider the options field in the authorized_keys file, which the ssh-keygen baulks at. I looked for a reliable way to parse it but the best I could come up with is covered by this answer. – starfry Feb 10 '17 at 8:51
up vote 36 down vote accepted

Here's another hack using plain bash without temporary files:

while read l; do
  [[ -n $l && ${l###} = $l ]] && ssh-keygen -l -f /dev/stdin <<<$l;
done < .ssh/authorized_keys

You can easily make it a function in your .bashrc:

function fingerprints() {
  local file="${1:-$HOME/.ssh/authorized_keys}"
  while read l; do
    [[ -n $l && ${l###} = $l ]] && ssh-keygen -l -f /dev/stdin <<<$l
  done < "${file}"
}

and call it with:

$ fingerprints .ssh/authorized_keys
  • 1
    nice @Raphink , thank you. added code.childno.de/marcel/changeset/afdce0dd ;) One note: ssh-keygen -l -f /dev/stdin seems not to work on a mac.. nevertheless not relevant for servers but gnaa apple or is it a BSD "problem" getting /dev/stdin is not a public key file.?! – childno͡.de Aug 1 '12 at 12:16
  • 1
    Reading from /dev/stdin is not a great idea in general, it's better to use -, but for some reason ssh-keygen doesn't know about -... – ℝaphink Aug 1 '12 at 12:34
  • Doesn't work on Mac? – Will Jul 28 '14 at 1:13
  • 1
    This does not work if the keys are prefixed with options. – starfry Feb 9 '17 at 11:22
  • 1
    @ℝaphink: I'd go for local file="${1:-$HOME/.ssh/authorized_keys}" to allow for it to work without any arguments and default to the usual ~/.ssh/authorized_keys file and quote the < "$file" used as input to the while loop. – 0xC0000022L Aug 9 '17 at 12:24

Here's a portable way to show all key fingerprints for a given file, tested on Mac and Linux:

#!/bin/bash

fingerprint_keys()
{
    if (( $# != 1 )); then
        echo "Usage: ${FUNCNAME} <authorized keys file>" >&2
        return 1
    fi

    local file="$1"
    if [ ! -r "$file" ]; then
        echo "${FUNCNAME}: File '${file}' does not exist or isn't readable." >&2
        return 1
    fi

    # Must be declared /before/ assignment, because of bash weirdness, in
    # order to get exit code in $?.
    local TMPFILE

    TEMPFILE=$(mktemp -q -t "$0.XXXXXXXXXX")
    if (( $? != 0 )); then
        echo "${FUNCNAME}: Can't create temporary file." >&2
        return 1
    fi

    while read line; do
        # Make sure lone isn't a comment or blank.
        if [[ -n "$line" ]] && [ "${line###}" == "$line" ]; then
            # Insert key into temporary file (ignoring noclobber).
            echo "$line" >| "$TEMPFILE"

            # Fingerprint time.
            ssh-keygen -l -f "$TEMPFILE"

            # OVerwrite the file ASAP (ignoring noclobber) to not leave keys
            # sitting in temp files.
            >| "$TEMPFILE"
        fi
    done < "$file"

    rm -f "$TEMPFILE"
    if (( $? != 0 )); then
        echo "${FUNCNAME}: Failed to remove temporary file." >&2
        return 1
    fi
}

Example Usage:

bash $ fingerprint_keys ~/.ssh/authorized_keys
2048 xx:xx:xx:xx:xx:xx:xx:xx:bb:xx:xx:xx:xx:xx:xx:xx  x@x.local (RSA)
bash $ 
  • sorry to say that but that's neither "simplier", nor "smaller" not even "smarter" and doesn't take another approach than listed above. just a script using more error handlers ;) – childno͡.de Jul 29 '14 at 5:40
  • 3
    Which makes it safer, right? You're welcome to make edits but why downvote? I didn't propose that it was any kind of better solution than yours... I feel a secure tempfile is better, and that more safety is needed for scripting purposes. Also, the version above is noclobber-safe. – Will Aug 2 '14 at 2:05
  • For a FreeBSD system (which does not use bash by default), I made the following changes: Assuming bash is installed from ports, change the first line to #!/usr/local/bin/bash. I then called the function by adding this as the last line: fingerprint_keys $@. I saved the script as fingerprints.bash, marking it executable with chmod u+x ./fingerprints.bash. Additionally, I added a comment to the file with the link to this answer, like so, near the top # solution from "Will" on SO http://serverfault.com/a/615892/126742. Call it like so ./fingerprints.bash ~/.ssh/authorized_keys. – derekv Aug 26 '15 at 13:44
  • 1
    @derekv: the more portable method is to use the following hashbang: #!/usr/bin/env bash, because the path for env is very portable and it tells env to execute the Bash it knows about. – 0xC0000022L Aug 9 '17 at 12:21

A one-liner based on the /dev/stdin trick from ℝaphink's answer and man xargs → EXAMPLES:

egrep '^[^#]' ~/.ssh/authorized_keys | xargs -n1 -I% bash -c 'ssh-keygen -l -f /dev/stdin <<<"%"'
  • This works great, and given it's a one-liner, can easily be used to run the command via SSH. Thanks! – Thibaut Barrère Jan 11 at 13:24

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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