jannal(无名小宝)

没有失败,只有缓慢的成功

导航

Linux之SSH

简介

  1. SSH 是 Secure Shell Protocol 的简写 (安全的壳程序协议),它可以透过数据封包加密技术,将等待传输的封包加密后再传输到网络上。是目前远程管理Linux系统的首选方式
  2. 在默认情况下,SSH 协议提供两个服务器功能
    • 类似Telnet 的远程联机使用 shell 的服务器,即是ssh
    • 类似FTP 服务的 SFTP,用于提供更安全的 FTP 服务
  3. SSH是由客户端和服务端的软件组成的。有两个不兼容的版本分别是:1.x和2.x。用SSH 2.x的客户程序是不能连接到SSH 1.x的服务程序。OpenSSH是SSH协议的具体实现,OpenSSH 2.x同时支持SSH 1.x和2.x
    • 服务端是一个守护进程(demon),他在后台运行并响应来自客户端的连接请求。服务端一般是sshd进程,提供了对远程连接的处理,一般包括公共密钥认证、密钥交换、对称密钥加密和非安全连接。
    • 客户端包含ssh程序,以及像scp(远程复制)、slogin(远程登录)、sftp(安全文件传输)等其他的应用程序
  4. 公私钥:公钥加密,私钥解密
    • 公钥 (public key):提供给远程主机进行数据加密的行为
    • 私钥 (private key):远程主机使用你的公钥加密的数据,在本地端就能够使用私钥来进行解密
  5. SSH 的协议版本有两种,V1与V2 ,其中 V2 加上了联机检测的机制, 可以避免联机期间被插入恶意的攻击码,因此比 V1 还要更加的安全。
  6. sshd是基于SSH协议开发的一款远程管理服务程序,能够提供两种安全验证的方法
    • 基于口令的验证——用账户和密码来验证登录
    • 基于密钥的验证——需要在本地生成密钥对,然后把密钥对中的公钥上传至服务器,并与服务器中的公钥进行比较;该方式相较来说更安全。
  7. sshd的安全指的是sshd传输的数据是加密的,但是sshd服务本身的安全性并不能完全保证

交互步骤

  1. ssh 服务器端与客户端的联机步骤示意图

  2. 步骤

    • 服务器建立公钥文件: 每一次启动 sshd 服务时,该服务会主动去找/etc/ssh/ssh_host 的文件,若系统刚刚安装完成时,由于没有这些公钥文件,因此 sshd 会主动去计算出这些需要的公钥文件,同时也会计算出服务器自己需要的私钥文件
    • 客户端主动联机要求: 若客户端想要联机到 ssh 服务器,则需要使用适当的客户端程序来联机,包括 ssh客户端程序
    • 服务器传送公钥文件给客户端: 接收到客户端的要求后,服务器便将第一个步骤取得的公钥文件传送给客户端使用 (此时是明码传送)
    • 客户端记录/比对服务器的公钥数据及随机计算自己的公私钥(这次的联机与下次的联机的密钥可能就会不一样): 若客户端第一次连接到此服务器,则会将服务器的公钥数据记录到客户端的**~/.ssh/known_hosts **目录。若是已经记录过该服务器的公钥数据,则客户端会去比对此次接收到的与之前的记录是否有差异。若接受此公钥数据, 则开始计算客户端自己的公私钥数据
    • 回传客户端的公钥数据到服务器端: 用户将自己的公钥传送给服务器。此时服务器:具有服务器的私钥与客户端的公钥,而客户端则是:具有服务器的公钥以及客户端自己的私钥,你会看到,在此次联机的服务器与客户端的密钥系统 (公钥+私钥) 并不一样,所以才称为非对称式密钥系统
    • 开始双向加解密:
      • 服务器到客户端:服务器传送数据时,拿用户的公钥加密后送出。客户端接收后,用自己的私钥解密;
      • 客户端到服务器:客户端传送数据时,拿服务器的公钥加密后送出。服务器接收后,用服务器的私钥解密。
  3. 如何产生新的服务器端的 ssh 公钥与服务器自己使用的成对私钥?

    由于服务器提供的公钥与自己的私钥都放置于 /etc/ssh/ssh_host* 
    $ rm /etc/ssh/ssh_host*  <==删除密钥文件
    $ systemctl restart sshd
    $ systemctl enable sshd
    $ date; ll /etc/ssh/ssh_host*
    

