7

Edit: What I really need to know WHICH ssh key from authorized_keys has been used to identify the currently logged on user.

According to "man sshd":

Protocol 2 public key consist of options, keytype, base64-encoded key, comment.

I see that when I use ssh-keygen, the comment is usually the local identity of the user. Is there any way to access this value when I'm on the remote computer ? (Kind of like the SSH_CLIENT shell variable)

(Assuming I enforce the comment to be a remote identity of some sort, I would like to log this from a shell-script! This is on ubuntu)

1
  • I wonder if, after almost 4 years, you managed to find a solution for this problem. I am looking for something quite close to this: to identify user/email even when people did a connection as ROOT. I would even go so far to trust them if they would provide this information as an ENV variable that would be passed from the ssh client machine to the current server.
    – sorin
    May 4, 2014 at 13:33

6 Answers 6

3

I personally would not recommend this solution, but am posting this for the sake of discussion.

If you're willing to:

  1. Change the Logging level of SSHd
  2. Give your script access to /var/log/secure (or equivalent log file)

You can set "LogLevel DEBUG" in sshd_config to get the following entries each time an ssh key is used successfully for authentication:

Aug 13 11:51:13 myhost sshd[20195]: debug1: matching key found: file /home/myuser/.ssh/authorized_keys, line 3
Aug 13 11:51:13 myhost sshd[20195]: Found matching DSA key: 00:aa:bb:cc:dd:ee:00:c0:0b:fa:ce:00:00:ab:cd:ef

Writing a script to parse the logs and retrieve the relevant information would be trivial. You could probably grep for "sshd[$PPID]" to reduce the lines the script has to munge.

Do note that changing the loglevel to DEBUG will increase the size of your logs considerable and may violate the privacy of users. From "man sshd_config":

Logging with a DEBUG level violates the privacy of users and is not recommended.

I'm sure there are various steps one can take to make this solution a little less ghastly (e.g. logging sshd DEBUG info to a different file and controlling access to that file and the script) but at the end if the day it will still make you cringe.

2
  • 1
    According to "man sshd" I should be able to add a "command" to the options field of each ssh key and this command would be executed when the key is used for authentication. I suppose I could use this to hack something together. I was hoping for a less spooky solution
    – krosenvold
    Aug 13, 2009 at 20:24
  • 1
    I suppose the environment option is even simpler
    – krosenvold
    Aug 13, 2009 at 20:25
3

It's for convenience, from the ssh-keygen man page on Debian:

For RSA1 keys, there is also a comment field in the key file that is only for convenience to the user to help identify the key. The comment can tell what the key is for, or whatever is useful. The comment is initialized to “user@host” when the key is created, but can be changed using the -c option.

I think the nearest you're going to get for determining which key was used to log in is with ssh-add, with -L, from the man page:

-L Lists public key parameters of all identities currently represented by the agent.

You can increase the logging level of the ssh daemon to DEBUG1:

LogLevel DEBUG1

And the log will show the RSA fingerprint of the SSH key used to log in:

Aug 13 08:52:56 ubuntu_test sshd[17115]: debug1: matching key found: file /home/username/.ssh/authorized_keys, line 1
Aug 13 08:52:56 ubuntu_test sshd[17115]: Found matching RSA key: xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx

You can get the fingerprint of a key with ssh-keygen:

-l Show fingerprint of specified public key file. Private RSA1 keys are also supported. For RSA and DSA keys ssh-keygen tries to find the matching public key file and prints its fingerprint. If combined with -v, an ASCII art representation of the key is supplied with the fingerprint.

From an authorized keys file, you would have to split up each line into a new file to read with ssh-keygen -l. Here's an example Ruby script that will do this:

#!/usr/bin/env ruby
File.open("/home/username/.ssh/authorized_keys").each do |l|
  file_name = l.split(" ")[2]
  key_file = File.new("#{file_name}.pub_key", "w")
  key_file.puts l
  key_file.close
  puts %x{ssh-keygen -l -f #{file_name}.pub_key}
end
1
  • Yes, it's for convenience. But I can enforce it to be a value that is well-known to me. I just need to know which key has been used to authorize the user
    – krosenvold
    Aug 13, 2009 at 7:04
1

This will help if you want to track the login from a script on the SSHd machine.

Step 1: Shell variable 'SSH_CLIENT' gives you two parts of the information

  • The remote IP address (192.168.1.2 in the line below)
  • The remote TCP port over which the client connected (56120 below)
    SSH_CLIENT='192.168.1.2 56120 22'  
                ----------- -----  
                 Source IP   Port

Step 2: You can now do a login (backwards) to the source IP (192.168.1.2) and check the UserID.

SSHd-Server$ ssh [email protected] exec "netstat -et  | grep 56120"  
 tcp  0  0 hostname:56120 localhost:ssh ESTABLISHED user1  9937126
                    -----                           ----- 

You have identified [email protected].

3
  • But this solution requires that the sshd machine be able to log on to all the client machines.
    – krosenvold
    Aug 13, 2009 at 7:02
  • @krosenvold, quite true. I am assuming a generally unix environment with the SSHd owner having at least a basic login access on the source machines.
    – nik
    Aug 13, 2009 at 11:41
  • I wish, I wish but my clients are a hetrogenous lot
    – krosenvold
    Aug 13, 2009 at 20:17
1

If you have the public key (of the suspected user) you can search the signature in auth.log. Match that with the output from (note that -l is here small -L):

ssh-keygen -l <enter>

This command will request the path to the public key and will output the signature for that key.

0

Since I couldn't find a complete answer on the net for this I wrote my own bash scritp:

#!/bin/bash

cat /root/.ssh/authorized_keys | while read KEY; do
        echo "";
        name=$(echo "$KEY" | cut -d ' ' -f3-);
        file_name=$(echo "$name" | tr ' ' '_');
        echo $KEY > $file_name;
        fingerprint=$(ssh-keygen -l -f $file_name);
        rm -f $file_name;
        echo "$name login's";
        logins=$(grep `echo "$fingerprint" | awk '{print $2}'` /var/log/secure*);
        logins_count=$(echo "$logins" | wc -l);
        echo "Total Login's: $logins_count";
        if [ -n "$logins" ]; then
                login_pids=$(echo "$logins" | perl -p -e 's/.*\[(.*)\].*/$1/g');
                for f in `ps -e | grep 'sshd' | awk '{print $1}' | grep "$login_pids"`; do
                        [ -n "$f" ] && echo "Current sessions pid: $f";
                done;
        fi;
done;

#

Edit: I wrote this many years later hope it might come in handy to someone https://github.com/sayajin101/SSH-Key-Login-Extended

0

I needed the same thing now and wrote a small script that updates the authorized_keys file and adds the environment variable SSH_COMMENT for every key in the file. If an option with the environment="SSH_COMMENT=<comment>" is already there it updates it, all other options remain untouched and in the same order as before. Also the comments remain untouched. The script also works fine if there are already other options containing spaces. This works by removing one part at a time from the end of a line until only the options remain.

Here is the bash function. It only needs grep, sed, cmp, mv, rm and chmod.

upgradeAuthorized() {
    local authorized="${1-}"

    if [ -z "$authorized" ]; then
        local defaultFile
        for defaultFile in "$HOME/.ssh/authorized_keys" "$HOME/.ssh/authorized_keys2"; do
            if upgradeAuthorized "$defaultFile"; then
                return 0
            fi
        done
        return 1
    fi

    if ! [ -f "$authorized" ]; then
        # Fail silently
        return 1
    fi

    local comment
    local line
    local key
    local keytype
    local options
    local commentEscaped
    local userEnv
    local newFile
    newFile="${authorized}.new"
    rm -f "$newFile"

    while IFS='' read -r line; do
        # Output comments and empty lines as-is
        if grep -Eq "^(\s*|\s*#.*)$" <<<"$line"; then
            echo "$line" >> "${newFile}"
            continue
        fi

        comment="${line##* }"
        line="${line% *}"
        key="${line##* }"
        line="${line% *}"
        keytype="${line##* }"
        options="${line% *}"
        if [[ "$options" == "$keytype" ]]; then
            options=""
        fi

        commentSshEscaped="$(sed "s/\"/\\\"/g" <<<"$comment")"
        if grep -Fq "environment=\"SSH_COMMENT=" <<< "$options"; then
            commentSedEscaped="$(sedEscapeReplace "$commentSshEscaped")"

            options="$(sed -E "s/(environment=\"SSH_COMMENT=)(.+?)*\"(,.*|$)/\1${commentSedEscaped}\"\3/g" <<<"$options")"
        elif [ -z "$options" ]; then
            options="environment=\"SSH_COMMENT=${commentSshEscaped}\""
        else
            options="environment=\"SSH_COMMENT=${commentSshEscaped}\",${options}"
        fi

        echo "${options} ${keytype} ${key} ${comment}" >> "${newFile}"
    done < "$authorized"

    if ! cmp -s "${authorized}" "${newFile}"; then
        mv -b "${newFile}" "${authorized}"
        chmod 0644 "${authorized}"
    else
        rm "${newFile}"
    fi
    return 0
}

Finally if you want to rerieve the comment from an arbitrary process you are allowed to access the environment, you can use the following function. It outputs the comment for a pid or nothing.

pSshComment() {
    local pid="${1-}"
    local default="${2-}"
    if [ -z "${pid}" ]; then
        echo "${default}"
        return 1
    fi

    if ! [ -f "/proc/${pid}/environ" ]; then
        echo "${default}"
        return 1
    fi

    local comment
    comment="$(xargs -0 printf '%s\n' < "/proc/${pid}/environ" 2>/dev/null | sed -nE "s/^SSH_COMMENT=(.*)$/\1/p")"
    if [ -z "$comment" ]; then
        return 1
    fi
    echo "$comment"
    return 0
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .