linux下升级openssh
2013-11-05 15:21:52 阿炯

主要是在centos5上的openssh是4.3p2版本的,有密钥泄露的问题,因此打算将其升级到6.x版本。针对有centos5、6及debian7平台,在同发行厂商的不同版本上打出的包不能正常安装。如果想要提高ssh文件传输性能,可以另外打一个补丁-hpn-sshDragonFly BSD的最新版本就打有此补丁。

[CentOS]
编译过程如下,安装包开发工具:
yum install -y rpm-build

Install packages necessary for building openssh
yum install -y gcc openssl-devel pam-devel

Download openssh sources
wget http://mirror.aarnet.edu.au/pub/OpenBSD/OpenSSH/portable/openssh-6.2p2.tar.gz
wget http://mirror.aarnet.edu.au/pub/OpenBSD/OpenSSH/portable/openssh-6.2p2.tar.gz.asc

wget http://mirror.aarnet.edu.au/pub/OpenBSD/OpenSSH/portable/DJM-GPG-KEY.asc
gpg --import DJM-GPG-KEY.asc
gpg openssh-6.2p2.tar.gz.asc

Copy info to redhat build tree
cp openssh-6.2p2.tar.gz /usr/src/redhat/SOURCES/
tar -xzvf openssh-6.2p2.tar.gz
cp openssh-6.2p2/contrib/redhat/openssh.spec /usr/src/redhat/SPECS/

Remove the X11 and Gnome stuff (since we are building for a server) from the spec file
vi /usr/src/redhat/SPECS/openssh.spec
 %define no_x11_askpass 0
 %define no_gnome_askpass 0
 
或者用perl来修改spec文件
perl -i.bak -pe 's/^(%define no_(gnome|x11)_askpass)\s+0$/$1 1/' openssh.spec

开始建包
rpmbuild -bb /usr/src/redhat/SPECS/openssh.spec

cd /usr/src/redhat/RPMS/`uname -i`
ls -l
-rw-r--r-- 1 root root 275808 Feb 27 08:08 openssh-6.2p2-1.x86_64.rpm
-rw-r--r-- 1 root root 439875 Feb 27 08:08 openssh-clients-6.2p2-1.x86_64.rpm
-rw-r--r-- 1 root root 277714 Feb 27 08:08 openssh-server-6.2p2-1.x86_64.rpm

rpm -Uvh openssh*rpm

service sshd reload|restart

查看ssh客户端的版本
ssh --version

关于升级后用户不能登录的问题,可以参考文章后面解决办法。

[Debian]
从临近的源站上下载对应包
wget http://mirrors.163.com/debian/pool/main/o/openssh/openssh_6.2p2-6.dsc
wget http://mirrors.163.com/debian/pool/main/o/openssh/openssh_6.2p2-6.debian.tar.gz
wget http://mirrors.163.com/debian/pool/main/o/openssh/openssh_6.2p2.orig.tar.gz

将openssh_6.2p2.orig.tar.gz包将压,后将openssh_6.2p2-6.debian.tar.gz解压出来的'debian'目录移动到'openssh-6.2p2'目录下。'.dsc'文件是不需要的,打包需要使用'dpkg-buildpackage'指令来实现。

dpkg-checkbuilddeps: Unmet build dependencies: libwrap0-dev | libwrap-dev libssl-dev (>= 0.9.8g) libpam0g-dev | libpam-dev libgtk2.0-dev libedit-dev libselinux1-dev libkrb5-dev | heimdal-dev libck-connector-dev dh-autoreconf autotools-dev

安装相关依赖软件包

apt-get install libwrap0-dev libwrap0-dev libssl-dev libpam0g-dev libgtk2.0-dev libedit-dev libselinux1-dev heimdal-dev libck-connector-dev dh-autoreconf autotools-dev libwrap-dev libpam-dev

进入'openssh-6.2p2'目录,执行指令:dpkg-buildpackage,编译完成后会在上级目录生成对应的软件包。

openssh-client_6.2p2-6_amd64.deb
openssh-server_6.2p2-6_amd64.deb
ssh_6.2p2-6_all.deb
ssh-krb5_6.2p2-6_all.deb
ssh-askpass-gnome_6.2p2-6_amd64.deb
openssh-client-udeb_6.2p2-6_amd64.udeb
openssh-server-udeb_6.2p2-6_amd64.udeb

# dpkg -i *.deb
(正在读取数据库 ... 系统当前共安装有 54620 个文件和目录。)
正预备替换 openssh-client 1:6.2p2-6 (使用 openssh-client_6.2p2-6_amd64.deb) ...
正在解压缩将用于更替的包文件 openssh-client ...
正预备替换 openssh-server 1:6.2p2-6 (使用 openssh-server_6.2p2-6_amd64.deb) ...
正在解压缩将用于更替的包文件 openssh-server ...
Selecting previously unselected package ssh.
正在解压缩 ssh (从 ssh_6.2p2-6_all.deb) ...
Selecting previously unselected package ssh-askpass-gnome.
正在解压缩 ssh-askpass-gnome (从 ssh-askpass-gnome_6.2p2-6_amd64.deb) ...
Selecting previously unselected package ssh-krb5.
正在解压缩 ssh-krb5 (从 ssh-krb5_6.2p2-6_all.deb) ...
正在设置 openssh-client (1:6.2p2-6) ...
正在处理用于 man-db 的触发器...
正在设置 ssh-askpass-gnome (1:6.2p2-6) ...
正在设置 openssh-server (1:6.2p2-6) ...
[ ok ] Restarting OpenBSD Secure Shell server: sshd.
正在设置 ssh (1:6.2p2-6) ...
正在设置 ssh-krb5 (1:6.2p2-6) ...
[ ok ] Restarting OpenBSD Secure Shell server: sshd.