客户端配置

  1. ~/.ssh/known_hosts是本机记录服务器公钥的文件,当客户端远程服务器时,本机会主动的用接收到的服务器的 public key 去比对 ~/.ssh/known_hosts有无相关的公钥, 然后进行以下动作:
  • 若接收的公钥尚未记录,则询问用户是否记录。若要记录 (输入yes) 则写入本机~/.ssh/known_hosts且继续登入的后续工作;若不记录 (输入no) 则不写入该文件,并且离开登入工作
  • 若接收到的公钥已有记录,则比对记录是否相同,若相同则继续登入动作;若不相同,则出现警告信息, 且离开登入的动作。这是客户端的自我保护功能,避免你的服务器是被别人伪装的。
  1. ssh程序可以从以下途径获取配置参数

    • 命令行选项
    • 用户配置文件 (~/.ssh/config)
    • 系统配置文件 (/etc/ssh/ssh_config)
  2. ~/.ssh/config,可以通过man ssh config查看文档

    1. Host配置项标识了一个配置区段。*代表0~n个非空白字符,?代表一个非空白字符,!表示例外通配。
    $ cat /etc/ssh/ssh_config | grep '^Host'
    Host *
    
    2. GlobalKnownHostsFile:指定一个或多个全局认证主机缓存文件,用来缓存通过认证的远程主机的密钥,
    多个文件用空格分隔。默认缓存文件为:/etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2
    
    3. HostName:指定远程主机名,可以直接使用数字IP地址。如果主机名中包含%h ,则实际使用时会被命令行中的主机名替换
    
    4. IdentityFile:指定密钥认证使用的私钥文件路径。可以指定多个密钥文件,在连接的过程中会依次尝试这些密钥文件
    默认为 ~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519 或 ~/.ssh/id_rsa 中的一个。
    文件名称可以使用以下转义符:
    '%d' 本地用户目录
    '%u' 本地用户名称
    '%l' 本地主机名
    '%h' 远程主机名
    '%r' 远程用户名
    
    5. Port:指定远程主机端口号,默认为 22 
    6. User:指定登录用户名
    7. UserKnownHostsFile: 指定一个或多个用户认证主机缓存文件,用来缓存通过认证的远程主机的密钥,多个文件用空格分隔。
    默认缓存文件为: ~/.ssh/known_hosts, ~/.ssh/known_hosts2.
    
    config文件示例
    #github
    Host github.com 									
    HostName github.com					
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/github_rsa
    #gitee
    Host gitee.com
    HostName gitee.com
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/gitee_rsa
    

配置多路复用

  1. 当远程部署使用SSH协议部署服务时,比如Ansible运行一个 playbook,它会创建许多SSH连接,用于传输文件或者运行命令等。Ansible每一次与服务器创建一条新SSH连接,都必须走一遍这样的协议交互。

  2. OpenSSH支持一项优化,叫作SSH 多路复用(SSH multiplexing),有时候也叫作长连接保持(ControlPersist)。当你使用SSH多路复用连接同一个服务器的SSH会话时将会共享同一条TCP连接,这样消耗在TCP建立连接的时间就只会发生在第一次连接的时候。

  3. 启用了多路复用后

    • 首次SSH到服务器时,OpenSSH将启动主连接;
    • OpenSSH创建一个UNIX 套接字(控制套接字,Control socket)维持与远程服务器的连接;
    • 当下一次SSH到服务器时,OpenSSH将会使用已建立的控制套接字与服务器通信,而不再是重新建立新的TCP连接
  4. 配置多路复用

    $ vim ~/.ssh/config
    Host *
        ControlMaster auto
        ControlPath ~/.ssh/%r@%h:%p.socket
        ControlPersist 10m    
    
  5. 配置说明

    • Host -连接名称
    • ControlMaster- 支持通过单个网络连接共享多个会话。设置为auto时,SSH将尝试使用主连接,但如果不存在,将回退到新连接。
    • ControlPath- 用于共享共享的控制unix套接字的路径。变量是:%r远程用户名,%h远程主机和%p远程端口。
    • ControlPersist- 保持时间,10m告诉SSH,如果超过10分钟都没有其它的SSH连接建立则关掉这个连接。
  6. 检查是否建立了主连接

    $ ssh -O check -p 22222 192.168.6.88
    如果返回表示主进程正在运行
    Master running (pid=27543) 
    如果返回表示没有运行
    Control socket connect(/root/.ssh/root@192.168.6.88:22222.socket): No such file or directory
    
    主动强制关闭
    $ ssh -O exit -p 22222 192.168.6.88
    
    正常连接时延测试
    $ time ssh -p 22222 192.168.6.88  /bin/true
    real    0m0.004s
    user    0m0.001s
    sys     0m0.001s
    

