sshd_config 似乎忽略了 AuthorizedKeysFile 指令

sshd_config 似乎忽略了 AuthorizedKeysFile 指令

我想阻止用户使用 ssh-copy-id 访问服务器

在我的 sshd_config 中我已经设置

AuthorizedKeysFile /etc/ssh/global_authorized_keys

我确认已阅读sshd -T | grep -i authorizedkey

authorizedkeysfile /etc/ssh/global_authorized_keys

我创建了一个只读文件来匹配

ls -l global_authorized_keys 
-r--r--r-- 1 root root 0 Sep 15 10:38 global_authorized_keys

问题是,当 sshd 服务重新启动后,客户端仍然可以使用

ssh-copy-id client@server
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 2 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 2

Now try logging into the machine, with:   "ssh 'client@server'"
and check to make sure that only the key(s) you wanted were added.

当我检查客户端 .ssh 目录时,我看到

ls -l authorized_keys 
-rw------- 1 client client 1312 Sep 15 10:42 authorized_key

那么看起来 sshd 忽略了 AuthorizedKeysFile 指令?

我的服务器版本是

OpenSSH_8.4p1 Debian-5+deb11u1, OpenSSL 1.1.1n  15 Mar 2022

也许还相关的是我使用 LDAP 作为用户公钥的提供者

AuthenticationMethods publickey keyboard-interactive
AuthorizedKeysCommand /usr/local/bin/ldap-ssh-keys.sh %u
AuthorizedKeysCommandUser nobody

cat /usr/local/bin/ldap-ssh-keys.sh
#!/bin/bash

ldap_server="ldaps://server.example.com"
ldap_base="dc=example,dc=com"
#log_file="/var/log/ldap-ssh-keys.log"

# Get the public key from LDAP
search_output=$(ldapsearch -x -H $ldap_server -b "$ldap_base" -LLL "(uid=$1)" -o ldif-wrap=no sshPublicKey 2>&1)
#echo "$search_output" >> "$log_file"
public_key=$(echo "$search_output" | grep sshPublicKey:: | cut -d' ' -f2- | tr -d '\r\n' | base64 -d 2>&1)
#echo "LDAP returned SSH public key: $public_key" >> "$log_file"
logger -t ldap-ssh-keys "LDAP public key search for $1 at $ldap_base on $ldap_server found: $public_key"

# Output the public key if found, or nothing if not
echo "$public_key"

除此之外,我已将个人用户授权密钥更改为指向只读的全局集的链接

lrwxrwxrwx 1 root   root    31 Sep 15 11:15 authorized_keys -> /etc/ssh/global_authorized_keys

我已经将 LDAP 脚本的更改实现为 Python,并进行了少量修改

#!/usr/bin/env python3

import argparse
import ldap
import ldap.filter
import syslog

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("username")
    args = parser.parse_args()

    # Use filter_format() to avoid LDAP filter injection
    filter_str = ldap.filter.filter_format("(&(objectClass=posixAccount)(uid=%s))",
                                           [args.username])

    conn = ldap.initialize("ldaps://ldap.example.com")
    
    try:
        conn.simple_bind_s()

        res = conn.search_s("dc=example,dc=com",
                            ldap.SCOPE_SUBTREE,
                            filter_str,
                            ["sshPublicKey"])

        if len(res) == 0:
            syslog.syslog(syslog.LOG_WARNING, f"No LDAP entry found for {args.username}")
            exit(2)
        elif len(res) > 1:
            syslog.syslog(syslog.LOG_ALERT, f"More than one LDAP entry for {args.username}")
            exit(1)

        for dn, attrs in res:
            keys = attrs.get("sshPublicKey", [])
            syslog.syslog(syslog.LOG_INFO, f"Found {len(keys)} keys for {args.username}")
            for val in keys:
                syslog.syslog(syslog.LOG_DEBUG, f"Found key: {val}")
                print(val.decode().strip())

    except ldap.LDAPError as e:
        syslog.syslog(syslog.LOG_ERR, f"LDAP error: {e}")
        exit(3)
    finally:
        conn.unbind_s()

if __name__ == "__main__":
    main()

我还有一个问题,即每个连接调用两次 LDAP 脚本

Sep 16 06:58:16 egde ldap-ssh-keys.py: Found 1 keys for jeremy
Sep 16 06:58:18 egde ldap-ssh-keys.py: Found 1 keys for jeremy
Sep 16 06:58:18 egde systemd[1]: Started Session 742 of user jeremy.
Sep 16 06:58:21 egde systemd[1]: session-742.scope: Succeeded.

答案1

问题是,当 sshd 服务重新启动后,客户端仍然可以使用ssh-copy-id

ssh-copy-id 只是一个脚本,手动在远程系统上创建文件并向其添加一行 – 它不使用任何特殊的 sshd 工具来执行此操作。(甚至没有找出要添加的正确路径,因为这sshd -T是最近才添加的)。

因此客户端可以以与客户端相同的方式使用 ssh-copy-id,vim ~/.ssh/authorized_keys而 sshd 无法对此产生任何影响。

该选项唯一改变的是 sshd 是否会该文件是否被上传或是否被完全忽略。您的用户可以随意使用 ssh-copy-id,SSH 服务器根本不会接受使用他们上传的密钥的登录。


此外,该 LDAP 脚本很糟糕。它假设只有一个密钥(“sshPublicKey”属性是多值的),并且假设 ldapsearch 将始终以 Base64 编码输出其值(它才不是,除非密钥的注释中恰好包含一些非 ASCII 文本!)。请正确执行。

#!/usr/bin/env python3
import argparse
import ldap
import ldap.filter
import syslog

parser = argparse.ArgumentParser()
parser.add_argument("username")
args = parser.parse_args()

# Use filter_format() or escape_filter_chars() to avoid LDAP filter injection
filter = ldap.filter.filter_format("(&(objectClass=posixAccount)(uid=%s))",
                                   [args.username])

conn = ldap.initialize("ldaps://ldap.example.com")
conn.simple_bind_s()
res = conn.search_s("o=Example",
                    ldap.SCOPE_SUBTREE,
                    filter,
                    ["sshPublicKey"])

if len(res) > 1:
    syslog.syslog(syslog.LOG_ALERT, f"More than one LDAP entry for {filter}")
    exit(1)

for dn, attrs in res:
    keys = attrs.get("sshPublicKey", [])
    syslog.syslog(syslog.LOG_INFO, f"Found {len(keys)} keys for {args.username}")
    for val in keys:
        syslog.syslog(syslog.LOG_DEBUG, f"Found key: {val}")
        print(val.decode().strip())

相关内容