我正在创建一个没有shell的受限用户,仅用于端口转发,我需要通过pubkey在登录时执行脚本,即使用户是通过ssh -N user@host
连接的,也不要求SSH服务器提供外壳
脚本应警告管理员对使用pubkey进行身份验证的连接,因此连接的用户不应该跳过脚本的执行(例如,通过与ssh -N
连接)。
我试着无济于事:
/etc/ssh/sshrc
设置命令。.ssh/authorized_keys
(man authorized_keys)chsh -s /sbin/myscript.sh USERNAME
)/etc/ssh/sshd_config
中的用户,例如:
Match User MYUSERNAME
ForceCommand "/sbin/myscript.sh"
当用户请求shell时,所有工作都会正常工作,但如果只记录端口转发而没有shell(ssh -N
),那么它就无法工作。
答案 0 :(得分:12)
ForceCommand选项在没有PTY的情况下运行,除非客户端请求一个。因此,您实际上没有shell以您期望的方式执行脚本。此外,OpenSSH SSHD_CONFIG(5)手册页清楚地说:
使用用户的登录shell和-c选项调用该命令。
这意味着如果您已禁用用户的登录shell,或将其设置为/bin/false
,则ForceCommand无法正常工作。假设:
然后,如果使用正确的用户名和自定义脚本的完全限定路径名正确修改了全局 sshd_config文件,则以下内容应该有效:
Match User foo
ForceCommand /path/to/script.sh
答案 1 :(得分:3)
我是OP的作者;我得出的结论是,我需要实现的只能使用SSH到日期(OpenSSH_6.9p1 Ubuntu-2, OpenSSL 1.0.2d 9 Jul 2015
),但是我找到了一个很棒的软件,它使用加密的SPA身份验证来打开SSH端口,它的新版本(到这篇文章的日期,它的GitHub主分支)具有执行命令的功能,总是用户成功授权。
FWKNOP设置iptables规则,允许在通过UDP发送的单个数据包上访问给定端口。然后在授权之后允许授权用户访问给定时间,例如30秒,在此之后关闭端口,保持连接打开。
Ubuntu存储库中当前版本(2.6.0-2.1build1)仍然不允许在成功的SPA上执行命令; (请改用GitHub的2.6.8)
在客户端计算机上:
sudo apt-get install fwknop-client
在服务器端:
sudo apt-get install fwknop-server
以下是有关如何设置客户端和服务器计算机的教程 https://help.ubuntu.com/community/SinglePacketAuthorization
然后,在设置之后,在服务器端:
/etc/default/fwknop-server
START_DAEMON="no"
更改为START_DAEMON="yes"
然后运行:
sudo service fwknop-server stop
sudo service fwknop-server start
因此,如上所述,Ubuntu存储库(2.6.0-2.1build1)中的当前版本无法在成功的SPA上执行命令。如果你需要OP的这个功能,但它将在fwknop版本(2.6.8)发布,如下所述:
https://github.com/mrash/fwknop/issues/172
因此,如果您现在需要使用它,您可以使用具有CMD_CYCLE_OPEN
选项的github branch master进行构建。
https://help.ubuntu.com/community/SinglePacketAuthorization
https://github.com/mrash/fwknop/(GitHub项目)
答案 2 :(得分:2)
如果只需要运行脚本,则可以依靠pam_exec
。
基本上,您引用了需要在/etc/pam.d/sshd
配置中运行的脚本:
session optional pam_exec.so seteuid /path/to/script.sh
经过一些测试,您可能希望将optional
更改为required
。
对于类似的请求,请参考此答案“ bash - How do I set up an email alert when a ssh login is successful? - Ask Ubuntu”。
实际上,脚本中只能使用环境变量中的有限子集:
LANGUAGE=en_US.UTF-8
PAM_USER=bitnami
PAM_RHOST=192.168.1.17
PAM_TYPE=open_session
PAM_SERVICE=sshd
PAM_TTY=ssh
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
PWD=/
如果您想从authorized_keys
获取用户信息,此脚本可能会有所帮助:
#!/bin/bash
# Get user from authorized_keys
# pam_exec_login.sh
# * [ssh - What is the SHA256 that comes on the sshd entry in auth.log? - Server Fault](https://serverfault.com/questions/888281/what-is-the-sha256-that-comes-on-the-sshd-entry-in-auth-log)
# * [bash - How to get all fingerprints for .ssh/authorized_keys(2) file - Server Fault](https://serverfault.com/questions/413231/how-to-get-all-fingerprints-for-ssh-authorized-keys2-file)
# Setup log
b=$(basename $0| cut -d. -f1)
log="/tmp/${b}.log"
function timeStamp () {
echo "$(date '+%b %d %H:%M:%S') ${HOSTNAME} $b[$$]:"
}
# Check if opening a remote session with sshd
if [ "${PAM_TYPE}" != "open_session" ] || [ $PAM_SERVICE != "sshd" ] || [ $PAM_RHOST == "::1" ]; then
exit $PAM_SUCCESS
fi
# Get info from auth.log
authLogLine=$(journalctl -u ssh.service |tail -100 |grep "sshd\[${PPID}\]" |grep "${PAM_RHOST}")
echo ${authLogLine} >> ${log}
PAM_USER_PORT=$(echo ${authLogLine}| sed -r 's/.*port (.*) ssh2.*/\1/')
PAM_USER_SHA256=$(echo ${authLogLine}| sed -r 's/.*SHA256:(.*)/\1/')
# Get details from .ssh/authorized_keys
authFile="/home/${PAM_USER}/.ssh/authorized_keys"
PAM_USER_authorized_keys=""
while read l; do
if [[ -n "$l" && "${l###}" = "$l" ]]; then
authFileSHA256=$(ssh-keygen -l -f <(echo "$l"))
if [[ "${authFileSHA256}" == *"${PAM_USER_SHA256}"* ]]; then
PAM_USER_authorized_keys=$(echo ${authFileSHA256}| cut -d" " -f3)
break
fi
fi
done < ${authFile}
if [[ -n ${PAM_USER_authorized_keys} ]]
then
echo "$(timeStamp) Local user: ${PAM_USER}, authorized_keys user: ${PAM_USER_authorized_keys}" >> ${log}
else
echo "$(timeStamp) WARNING: no matching user in authorized_keys" >> ${log}
fi
答案 3 :(得分:1)
我是OP的作者。此外,您可以实现一个简单的logwatcher,如下所述用python3编写,它保持读取文件并在行包含模式时执行命令。
logwatcher.python3
#!/usr/bin/env python3
# follow.py
#
# Follow a file like tail -f.
import sys
import os
import time
def follow(thefile):
thefile.seek(0,2)
while True:
line = thefile.readline()
if not line:
time.sleep(0.5)
continue
yield line
if __name__ == '__main__':
logfilename = sys.argv[1]
pattern_string = sys.argv[2]
command_to_execute = sys.argv[3]
print("Log filename is: {}".format(logfilename))
logfile = open(logfilename, "r")
loglines = follow(logfile)
for line in loglines:
if pattern_string in line:
os.system(command_to_execute)
chmod +x logwatcher.python3
crontab -e
然后在此处写下这一行并在此之后保存:
@reboot /home/YOURUSERNAME/logwatcher.python3 "/var/log/auth.log" "session opened for user" "/sbin/myscript.sh"
此脚本的第一个参数是要监视的日志文件,第二个参数是要在其中查找的字符串。当在文件中找到该行时,第三个参数是要执行的脚本。
最好是使用更可靠的东西来启动/重启脚本,以免崩溃。