Perl CGI脚本SSH远程机器失败:权限与密钥问题排查
排查RHEL7下Perl CGI执行SSH命令失败的问题
这种问题我碰到过好几次,核心原因其实是Apache CGI进程的运行环境和你手动用noc用户登录后的交互式shell完全不一样——哪怕都是同一个用户身份,上下文差异也会导致各种权限、路径相关的问题。结合你提到的日志错误,咱们一步步拆解排查:
1. 优先检查CGI进程的环境变量
Apache的CGI进程不会继承noc用户交互式shell的环境变量,最关键的就是HOME路径:
- 如果
HOME没有被正确设置为/home/noc,SSH会在错误的目录下找.ssh文件夹(比如Apache的默认home目录,甚至空路径),自然会出现无法访问known_hosts和私钥的错误。 - 排查方法:在你的Perl CGI脚本开头添加一段代码,打印当前环境变量:
运行脚本后看print "Content-Type: text/plain\n\n"; foreach my $key (sort keys %ENV) { print "$key = $ENV{$key}\n"; }HOME的值是不是/home/noc。如果不是,在执行SSH命令前手动设置:$ENV{HOME} = '/home/noc'; # 然后再执行SSH命令 my $output = qx(ssh -i /home/noc/.ssh/noc_offshore_key 10.208.9.88 /tmp/jetty_change.sh 2>&1);
2. SELinux限制(RHEL7默认开启,大概率是这个原因)
RHEL7默认强制开启SELinux,哪怕文件权限完全正确,SELinux的安全上下文也会阻止Apache进程访问用户的.ssh目录:
- 快速验证:临时关闭SELinux测试(执行
setenforce 0),然后重新运行CGI脚本。如果命令能正常执行,就确定是SELinux的问题。 - 永久修复:不要直接关闭SELinux,而是调整策略:
- 允许Apache发起网络连接(SSH需要网络):
setsebool -P httpd_can_network_connect 1 - 允许Apache读取用户home目录下的内容:
setsebool -P httpd_read_user_content 1 - 调整
.ssh目录的SELinux上下文,让Apache能访问:chcon -R -t httpd_user_content_t /home/noc/.ssh/
- 允许Apache发起网络连接(SSH需要网络):
3. 明确指定SSH私钥路径
手动执行时你可能已经通过ssh-agent或者默认配置指定了私钥,但CGI环境里没有这些配置,所以必须在SSH命令里明确指定私钥文件:
ssh -i /home/noc/.ssh/noc_offshore_key 10.208.9.88 /tmp/jetty_change.sh
确保在Perl脚本里的SSH命令包含-i参数和完整的私钥路径,避免依赖默认的id_rsa等文件名。
4. 确认known_hosts的状态
日志提到无法删除known_hosts,可能是因为CGI进程第一次连接目标主机时,需要添加主机指纹到known_hosts,但:
- 如果
known_hosts文件是只读权限(比如chmod 400),noc用户虽然能读但不能写,就会报错。手动执行时你可能已经添加过指纹,所以不会触发这个问题。 - 解决方法:确保
/home/noc/.ssh/known_hosts的权限是600(noc用户可读写),或者提前把目标主机的指纹添加到known_hosts里(测试时可临时用-o StrictHostKeyChecking=no,不推荐生产环境)。
最后再做一次验证
在CGI脚本里先执行几个基础命令,确认目录和文件的访问权限:
my $ssh_dir_check = qx(ls -ld /home/noc/.ssh/ 2>&1); my $key_check = qx(ls -l /home/noc/.ssh/noc_offshore_key 2>&1); print "SSH dir check: $ssh_dir_check\n"; print "Key check: $key_check\n";
这样能快速确认CGI进程是否能正常访问这些资源。
内容的提问来源于stack exchange,提问作者Prateek
相关产品推荐
相关产品推荐