视情况可能要安装'heimdal-dev'包,
dpkg: dependency problems prevent configuration of ssh-askpass-gnome:
 ssh-askpass-gnome 依赖于 libglib2.0-0 (>= 2.12.0);然而:
  未安装软件包 libglib2.0-0。
 ssh-askpass-gnome 依赖于 libgtk2.0-0 (>= 2.8.0);然而:
  未安装软件包 libgtk2.0-0。

dpkg: error processing ssh-askpass-gnome (--install):
 依赖关系问题 - 仍未被配置
正在处理用于 man-db 的触发器...
正在设置 openssh-server (1:6.2p2-6) ...
Creating SSH2 RSA key; this may take some time ...
Creating SSH2 DSA key; this may take some time ...
Creating SSH2 ECDSA key; this may take some time ...
[ ok ] Starting OpenBSD Secure Shell server: sshd.
正在设置 ssh (1:6.2p2-6) ...
正在设置 ssh-krb5 (1:6.2p2-6) ...
[ ok ] Restarting OpenBSD Secure Shell server: sshd.
在处理时有错误发生:
 ssh-askpass-gnome
 
可以在安装不安装ssh-askpass-gnome包,debian下需要在安装的编译控制文件进行设置,以排除生成此类包。从源码包不能打其它的补丁,否则会造成编译打包失败。


[总结]
升级的过程总结如下:
远程关闭了openssh服务后,ssh连接依然可用,可以放心升级。甚至可以在当前连接中将openssh卸载掉,也不会中断本次连接(只要不是连接断开),但不能新建连接了。在第三方源中也有openssh的新版本,但同时会影响其它软件的依赖关系。

[centos升级后不能登录的问题]
PAM unable to dlopen(/lib64/security/pam_stack.so): /lib64/security/pam_stack.so: cannot open shared object file: No such file or directory
不能再用原来的pam.d/sshd文件了,需要新的写法,其大致内容如下:
#%PAM-1.0
auth       include      system-auth
account    required     pam_nologin.so
account    include      system-auth
password   include      system-auth
session    optional     pam_keyinit.so force revoke
session    include      system-auth
session    required     pam_loginuid.so


在CentOS 7上从源码包安装升级openssh 8.0的过程记录

需要在同版本同架构的机器编译安装好它,后将所有的安装文件做一个包(sshv8.tar),它内置了一份配置文件,侦听的端口在6543上,下载该包到各台机器上解压使用。将要升级的机器的ip写到st.ssh文件中,每行一个,并做好了ssh autologin。

安装fuser
for h in $(cat st.ssh);do echo "$h:" && ssh -p 6543 $h 'yum install psmisc -y';done

下载并解压
cd /tmp && curl -O http://172.18.xx.57/sa/sf/sshv8.tar && tar -xf sshv8.tar -C /opt
for h in $(cat st.ssh);do echo "$h:" && ssh $h 'cd /tmp && curl -O http://ip:port/sa/sf/sshv8.tar && tar -xvf sshv8.tar -C /opt';done

同步老配置文件到新目录下,只同步已有的key并修改它的权限
/usr/bin/rsync -av /etc/ssh/ /opt/ssh/etc/ --exclude=*_config && chmod go-rwx /opt/ssh/etc/ssh_host_*
for h in $(cat st.ssh);do echo "$h:" && ssh $h '/usr/bin/rsync -av /etc/ssh/ /opt/ssh/etc/ --exclude=*_config && chmod go-rwx /opt/ssh/etc/ssh_host_*';done

测试新的ssh服的配置文件
/opt/ssh/sbin/sshd -t -f /opt/ssh/etc/sshd_config
for h in $(cat st.ssh);do echo "$h:" && ssh $h '/opt/ssh/sbin/sshd -t -f /opt/ssh/etc/sshd_config';done


拉起新的sshd服务
/opt/ssh/sbin/sshd -f /opt/ssh/etc/sshd_config
for h in $(cat st.ssh);do echo "$h:" && ssh $h '/opt/ssh/sbin/sshd -f /opt/ssh/etc/sshd_config';done

加入到自启动中(至少在rc.local中)
chmod a+x /etc/rc.d/rc.local && echo "/opt/ssh/sbin/sshd -f /opt/ssh/etc/sshd_config" >> /etc/rc.d/rc.local
for h in $(cat st.ssh);do echo "$h:" && ssh $h 'chmod a+x /etc/rc.d/rc.local && echo "/opt/ssh/sbin/sshd -f /opt/ssh/etc/sshd_config" >> /etc/rc.d/rc.local';done

