Ubuntu-OpenSSH升级过程

目录

  • 升级前准备
  • 手动升级流程
  • 遇到问题及解决

升级前准备

查看待升级机器的系统版本及OpenSSH 和其依赖的 OpenSSL,ZLib的版本

  • ubuntu-16.04
    • OpenSSH_7.2p2 Ubuntu-4ubuntu2.8, OpenSSL 1.0.2g 1 Mar 2016
1
2
3
4
5
root@openstack-backupagent-zw-sjzt2:~# apt-get install -s zlib1g
Reading package lists... Done
Building dependency tree
Reading state information... Done
zlib1g is already the newest version (1:1.2.8.dfsg-2ubuntu4.3).

手动升级流程

对于可以连接互联网的Ubuntu机器,比较方便。对于不能连接互联网的机器,需要考虑到下载依赖包。

重点说一下离线安装过程(不能连接互联网)

1. 离线安装编译openssh源码需要编译环境

一,下面步骤在一台有网的相同版本的服务器上进行操作

  1. 查询有哪些软件包;

    1
    apt-cache search xxx(要搜索的包名)
  2. 然后对xxx执行安装或仅下载不安装操作

    1
    2
    3
    apt-get install xxx     # 下载并安装 xxx 包
    apt-get -d install xxx # 仅下载xxx到缓存位置,不安装
    # 缓存的文件在 /var/cache/apt/archives 目录下
  3. 生成依赖关系,

    • 到上一步骤缓存的目录下将安装 xxx 所涉及的包 copy 到指定目录下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mkdir /root/offline_gcc_packages
    cp -r /var/cache/apt/archives /root/offline_gcc_packages
    chmod 777 -R /root/offline_gcc_packages
    # 建立 deb 包的依赖关系
    apt-get install dpkg-dev

    # 这个步骤非常重要,后面再说
    dpkg-scanpackages archives /dev/null > root/offline_gcc_packages/Packages

    # 将生成的Packages复制到和deb同目录下
    cp /root/offline_gcc_packages/Packages root/offline_gcc_packages/archives/Packages

    # 打成压缩包,以备后用
    cd /root/
    tar zcvf offline_gcc_packages_ubuntu_right.tar.gz /root/offline_gcc_packages

二,在离线的服务器上进行安装

  1. offline_gcc_packages_ubuntu_right.tar.gz 解压

    1
    tar zxvf offline_gcc_packages_ubuntu_right.tar.gz
  2. 将安装包解压后的目录和源路径,添加到系统源 sources.list

    1
    2
    3
    4
    5
    6
    # 修改前,先备份原有文件
    cp /etc/apt/sources.list /etc/apt/sources.list.bak
    # 清空原有内容,或者注释掉
    > /etc/apt/sources.list
    # 加入下面一行内容
    deb file:///root/offline_gcc_packages xenial/
  3. 更新系统源

    1
    apt-get update

    注意,这里可能遇到一些报错,

    apt-get update —allow-insecure-repositories

    注意,本地的源是没有签名的,直接更新ubuntu1604下的apt会提示找不到release文件,是一种不安全的源,默认是被禁用的。如果还要安装的话需要加上这个 –allow-unauthenticated选项。

    apt-get update –allow-unauthenticated

  4. 离线安装 gcc

    1
    apt-get install gcc

    注意:在执行是可能会出现这样的错误 You will have to enable the component called ‘main’

    解决方法:sudo add-apt-repository main

注意事项:

上面步骤中,需要格外注意的是创建 deb 包的依赖关系与修改系统源的步骤。这两步骤是紧密关联的。

Packages 记录了archives目录下的 deb 包的依赖关系和每个deb文件其他信息,系统源根据会查询指定目录下 Packages 文件中的 Filename 找到需要的 deb 文件。Packages 文件中的Filename,如下:

1
Filename: archives/binutils_2.26.1-1ubuntu1~16.04.8_amd64.deb

系统源配置如下:

1
2
3
# 这里重点两部分内容:
# <这部分是文件的父级目录,找文件时会拼接这个路径> <这部分是操作系统版本号名称>
deb file:///root/offline_gcc_packages xenial/
1
2
3
4
5
6
7
8
9
10
Reading package lists... Done
N: Can't drop privileges for downloading as file '/root/offline_gcc_packages/xenial/InRelease' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
W: The repository 'file:/root/offline_gcc_packages xenial/ Release' does not have a Release file.
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: Failed to fetch file:/root/offline_gcc_packages/xenial/Packages File not found - /root/offline_gcc_packages/xenial/Packages (2: No such file or directory)
E: Some index files failed to download. They have been ignored, or old ones used instead.


N: Can't drop privileges for downloading as file '/root/offline_gcc_packages/archives/libmpc3_1.0.3-1_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)

方法二

依然需要一台同配置可联网的 Ubuntu16.04LTS版本系统

  1. 将后面编译OpenSSH源码需要的包下载到本地

    下载前,先进入 /var/cache/apt/archives/ 目录下,清空原有的缓存包

    1
    apt-get install -d gcc zlib1g-dev libssl-dev libpam0g-dev libsystemd-dev make
  2. 在Ubuntu官网上搜索下面两个版本的deb包

    1
    2
    3
    4
    libssl1.0.0=1.0.2g-1ubuntu4.20
    - libssl1.0.0_1.0.2g-1ubuntu4.20_amd64.deb
    libc6=2.23-0ubuntu11.3
    - libc6_2.23-0ubuntu11.3_amd64.deb
  3. 进入本地缓存目录,将步骤1中下载的包 copy 到与步骤2下载的包相同目录下,然后打包并放到离线的机器上

  4. 在离线机器上解压缓存包,并安装所有包

    1
    dpkg -i *

2. 离线升级OpenSSH

  1. 下载 openssh-8.8p1 源码,解压

    1
    2
    tar zxvf openssh-8.8p1.tar.gz
    cd openssh-8.8p1/
  2. 配置安装路径,并生成makefile文件

    1
    ./configure --prefix=/usr --sysconfdir=/etc/ssh --with-md5-passwords --with-pam --with-zlib --with-privsep-path=/var/lib/sshd

    没有报错,且看到类似如下内容,表示执行成功

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ......
    Preprocessor flags: -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE
    Linker flags: -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -fstack-protector-strong -pie
    Libraries: -lcrypto -ldl -lutil -lz -lcrypt -lresolv
    +for sshd: -lpam

    PAM is enabled. You may need to install a PAM control file
    for sshd, otherwise password authentication may fail.
    Example PAM control files can be found in the contrib/
    subdirectory
  3. 修改源码

    在源码目录下,找到 sshd.c 文件,找到调用 server_accept_loop 函数的行,(这个函数的定义也在这个文件中,找到调用位置!)。添加向systemd发送通知的行,内容如下:

    1
    2
    3
    4
    /* Signal systemd that we are ready to accept connections */
    sd_notify(0, "READY=1");
    /* Accept a connection and return in a forked child */
    server_accept_loop(&sock_in, &sock_out,&newsock, config_s);
    1. 在 第 2072 行添加 15个空格+ sd_notify(0,"READY=1");

    2. 在第 44 行 添加

    同时在源文件开头添加引用头文件:

    1
    #include <systemd/sd-daemon.h>
  4. 修改 Makefile 文件

    编译前,需要在源码目录中,找到步骤2生成的 Makefile文件,修改变量LIBS,添加对 systemd的依赖,内容如下:

    1
    LIBS=-lcrypto -ldl -lutil -lz -lcrypt -lresolv -lsystemd

    在文件的第 50 行,追加 -lsystemd

  5. 编译,安装

    1
    make && make install
  6. 修改配置文件

    安装完成后,会自动执行 sshd -t /etc/ssh/sshd_config,将提示中出现的几个弃用或不支持的参数注释掉,报错如下:

    1
    2
    3
    4
    5
    6
    /etc/ssh/sshd_config line 16: Deprecated option UsePrivilegeSeparation
    /etc/ssh/sshd_config line 19: Deprecated option KeyRegenerationInterval
    /etc/ssh/sshd_config line 20: Deprecated option ServerKeyBits
    /etc/ssh/sshd_config line 31: Deprecated option RSAAuthentication
    /etc/ssh/sshd_config line 38: Deprecated option RhostsRSAAuthentication
    /etc/ssh/sshd_config line 61: Unsupported option GSSAPIAuthentication

    sed -i -e "16s/^/#/" -e "19s/^/#/" -e "20s/^/#/" -e "31s/^/#/" -e "38s/^/#/" -e "61s/^/#/" /etc/ssh/sshd_config

  7. 重启服务

    1
    systemctl restart sshd

遇到问题及解决

离线安装依赖包的问题

2. 升级后 sshd 服务处于activating(start) 状态

在 [离线升级OpenSSH](# 2. 离线升级OpenSSH) 章节中,添加了步骤3和4,即修改源码并修改Makefile文件的内容。

这是因为如果只执行步骤1,2,5,6的情况下,在Ubuntu16.04 LTS版本中,安装重试时,会报如下错误:

1
2
root@ubuntu-test-update-openssh:/etc/ssh# systemctl restart sshd
Job for ssh.service failed because a timeout was exceeded. See "systemctl status ssh.service" and "journalctl -xe" for details.

执行 systemctl status ssh.service 查看服务状态,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: activating (start) since Sun 2022-02-06 12:54:51 UTC; 1min 18s ago
Process: 23608 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
Main PID: 23611 (sshd)
Tasks: 1
Memory: 508.0K
CPU: 21ms
CGroup: /system.slice/ssh.service
└─23611 sshd: /usr/sbin/sshd [listener] 0 of 10-100 startup

Feb 06 12:54:51 ubuntu-test-update-openssh systemd[1]: Starting OpenBSD Secure Shell server...
Feb 06 12:54:51 ubuntu-test-update-openssh sshd[23611]: Server listening on 0.0.0.0 port 22.
Feb 06 12:54:51 ubuntu-test-update-openssh sshd[23611]: Server listening on :: port 22.

如上所示,服务的状态为 Active: activating (start),尽管端口已经监听,且能正常连接,但是这种状态并不正常。即使执行 journalctl -xe 也看不到有用的信息。

查看系统日志 tail -f /var/log/syslog,会发现 ssh.server 服务在不停的重启。

原因

首先查看 sshd 服务启动文件 /lib/systemd/system/ssh.service ,部分内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
...
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecStart=/usr/sbin/sshd $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
...

这里重点看Type=notify 配置,这意味着当前服务启动完毕,会通知 systemd,再继续往下执行。

所以出现命令挂起的原因是 sshd 服务启动后,没有给 systemd 服务发消息,导致 systemd 一直等待,直到超时。这也是为什么执行 restart 命令后会报 timeout 的原因。

解决

方法1(推荐)

这种方法更可靠,减少之后使用过程中遇到其他未知问题的可能。

添加步骤3和4,即修改源码,添加通知 systemd 的内容和依赖。

同时在前面安装编译源码的依赖时,安装了libsystemd-dev 依赖包,这是因为默认的依赖中,不包含 sd_notify 这个函数,所以需要执行编译前安装依赖包。单独安装使用如下命名:

1
apt-get install libsystemd-dev

方法2

通过前面内容,我们知道服务挂起的原因是因为服务启动配置中设置了Type=notify,但是启动后并没有通知systemd导致,所以这里直接注释掉该选项,即不通知systemd,这种情况下,系统会使用默认的Type=simle配置(ExecStart 字段启动的进程为主进程)。

然后重新加载配置文件,并重启服务。

1
2
systemctl daemon-reload
systemctl restart sshd
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2023 ligongzhao
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信