关于云主机root无法从VNC登录处理 一、问题描述某次基线加固过程中一线反馈离开工位后返回时原root登录会话断开使用普通用户无法切到root尝试使用移动云控制台进行VNC登录但也提示登录失败报incorrect auth二、处理过程1单用户模式登录救援模式因文件不全无法处理该场景现场使用bclinux8.6Anolis 8.6系统单用户模式只需要启动时修改grub引导菜单第一项里的linux内核加载菜单在initrd前面那一行最后面直接加single后ctrlx登录即可输入root密码这时可跳过登录验证2检查root用户登录失败原因查看/var/log/secure和authpriv日志可看到如下报错3询问操作前做了什么变更发现主要操作/etc/pam.d/下文件最后锁定主要修改其下的login文件增加了如下内容其中pam_securetty.so这个PAM模块用于限制只有从指定的终端才能用于root登录。结合/etc/securetty文件完成登录终端的限制现场正式基于此修改导致VNC无法登录4综上如果使用它限制了root登录,而vnc又无法登录root账户,可以通过以下步骤进行排查检查/etc/securetty文件,看看限制的终端列表是否包含vnc会使用的虚拟终端,如vcsa等。如果不包含需要添加。检查PAM配置文件(通常在/etc/pam.d/目录下),确保与登录相关的服务如login、sshd等都包含了pam_securetty.so模块。在PAM配置文件中,尝试将pam_securetty.so模块的control标志设置为sufficient而不是required。检查Selinux策略是否存在限制,可以尝试暂时将Selinux模式切换到permissive。检查系统日志如/var/log/secure,看看具体是在什么地方禁止了root登录。尝试更新vnc相关软件包,或切换到其他vnc实现(如x11vnc)来检查问题是否出在具体实现上。如果问题仍未解决,可以尝试完全移除pam_securetty.so模块进行测试。现场检查/etc/securetty文件为空故禁止root从任何终端登录但是要综合考虑基线合规标准查看/etc/pam.d/login文件的模块类型配置查看login文件中的控制标志配置。查看是否存在auth required pam_securetty.so存在视为合规。但是又不限制移动云终端VNC登录综上在/etc/securetty文件新增tty2豁免验证VNC登录成功至此该问题解决。三、附录3.1、救援模式回顾Grub启动菜单找到linux16行修改ro为rw删除多余内容并在行尾添加内核参数rd.break(或init/bin/bash);完成后按ctrlx进入救援模式如下所示进入后执行mount-oremount,rw /sysrootchroot/sysroot#修改密码passwdroottouch/.autorelableexit#退出/reboot或init6#重启3.2、其他登录报错当/etc/pam.d/login文件中限制登录的行auth required pam securettu.so书写错误时会导致任何用户都无法登陆报上图错误修复同上文删除login文件中auth required pam securettu.so行多余内容删除/etc/securetty文件否则默认所有终端root无法登陆3.3、VNC登录VNC (Virtual Network Computing) 是OpenStack项目中的一项虚拟网络服务它又称为一个图形化桌面共享系统它基于图形接口提供了一个图形化的终端允许用户连接到远程服务器来完成管理操作实际就是将远端主机的终端界面通过网络传送给当前的用户就行当前界面就是远程主机一样因此它又被当做为一种协议被称为是一种用于远程访问虚拟机的图形化界面的协议VNC service是 OpenStack 中的实例控制台服务能让用户通过浏览器/VNC客户端就能访问到远程的虚拟机VNC连接的主要原理是将远程计算机的屏幕图像压缩成图像数据流并通过网络传输到本地计算机。本地计算机接收到图像数据流后将其解压缩并显示在本地屏幕上。同时本地计算机的输入设备(如鼠标和键盘)的操作也会被捕捉并通过网络传输到远程计算机。远程计算机接收到本地计算机的输入后将其应用于自己的系统。如下是一端Python代码配置OpenStack 虚拟机VNC的importopenstack# Create a connection to the OpenStack APIconnopenstack.connect(cloudopenstack)# Get the virtual machine by its IDvmconn.compute.find_server(vm_id)# Define the VNC settingsvnc_settings{vnc_ip:192.168.1.100,vnc_port:5900,vnc_password:password123}# Update the virtual machines metadata with the VNC settingsconn.compute.set_server_metadata(vm,**vnc_settings)在 Linux 中VNC 包括以下四个命令vncservervncviewervncpasswd和 vncconnect。VNC基本上是由两部分组成一部分是客户端的应用程序(vncviewer) 另外一部分是服务器端的应用程序( vncserver)。VNC的基本运行原理和一些Windows下的 远程控制软件类似。1、vncserver此服务程序必须在在主或遥控计算机上运行。你只能作为使用者不需要root用户身份使用此项服务。2、vncviewer本地应用程序用于远程接入运行 vncserver的计算机并显示其环境。你需要知道远程计算机的IP地址和vncserver设定的密码。3、vncpasswdvncserver的密码设置工具。vncserver服务程序没有设置密码将不能运行好习惯。如果你没有设置运行vncserver时它会提示你输入一个密码。所以一般我不会单独运行这个命令来设置密码。4、vncconnect告诉 vncserver连接到远程一个运行vncviewer的计算机的IP和端口号。这样我就可以避免给其他人一个接入的密码。5、Xvnc一个vnc“主控”程序一般来说不需要直接运行。vncserver和vncviewer实际上是Xvnc的脚本VNC连接的通信过程主要分为以下几个步骤1.建立连接:当用户在VNC客户端中输入远程计算机的IP地址和端口号后VNC客户端会请求与远程计算机建立连接。远程计算机上运行的VNC服务器会监听指定的端口等待客户端的连接请求。2.认证过程:在建立连接之后远程计算机会要求客户端进行身份认证。这是为了确保只有经过授权的用户才能远程访问远程计算机。客户端需要提供正确的认证凭证(如密码)才能通过认证过程。3.图像传输|:认证通过后VNC服务器会开始捕捉远程计算机的屏幕图像并将其压缩成图像数据流。然后VNC服务器将图像数据流通过网络传输到VNC客户端。VNC客户端接收到图像数据流后将其解压缩并显示在本地计算机的屏幕上。4.输入传输:同时VNC客户端还会捕捉本地计算机的输入设备操作如鼠标移动和键盘输入。VNC客户端将捕捉到的输入操作通过网络传输到VNC服务器。VNC服务器接收到本地计算机的输入后将其应用于远程计算机的系统。在OpenStack项目中我们通常是通过访问 HorizonOpenStack Web 界面选择对应的项目和实例。在实例详情页面中点击 “Console” 标签页。选择 “VNC Console”然后点击 “Launch Console”就可以登录 OpenStack 的被控制节点/虚拟机实例。如想关闭VNC功能时可编辑Nova配置文件/etc/nova/nova.conf完成后重启Nova服务即可配置如下[DEFAULT]vnc_enabledFalse#修改为false#重启servicenova-compute restartservicenova-consoleauth restartservicenova-novncproxy restart四、问题二无法登录直接跳过密码输入界面报Login incorrect#crond程序查看日志journalctl -u login、journalctl -u systemd-logind或 tail -f /var/log/securePAM adding faulty module: /usr/lib64/security/pam_unix.so pam unable to dlopen(uselib64/security pan unix. s0): /afs/del willisr/lib64/1ibcrypt.so.1: version XCRYPT_2.0 not found(required by /usr/lib64/security/pam_unix.so)#排查ldconfig-p|grep1ibcrypt#查看 ld.so.cache 中注册的 1ibcrypt 库的路径find/usr/lib* /usr/lib64*-namelibssl.so.102/dev/nullrpm-qf/usr/lib64/libssl.so.10rpm-qf/usr/lib64/libssl.so.1.1.1d dpkg-S/usr/lib/x86_64-linux-gnu/libssl.so.1.1#openssl内嵌版本比较#查看 libssl.so.10 的版本信息strings /usr/lib64/libssl.so.10|grep-iOpenSSL# 查看 libssl.so.1.1.1d 的版本信息strings /usr/lib64/libssl.so.1.1.1d|grep-iOpenSSL# 查看动态链接器缓存的库信息ldconfig-p|greplibssl# 查看当前 OpenSSL 的运行库路径ldd /usr/bin/openssl|greplibssl#多版本使用在 Linux 系统中同时存在多个 OpenSSL 版本时可以通过以下方案实现程序使用特定版本如 libssl.so.10而不影响系统默认的 libssl.so.1.1.1d利用 Linux 动态链接器的加载机制通过环境变量、软链接或修改程序链接路径等方式让特定程序加载指定的 OpenSSL 版本而系统其他程序继续使用默认版本。#方式一创建启动脚本脚本中指定旧版本 OpenSSL 的程序#!/bin/bash# 例如/usr/local/bin/myapp_openssl10.shexportLD_LIBRARY_PATH/usr/local/openssl-1.0.2/lib:$LD_LIBRARY_PATHexec/path/to/myapp$#之后运行程序./myapp_openssl10.sh#验证LD_LIBRARY_PATH/usr/local/openssl-1.0.2/lib ldd /path/to/myapp|greplibssl# 查看程序实际加载的 OpenSSL 库#方式二使用 rpath 编译时绑定永久方案即在编译程序时指定库搜索路径将路径硬编码到可执行文件中# 编译时添加 -rpath 参数指定库路径gcc-omyapp myapp.c -L/usr/local/openssl-1.0.2/lib\-lssl-lcrypto-Wl,-rpath,/usr/local/openssl-1.0.2/lib#验证查看编译后的 rpath 设置readelf-dmyapp|grepRUNPATH#方式三推荐方案使用 ldconfig 配置系统级共存通过合理配置动态链接器缓存实现系统级的多版本共存让不同程序自动选择正确版本# 为旧版本创建独立的 ldconfig 配置echo/usr/local/openssl-1.0.2/lib/etc/ld.so.conf.d/openssl-1.0.2.conf ldconfig#更新 ldconfig 缓存#为特定程序设置软链接创建一个包装脚本使用 LD_PRELOAD 强制加载旧版本库#!/bin/bash# 包装脚本exportLD_PRELOAD/usr/local/openssl-1.0.2/lib/libssl.so.10:/usr/local/openssl-1.0.2/lib/libcrypto.so.10exec/path/to/myapp$#方式四对于已编译的程序可以使用 patchelf 工具修改其运行时库搜索路径yuminstallpatchelf#apt-get install patchelf# 查看当前程序链接的库patchelf --print-rpath /path/to/myapp# 设置程序使用旧版本 OpenSSL 库路径patchelf --set-rpath /usr/local/openssl-1.0.2/lib /path/to/myapp# 或直接替换依赖的库名称patchelf --replace-needed libssl.so.1.1 libssl.so.10 /path/to/myapp#方式五使用 LD_PRELOAD 强制加载特定版本# 创建启动脚本exportLD_PRELOAD/usr/local/openssl-1.0.2/lib/libssl.so.10:/usr/local/openssl-1.0.2/lib/libcrypto.so.10exec/path/to/myapp$#验证ldd /path/to/myapp|greplibssl# 查看程序运行时依赖的库ldconfig-p|greplibssl# 查看动态链接器缓存的库信息LD_DEBUGlibs /path/to/myapp21|greplibssl# 查看程序是否使用了指定版本的库LD_DEBUGlibs 应用名称可以实时查看动态链接器在加载 应用时搜索和选择库的完整路径精确定位污染源strings /usr/local/openssl-1.0.2/lib/libssl.so.10|grep-iOpenSSL# 查看库文件内嵌的版本信息原因现场是因为某客户端库文件路径配置错误直接放到/etc/ld.so.conf.d/下覆盖了登录依赖的库环境读取它的应用程序依赖libssl.so.10和libcrypto.so.10 显示 not found其中libssl.so.10 对应的是 OpenSSL 1.0.x 系列libssl.so.1.1.1d 对应的是 OpenSSL 1.1.1dlibssl.so.1.1.1d 比 libssl.so.10 更新。本次问题中这是一个典型的动态链接库搜索路径污染导致系统基础服务崩溃的案例。Linux 系统通过动态链接器ld.so 来加载程序运行所需的共享库.so 文件。其搜索顺序遵循严格的优先级1、LD_PRELOAD环境变量2、二进制文件内的 RPATH/RUNPATH3、LD_LIBRARY_PATH环境变量4、/etc/ld.so.cache由 ldconfig 根据 /etc/ld.so.conf 及其目录下的 .conf 文件生成5、默认路径 /lib 和 /usr/lib当错误的库信息写入缓存 /etc/ld.so.cache如果其中包含了一个错误的路径该路径下可能不存在库文件或者存在版本不匹配的库文件就会导致链接器在后续查找时出现混乱。在本例是因为刚好影响的是openssl库和加密的libcrypto库而sshd 和 login 进程依赖 OpenSSL 库SSH 服务sshd和终端登录login进程、su命令、yum命令都依赖于 libssl.so 和 libcrypto.so 等 OpenSSL 库来进行加密通信和身份验证另外su和login 依赖的pam_unix.so 等 PAM可插拔认证模块模块这些模块的底层也可能依赖 libcrypto 库如果这些库加载失败服务就会运行异常将会出现Login incorrect或 unknown module 等错误导致即使密码正确也无法登录。另外NetworkManager、dhclient 等网络服务也依赖 OpenSSL它们的崩溃会导致网络连接中断无法获取 IP 地址进一步加剧了问题的严重性。最后请注意修改 /etc/ld.so.conf.d/ 下的配置文件后ldconfig 会生成一个全局的缓存。这个缓存一旦被错误路径污染任何依赖标准库尤其是 OpenSSL的系统服务如 sshd、login、网络服务都可能在启动时加载到错误的库导致崩溃从而引发包括终端用户无法登录在内的系统级连锁故障。尤其在涉及覆盖系统库的多版本环境配置时虽然/etc/ld.so.conf.d/openssl-1.0.2.conf 这个文件本身就是为了实现多版本隔离而创建的独立配置文件但如果 openssl-1.0.2.conf 中写入了错误的路径例如路径拼写错误、路径指向了不存在的目录或路径指向了包含错误版本库的目录ldconfig 会在缓存中记录下这个错误信息。当系统服务如 sshd、yum启动时动态链接器会优先在缓存中查找库文件很可能就会加载到错误路径下的库从而引发 symbol lookup error 等崩溃因此我们还需要关注配置文件中的内容和引用该独立库的应用配置内容方面我们需要确认1路径存在性确认要添加的库路径如 /opt/openssl-1.0.2/lib注意这里库库文件所在的绝对路径不是具体到具体库文件确实存在并且该目录下包含您期望的 .so 文件另外应避免手动编辑应使用echo /opt/openssl-1.0.2/lib | sudo tee /etc/ld.so.conf.d/openssl-1.0.2.conf这样的命令。2文件完整性确认该目录下的 libssl.so 和 libcrypto.so 等关键库文件是完整的、未被损坏的并且版本号正确。3版本正确性使用 strings 命令确认库文件的内嵌版本信息确保它确实是您需要的版本而不是一个错误的版本。4 执行 ldconfig 前进行“安全验证”使用ldconfig -vN 2/dev/null | grep /opt/openssl-1.0.2 -N不重建缓存来预览 ldconfig 将扫描的路径检查是否包含你新加的路径其中检查关键服务的库路径依赖记下依赖路径与ldconfig后的路径进行比对确认最后执行ldconfig后立即验证确认无误后再退出当前会话