我的一些 Debian 风格的服务器上的授权密钥已经因旧 PC 等的密钥而变得臃肿。有没有办法让我知道哪个密钥已用于登录?我想把它清理干净。
我搜索了 /var/log/auth 但没有真正的运气。
答案1
此时此刻值得学习的部分也许是 SSH 密钥的“注释”字段非常有用。虽然默认值user@hostname
是合理的,但一个用户创建多个 SSH 密钥是很常见的,每个密钥都有不同的目的:
ssh-keygen -C "this key is for backups" -t ....
ssh-keygen -C "webmaster access for www.example.com"
更重要的是,当公共 SSH 密钥插入到 中时
~/.ssh/authorized_keys
,最好保留(甚至扩展)该注释来标识密钥。如果密钥没有注释,则可以对其进行编辑。如果没有唯一的密钥注释,则很难区分一个密钥与另一个密钥,因为正如您所说,SHA256 哈希与公钥没有立即明显的相关性。
所以:
-C "this is the comment"
创建 SSH 密钥时使用唯一注释 ( )- 将密钥添加到authorized_keys 文件时,请确保注释不仅反映了密钥的所属人员,还反映了您授予该密钥访问权限的原因。
请记住,(仔细)编辑注释不会损害密钥的完整性。您可以编辑现有公钥(您的或其他人的)的通用注释,并使其对您或当前的目的更有意义。
话虽如此,你的问题似乎是一个有趣的挑战。做你想做的事情的主要限制是:
如上所述,具有特定密钥的人类可读描述符,以便可以明确地引用已使用或未使用的密钥
SSH 日志是使用 SSH 密钥时的源文档,这些日志通常不会无限期保留,因此只能判断“最近”使用了哪些 SSH 密钥。即使有长期的日志保留,年份条目通常在日志文件中不可用,并且按字母顺序排列的月份名称的排序需要进一步的繁琐。该脚本采用的捷径是简单地计算给定键在每个日志文件中出现的次数。
SSH 日志通常受到普通用户的读取保护,因此可能需要
sudo
访问权限才能读取它们。
但无论如何我们还是继续吧!
您想要检查“不活动”的公钥列表很可能是您~/.ssh/authorized_keys
文件中的密钥。该脚本需要ssh
一个朋友可以接受的格式的此类文件的路径名。特别是,ssh-keygen
将用于读取公钥并提取底层密钥的 SHA256 哈希值,这是与 中的 SSH 日志关联所需的哈希值/var/log/auth-log*
。
$ ssh-keygen -l -f .ssh/my-laptop-id_rsa.pub
2048 SHA256:YmiLC7LFQ+mSE3SHkXzbpFuWi0HbIpGCaIUYuR6rAiM root@my-laptop (RSA)
我们不会引用第一个参数(以位为单位的密钥长度),但第二个参数是我们最重要的密钥 SHA256 哈希值,第二个参数之外的所有内容都是密钥注释,加上附加的“(RSA)”它反映了用于密钥的加密方案。 ssh-keygen -l
是该脚本的主要盟友,以及用于存储多个密钥的数组技术——一个数组用于 SHA256 哈希值,另一个数组用于每个密钥的注释或脚本所称的“标签”。
最后,我们迭代 SHA256 哈希值数组,grep
通过
/var/log/auth.log*
文件来计算每个哈希值出现的次数,并显示格式化结果。
该脚本还有很多改进的空间,但希望这能激发一些关于解决问题的不同方法以及如何呈现结果的想法。
#!/usr/bin/env bash
set -e
sha_of_pubkeys() {
# Given an ssh authorized_keys file on stdin, extract the SHA256 hash of each
# key, and return:
# (sha256 hash) <space> (key comment)
# on stdout.
grep '^[^#]' |
ssh-keygen -l -f - |
sed -Ee 's/^[^ ]* +//'
} # sha_of_pubkeys
count_sha_in_logs() {
# Pass $1 with the key hash "SHA256:xxxxx"
# We'll return stdout with "<tab>n time(s) in filename"
regex="Accepted publickey for .* ssh2: .* $1$"
grep -wc "$regex" /var/log/auth.log* |
grep -v ':0$' |
awk -F: '{printf "\t%8d time(s) in %s\n", $2, $1}'
}
##############################
#
# M A I N
#
##############################
[[ -r "$1" ]] || {
printf "Can't read input file: %s\n" "$1"
exit 1
}
# We'll identify pub keys by their (unique) comment field.
# Store them in this array, indexed in order of occurrence.
key_ids=()
readarray -t key_ids << EOF
$(
# delete the first field (the hash) from sha_of_pubkeys stdout
sha_of_pubkeys < "$1" |
sed -Ee 's/^[^ ]* +//'
)
EOF
# Store the SHA256 hash of each key in this array:
key_shas=()
readarray -t key_shas << EOF
$(
# the hash is the first field from sha_of_pubkeys
sha_of_pubkeys < "$1" |
awk '{print $1}'
)
EOF
# How many unique keys did we find?
n_ids=$(
printf '%s\n' "${key_ids[@]}" |
sort |
uniq |
wc -l
)
if ( [[ ${#key_shas[@]} -eq ${#key_ids[@]} ]] &&
[[ ${#key_shas[@]} -eq ${n_ids} ]] )
then
printf '%d keys found in "%s".\nHere are their comment tags and key types:\n' ${n_ids} "$1"
sha_count=()
for i in $(jot $n_ids 0)
do
printf '%4d ... %s\n' $(($i+1)) "${key_ids[$i]}"
sha_count+=( "$(count_sha_in_logs "${key_shas[$i]}")" )
done
printf '\n'
for i in $(jot $n_ids 0)
do
if [[ -z "${sha_count[$i]}" ]]
then
s='does not appear.'
else
s="$(printf 'appears:\n%s\n' "${sha_count[$i]}")"
fi
printf 'Key %d\n label: "%s"\n hash: "%s"\n %s\n\n' $(($i+1)) "${key_ids[$i]}" "${key_shas[$i]}" "$s"
done
else
printf "Every key must have a comment field.\n"
printf "Every comment field must be unique.\n"
exit 1
fi
输出:
$ sudo ./test.sh ~/.ssh/authorized_keys
Password:
6 keys found in "/home/jim/.ssh/authorized_keys".
Here are their comment tags and key types:
1 ... jim@w541 (RSA)
2 ... admin@work-imac (RSA)
3 ... admin@other-imac (RSA)
4 ... [email protected] (RSA)
5 ... [email protected] (ed25519) (ED25519)
6 ... [email protected] (RSA)
Key 1
label: "jim@w541 (RSA)"
hash: "SHA256:CvsACdXgliEpeQtUriFW87vpMZEbO6V7znj/3bhmPwo"
does not appear.
Key 2
label: "admin@work-imac (RSA)"
hash: "SHA256:x9wjIdW1OpGQhQ6rGiN25Vm2Y8og7/6lajHDK8jJAM4"
does not appear.
Key 3
label: "admin@other-imac (RSA)"
hash: "SHA256:LJ1DTCnQ6UAoXhmF3+4RqEbzCwiS+rZ3P692a8c/nNE"
does not appear.
Key 4
label: "[email protected] (RSA)"
hash: "SHA256:cTQi5zMvfYegFAzffkWngraE8B1lJCagOxrS+TkwSaA"
appears:
4 time(s) in /var/log/auth.log.1
Key 5
label: "[email protected] (ed25519) (ED25519)"
hash: "SHA256:sPvGf5/+N3OkYlS3JV53esv2ASn+GDusMSbStaHkmik"
appears:
1 time(s) in /var/log/auth.log
Key 6
label: "[email protected] (RSA)"
hash: "SHA256:58sSa6I24R+bsRgCMJ3v2Xog1G5bP7tP9o8V8dbVtec"
does not appear.
这些密钥中的大多数最近都没有使用过。密钥 5 今天使用了一次,密钥 4 昨天使用了 4 次,假设每日日志轮换为/var/log/auth-log
。
由于我们需要sudo
权限来读取,/var/log/auth.log*
我们不妨看看该/root/.ssh/authorized_keys
文件被引用的频率:
$ sudo ./test.sh /root/.ssh/authorized_keys
8 keys found in "/root/.ssh/authorized_keys".
Here are their comment tags and key types:
1 ... root@backup-host (RSA)
2 ... ansible key (RSA)
3 ... jim@jimsdesk (RSA)
4 ... root@w541 (RSA)
5 ... root@thumb (RSA)
6 ... nagios@nagios-host (RSA)
7 ... root@mrtg-host (RSA)
8 ... jim@w541 (RSA)
Key 1
label: "root@backup-host (RSA)"
hash: "SHA256:iHsBJAi3nZt3op/kuJLQShZg+hF94gBQi8mFBTa4gLI"
appears:
1 time(s) in /var/log/auth.log
Key 2
label: "ansible key (RSA)"
hash: "SHA256:eedHBecrrsd8ESf4Ggl8S7my/p9YIhU77cvh/GrRxNY"
does not appear.
Key 3
label: "jim@jimsdesk (RSA)"
hash: "SHA256:cTQi5zMvfYegFAzffkWngraE8B1lJCagOxrS+TkwSaA"
appears:
4 time(s) in /var/log/auth.log.1
Key 4
label: "root@w541 (RSA)"
hash: "SHA256:YmiLC7LFQ+mSE3SHkXzbpFuWi0HbIpGCaIUYuR6rAiM"
does not appear.
Key 5
label: "root@thumb (RSA)"
hash: "SHA256:Db+9kBzpOKy1DlOGYQB60njQ4uXVHBAl1pgBQ0+E0pg"
does not appear.
Key 6
label: "nagios@nagios-host (RSA)"
hash: "SHA256:dQWTtyWfp0eRyj1/6PHTLOKGOzS0hlktfd9Rqpg6vng"
appears:
574 time(s) in /var/log/auth.log
1650 time(s) in /var/log/auth.log.0
1650 time(s) in /var/log/auth.log.1
1650 time(s) in /var/log/auth.log.2
1650 time(s) in /var/log/auth.log.3
1650 time(s) in /var/log/auth.log.4
1650 time(s) in /var/log/auth.log.5
1650 time(s) in /var/log/auth.log.6
Key 7
label: "root@mrtg-host (RSA)"
hash: "SHA256:XLH0tz28SacSrur0pAfE2TB7mU37cm2BEH9IB/D+dew"
does not appear.
Key 8
label: "jim@w541 (RSA)"
hash: "SHA256:CvsACdXgliEpeQtUriFW87vpMZEbO6V7znj/3bhmPwo"
does not appear.