服务端配置

  1. 所有的 sshd 服务器详细设定都放在/etc/ssh/sshd_config

    # 默认端口是22,可以使用多个Port,多增加一行即可
    # Port 22
    
    # SSH 协议版本,1或者2。如果想要支持旧版本V1,使用Protocol 2,1
    Protocol 2
    
    # 默认监听所有网卡,即有监听所有IP地址
    # ListenAddress 0.0.0.0
    
    # 默认的pid文件
    # PidFile /var/run/sshd.pid
    
    # 在输入密码的画面中多久时间内没有成功连上SSH server就强迫断线。无单位则默认时间为秒
    # LoginGraceTime 2m
    
    # 指定何时开始使用压缩数据模式进行传输(yes,no,delayed登入后才将数据压缩)
    # Compression delayed
    
    # Server服务器的 Private Key 放置的文件,预设使用下面的文件即可
    HostKey /etc/ssh/ssh_host_key        # SSH version 1 使用的私钥
    HostKey /etc/ssh/ssh_host_rsa_key    # SSH version 2 使用的 RSA 私钥
    HostKey /etc/ssh/ssh_host_dsa_key    # SSH version 2 使用的 DSA 私钥
    
    # 使用 SSH 登入系统的时候,SSH 会记录信息。可用的 daemon name 为:DAEMON,USER,AUTH,
    # LOCAL0,LOCAL1,LOCAL2,LOCAL3,LOCAL4,LOCAL5,
    SyslogFacility AUTHPRIV
    
    # 登录记录的等级
    # LogLevel INFO
    
    # 是否允许 root 登入
    # PermitRootLogin yes
    
    #最大密码尝试次数
    #MaxAuthTries 6
    
    # 是否让 sshd 去检查用户家目录或相关档案的权限数据
    # StrictModes yes
    
    # 是否允许用户自行使用成对的密钥系统进行登入行为,仅针对 version 2
    # 至于自制的公钥数据就放置于用户家目录下的 .ssh/authorized_keys 内
    # PubkeyAuthentication yes
    # AuthorizedKeysFile      .ssh/authorized_keys
    
    # 密码验证
    PasswordAuthentication yes
    
    # 是否允许以空的密码登入
    # PermitEmptyPasswords no
    
    # 本机系统不使用 .rhosts,.rhosts太不安全
    # RhostsAuthentication no
    
    # # 是否取消使用 ~/.ssh/.rhosts 来做为认证
    # IgnoreRhosts yes
    
    # 这个选项是专门给 version 1 用的,使用 rhosts 档案在 /etc/hosts.equiv
    # RhostsRSAAuthentication no 
    
    # 专门给version 2 使用的
    # HostbasedAuthentication no
    
    # 是否忽略家目录内的 ~/.ssh/known_hosts 这个文件所记录的主机内容
    # IgnoreUserKnownHosts no
    
    # 允许任何的密码认证
    ChallengeResponseAuthentication no
    
    # 利用 PAM 管理使用者认证有很多好处,可以记录与管理
    UsePAM yes
     
    # Kerberos 有关的参数设定
    # KerberosAuthentication no
    # KerberosOrLocalPasswd yes
    # KerberosTicketCleanup yes
    # KerberosTgtPassing no
     
    # 在 X-Window 底下使用的相关设定!
    X11Forwarding yes
    # X11DisplayOffset 10
    # X11UseLocalhost yes
    
    
    # 登入后是否显示出一些信息,打印出 /etc/motd 这个档案的内容
    # PrintMotd yes
    
    # 显示上次登入的信息
    # PrintLastLog yes
    
    # 服务器会一直传送 TCP 封包给客户端以判断对方式否一直存在联机
    # TCPKeepAlive yes
    
    UsePrivilegeSeparation yes
    MaxStartups 10
    
    # 设定受抵挡的使用者名称
    DenyUsers *
    # 拒绝部分使用者名称
    DenyUsers test
    # 拒绝群组名称
    DenyGroups test
    
    Subsystem       sftp    /usr/lib/ssh/sftp-server
    # UseDNS yes
    
  2. 检查配置文件的有效性和密匙的完整性

    $ sudo sshd -t
    扩展测试模式
    $ sudo sshd -T
    

安全性配置

  1. 考虑 ssh 客户端向后兼容性的时候,请使用 RSA密匙代替 ECDSA 密匙。所有的 ssh 密钥要么使用 ED25519 要么使用 RSA,不要使用其它类型