转移置换ssh端口:新版本的sshd侦听到22端口,老版本的换到5222端口做为备用通道。

先看一下sshd的状态(最好关闭防火墙)
for h in $(cat st.ssh);do echo "$h:" && ssh $h 'systemctl status sshd';done
for h in $(cat st.ssh);do echo "$h:" && ssh $h 'systemctl status firewalld';done

老版本转移:22->5222
sed -i "s/#Port 22/Port 5222/g" /etc/ssh/sshd_config && /usr/bin/systemctl restart sshd
for h in $(cat st.ssh);do echo "$h:" && ssh $h 'sed -i "s/#Port 22/Port 5222/g" /etc/ssh/sshd_config && /usr/bin/systemctl restart sshd';done

注意不能再用22端口连ssh了,有5222或6543可选,查看一下老版本的端口是否生效。
/usr/sbin/fuser 5222/tcp
for h in $(cat st.ssh);do echo "$h:" && ssh -p 6543 $h '/usr/sbin/fuser 5222/tcp';done

新版本转移:
6543->22
sed -i "s/Port 6543/Port 22/g" /opt/ssh/etc/sshd_config && /usr/sbin/fuser -k -SIGHUP 6543/tcp
for h in $(cat st.ssh);do echo "$h:" && ssh -p 5222 $h 'sed -i "s/Port 6543/Port 22/g" /opt/ssh/etc/sshd_config && /usr/sbin/fuser -k -SIGHUP 6543/tcp';done

查看对应的端口上是否有进程在侦听,检查22与5222是否都存在,5222是不是由系统的sshd所侦听
for h in $(cat st.ssh);do echo "$h:" && ssh $h '/usr/sbin/fuser 5222/tcp';done
for h in $(cat st.ssh);do echo "$h:" && ssh $h '/usr/sbin/fuser 22/tcp';done


都确认OK后,将5222停止并将原sshd服务从系统中移除,防止因机器重启而拉起老的ssh服务
/usr/sbin/fuser -k -SIGHUP 5222/tcp && systemctl stop sshd.service && systemctl disable sshd.service
for h in $(cat st.ssh);do echo "$h:" && ssh $h '/usr/sbin/fuser -k -SIGHUP 5222/tcp && systemctl stop sshd.service && systemctl disable sshd.service';done

至此完成。

configure时可能遇到的问题

configure: error: PAM headers not found
典型的缺少依赖包,安装之
yum install pam-devel libedit-devel -y


在有机器上报:
/var/empty must be owned by root and not group or world-writable.

这个系权限问题,将组的可写权限移除后解决此问题。


提供一个看本局域网内所有机器上指定端口的sshd的版本信息的Perl脚本(多线程)

use v5.20;
use threads;
use Data::Dumper;
use Thread::Queue;
use IO::Socket::INET;

my $q=Thread::Queue->new();
my @addres=(1..254);
my @hosts=map "10.206.xx.$_",@addres;
my ($thread_num,@workers)=(9);

#准备线程的运行
for(1..$thread_num){
 push @workers,async{
  while(defined(my $ip=$q->dequeue())){
   my $tid=threads->self->tid();
   worker($ip);
  }
 };
}

sub worker{
my $host=shift;
# create a connecting socket
my $socket = new IO::Socket::INET (PeerHost => "$host",PeerPort => '22',Proto => 'tcp',Timeout=>'1');
unless($socket){warn "cannot connect to $host by $!" && return;}
# data to send to a server
my $req = 'hi.';
my $size = $socket->send($req);

# notify server that request has been sent
# receive a response of up to 1024 characters from server
my $response = "";
$socket->recv($response, 1024);
print "$host:$response";
$socket->close();
}

$q->enqueue($_) for @hosts; # Send work
$q->end() for @workers; # Tell workers they're done.
$_->join() for @workers; # Wait for the workers to finish.



因开启SELinux导致更换端口后不能成功重启的问题排查

sshd[16592]: error: Bind to port 6543 on 0.0.0.0 failed: Permission denied.
sshd[16592]: error: Bind to port 6543 on :: failed: Permission denied.
sshd[16592]: fatal: Cannot bind any address.

查看一下selinux的状态
# sestatus
SELinux status:    enabled
SELinuxfs mount:    /selinux
Current mode:    enforcing
Mode from config file:    enforcing
Policy version:    21
Policy from config file:    targeted

要查看ssh允许的端口
# semanage port -l | grep ssh
ssh_port_t    tcp    22

允许ssh服务运行在6543端口上
# semanage port -a -t ssh_port_t -p tcp 6543

再次查看设置是还实现
# semanage port -l | grep ssh
ssh_port_t        tcp    6543, 22

再通过systemctl指令重启ssh服务会发现能正常重启了
sshd[27291]: Received signal 15; terminating.
sshd[27367]: Server listening on 0.0.0.0 port 6543.
sshd[27367]: Server listening on :: port 6543.



该文章最后由 于 2021-07-02 11:12:26 更新,目前是第 2 版。