$ ssh-keygen -t ed25519 -C "Login to production cluster at xyz corp"
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_aws_$(date +%Y-%m-%d) -C "AWS key for abc corp clients"
  1. 禁用 root 用户登录

    1. 禁用 root 用户登录前,确认普通用户可以以 root 身份登录
    1.1 Debian/Ubuntu系统操作方式(允许 sudo 组中的用户执行任何命令)
    $ sudo adduser jannal
    $ id jannal 验证用户组
    
    1.2 CentOS/RHEL 和 Fedora系统操作方式(允许 wheel 组中的用户执行所有的命令)
    $ sudo adduser jannal
    $ sudo passwd jannal
    $ sudo usermod -aG wheel jannal
    $ id jannal
    
    1.3 测试并确保用户 jannal可以以 root 身份登录执行以下命令:
    $ sudo -i
    $ sudo systemctl status sshd
    
    2. 添加以下内容到 sshd_config 文件中来禁用 root 登录
    PermitRootLogin no
    ChallengeResponseAuthentication no
    PasswordAuthentication no
    UsePAM no
    
  2. 禁用密码登录,仅留下公匙登录

    AuthenticationMethods publickey
    PubkeyAuthentication yes
    CentOS 6.x/RHEL 6.x 系统中老版本的 sshd 用户可以使用以下设置
    PubkeyAuthentication yes
    
    禁止空密码
    PermitEmptyPasswords no
    
  3. sshd 只想让部分主机来源能够登入

    $ vim  /etc/hosts.allow
    sshd: 127.0.0.1 192.168.1.0/255.255.255.0 192.168.100.0/255.255.255.0
    $ vim /etc/hosts.allow
    sshd : ALL 
    
    使用防火墙也可以达到效果
    $ vim /usr/local/virus/iptables/iptables.allow
    iptables -A INPUT -i $EXTIF -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT
    iptables -A INPUT -i $EXTIF -s 192.168.100.0/24 -p tcp --dport 22 -j ACCEPT
    
  4. sshd强化配置,可以采取的策略

    • 禁止 root 这个账号使用 sshd 的服务

    • 禁止 nossh(自定义群组) 这个群组的用户使用 sshd 的服务

    • 禁止 testssh(某个用户) 这个用户使用 sshd 的服务

      $ vim /etc/ssh/sshd_config
      ...省略...
      PermitRootLogin no  修改为no
      
      在文件末尾添加这两行
      DenyGroups  nossh  
      DenyUsers   testssh
      ...省略...
      
      查看日志
      $ tail /var/log/secure
      

SSH命令

  1. 查看sshd是否运行

    $ ps -waux | grep sshd
    
  2. 客户端生成公私钥

    1. rsa是默认算法
    $ ssh-keygen -t rsa -f ~/.ssh/sync_rsa 
    或者
    $ ssh-keygen -t dsa -f ~/.ssh/sync_dsa
    
  3. 拷贝客户端公钥给目标服务器方式一(推荐)

    1. 使用默认的22端口 
    $ ssh-copy-id -i ~/.ssh/sync_rsa.pub root@192.168.100.140
    非22端口
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub ssh://root@192.168.100.140:22222
    
    2. 连接特定端口12222
    $ ssh-copy-id -i id_dsa.pub –p 12222 root@192.168.100.140
    
    4. 查看服务器是否生成authorized_keys 
    $ ll ~/.ssh/authorized_keys 
    -rw------- 1 root root 575 Oct  4 02:48 /root/.ssh/authorized_keys
    
    3. 查看是否配置成功
    $ ssh -i ~/.ssh/sync_rsa -p 12222 root@192.168.100.140 
    
  4. 拷贝客户端公钥给目标服务器方式二

    1. 复制客户端的公钥到服务器上
    $ scp ~/.ssh/id_rsa.pub root@192.168.100.140:~
    
    2. 在服务器上将客户端公钥内的数据转存到 authorized_keys,权限必须是644
    $ cat id_rsa.pub >> .ssh/authorized_keys
    $ chmod 644 .ssh/authorized_keys
    
  5. 格式:ssh [-f] [-o 参数项目] [-p 端口] [账号@]IP [指令]

    选项与参数:
    -f :与最后的[指令]配合 ,不登入远程主机,而是直接发送一个指令执行
    -o 参数项目:主要的参数项目有:
    	ConnectTimeout=秒数 :联机等待的秒数,减少等待的时间
    	StrictHostKeyChecking=[yes|no|ask]:预设是 ask,若要让 public key
      主动加入 known_hosts ,则可以设定为 no 即可。
    -p :如果sshd服务在非22端口,需使用此项目
    [指令] :不登入远程主机,直接发送指令过去。但与 -f 意义不太相同。
    
    1. 登入远程主机并执行命令,一直阻塞直到完成,最后离开
    $ ssh root@192.168.100.140 find / & > 1.log
    
    2. 登入远程主机并执行命令,然后立刻离开,服务器自己去执行命令
    $ ssh -f root@192.168.100.140 find / & > 1.log
    
    3. 不会有yes或者no提示,直接会写入 ~/.ssh/known_hosts 
    $ ssh -o StrictHostKeyChecking=no root@192.168.100.140
    
  6. 批量获取机器 SSH 公钥,再用ssh登录到已经获取过公钥的服务器时,不需要再输入yes。

    $ ssh-keyscan --help
    usage: ssh-keyscan [-46cHv] [-f file] [-p port] [-T timeout] [-t type]
                       [host | addrlist namelist]
    -f 指定一个文件,包含若干需要扫描的机器列表。-f - 表示从标准输入读取机器列表
    -p 指定连接远端 server 时的端口号;
    -T 指定超时时间;
    -t 则选择需要获取哪些类型的公钥指纹。
    
    直接获取github的公钥
    $ ssh-keyscan github.com
    
    2. 通过文件获取,新建一个host_list.txt
    github.com
    gitlab.com
    192.168.101.8
    
    $ ssh-keyscan -f host_list.txt
    将标准错误的输出重定向到 /dev/null 即可获得机器列表的公钥指纹
    $ ssh-keyscan -f hostlist.txt 1>>~/.ssh/known_hosts 2>/dev/null
    
    将 ~/.ssh/known_hosts 用 scp 拷贝到 host_list.txt中的所有机器上即可
    

SCP命令

  1. 复制

    $ scp [-pr] [-l 速率] file  [账号@]主机:目录名 <==上传
    $ scp [-pr] [-l 速率] [账号@]主机:file  目录名 <==下载
    选项与参数:
    -v :显示详细的连接进度
    -p :保留原本档案的权限数据;
    -r :复制来源为目录时,可以复制整个目录 (含子目录)
    -l :可以限制传输的速度,单位为 bit/s ,例如 [-l 800] 代表传输速限 100Kbytes/s
    

不间断会话服务

  1. sshd服务,当与远程主机的会话被关闭时,在远程主机上运行的命令也随之被中断。比如正在使用脚本安装某个服务程序,中途是绝对不能关闭在本地打开的终端窗口或断开网络链接的,甚至是网速的波动都有可能导致任务中断,此时只能重新进行远程链接并重新开始任务

  2. screen是一款能够实现多窗口远程控制的开源服务程序,就是为了解决网络异常中断或为了同时控制多个远程终端窗口而设计的程序

    • 会话恢复:即便网络中断,也可让会话随时恢复,确保用户不会失去对远程会话的控制。
    • 多窗口:每个会话都是独立运行的,拥有各自独立的输入输出终端窗口,终端窗口内显示过的信息也将被分开隔离保存,以便下次使用时依然能看到之前的操作记录。
    • 会话共享:当多个用户同时登录到远程服务器时,便可以使用会话共享功能让用户之间的输入输出信息共享。
  3. screen安装

    $ yum install screen -y
    $ screen --help
    $ screen -S <session name>
    $ exit 退出
    
  4. 常用参数

    • -S参数创建会话窗口;
    • -d参数将指定会话进行离线处理
    • -r参数回复指定会话
    • -x参数一次性恢复所有的会话
    • -ls参数显示当前已有的会话
    • -wipe参数把目前无法使用的会话删除
  5. 实战演示

    1. 在一个SSH会话窗口执行
    1.1. 创建一个logview会话窗口(屏幕会闪烁一下)
    $ screen -S logview
    
    1.2. 查看是否生效
    $ screen -ls
    There is a screen on:
            46150.logview   (Attached)
    1 Socket in /var/run/screen/S-root.
    
    1.3. 执行命令
    $ tail -f /var/log/messages
    1.4. 关闭当前ssh会话窗口
    
    2. 在一个新的SSH会话窗口执行
    $ screen -ls
    2.1 恢复会话
    $ screen -r logview
    
  6. 会话共享功能,当多个用户同时控制主机的时候,它可以把屏幕内容共享出来,也就是说每个用户都可以看到相同的内容。

排查问题

  1. 无法连接时,排查一下
    • 是否能ping通
    • 是否能telnet通22端口
    • 查看防火墙是否开启
    • 打开ssh的调测进行观察:ssh -vvv root@192.168.100.140
    • /.ssh/**目录权限必须是700。**/.ssh/authorized_keys权限必须是644。私钥文件(~/.ssh/id_rsa)必须是600
    • 连接的服务器的公钥和本地的known_hosts文件中的不匹配。删除known_hosts对应IP的公钥信息,重新发起连接

posted on 2021-12-26 11:34  jannal  阅读(164)  评论(0编辑  收藏  举报