• 关于Linux中批量配置SSH免密的一些笔记


    写在前面


    • 今天和小伙伴们分享批量配置SSH免密的一些笔记
    • 传统的运维场景可以通过Ansible 等运维工具处理
    • 在安装使用一些运维工具,比如Ansible,或则一些pass组件,需要配置ssh免密,sudo免密的操作
    • 今天和小伙伴分享如何批量操作
    • 博文内容比较简单,涉及
      + expect 内网外网安装
      + 通过expect来批量配置免密
    • 食用方式:
      + 需要Linux 基础知识
    • 理解不足小伙伴帮忙指正

    傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波


    expect 安装

    expect 是由Don Libes基于Tcl(Tool Command Language )语言开发的,主要应用于自动化交互式操作的场景,借助Expect处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率

    在内网环境下,无法连接yum源,我们可以找一台有网的机器,把rpm包下载下来,然后上传到内网环境

    [root@vms152 ~]# yum -y install expect --downloadonly --downloaddir=/root/soft
    ...
    [root@vms152 ~]# cd soft/;ls
    expect-5.45-14.el7_1.x86_64.rpm  tcl-8.5.13-8.el7.x86_64.rpm
    
    • 1
    • 2
    • 3
    • 4

    通过rpm -ivh 的方式来安装

    [root@vms152 soft]# rpm -ivh /root/soft/*
    准备中...                          ################################# [100%]
    正在升级/安装...
       1:tcl-1:8.5.13-8.el7               ################################# [ 50%]
       2:expect-5.45-14.el7_1             ################################# [100%]
    [root@vms152 soft]#
    [root@vms152 soft]# which expect
    /usr/bin/expect
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在可以连接yum源的情况下,我们直接通过包管理器yum来下载

    [root@vms152 soft]# yum -y install expect
    
    • 1

    expect 基础用法

    这里以root用户为例配置免密

    Expect作为一种重要的TCL扩展包,主要有以下几个命令:

    • spawn:spawn用于启动一个进程,之后所有expect操作都在这个进程中进行,类似于我们直接在命令行敲bash
    • expect:获取匹配信息匹配成功则执行expect后面的程序动作(检测由壳内进程发出的特定交互指令反馈字符串后向下执行)
    • send:用于向进程发送字符串(从壳外向壳内进程发送一条字符串,换行符为确认结束)
    • interact:允许用户交互
    • exp_continue:在expect中多次匹配就需要用到
    • send_user:用来打印输出 相当于shell中的echo
    • exit:退出expect脚本
    • eof:expect执行结束 退出
    • set:定义变量
    • puts:输出变量
    • set timeout:设置超时时间

    我们来看一个简单的Demo,命令行的方式来运行,通过SSH登录一台机器,并退出。这个交互式到的命令通过expect如何处理。

    [root@vms152 soft]# expect  <<- EOF
    > spawn ssh root@127.0.0.1
    > expect "*pass*" { send "redhat\r"}
    > expect "*connecting*" { send "yes\r"}
    > expect "#"
    > send "exit \r"
    > expect eof
    > EOF
    spawn ssh root@127.0.0.1
    root@127.0.0.1's password:
    Last login: Sat Aug 20 15:22:06 2022 from 127.0.0.1
    [root@vms152 ~]# exit
    登出
    Connection to 127.0.0.1 closed.
    [root@vms152 soft]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果是第一次登录,或者没有保存公钥,那么会有一个保存公钥的提示,我们可以这样处理,这次我们通过ctl脚本的方式

    [root@vms153 ~]# cat su.ctl
    #!/usr/bin/expect
    
    spawn ssh root@127.0.0.1
    
    expect {
           "*connecting*" { send "yes\r"}
           "*pass*" { send "redhat\r"}
           }
    
    expect {
           "#" {send "\r"}
           "*pass*" { send "redhat\r"}
           }
    expect {
           "#" {send "exit \r"}
           }
    expect eof
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    清空SHSH存放公钥的文件,给脚本授权,执行

    [root@vms153 ~]# cat /dev/null  > /root/.ssh/known_hosts
    [root@vms154 ~]# chmod +x su.ctl 
    [root@vms153 ~]# ./su.ctl
    spawn ssh root@127.0.0.1
    The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
    ECDSA key fingerprint is SHA256:rQokINjVDeZOfyKKcLlhIe92bgkN8xZ13QiPwr/0cxo.
    ECDSA key fingerprint is MD5:35:83:98:1d:76:b8:33:b0:b6:ba:d5:0f:34:2f:ba:b9.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.
    root@127.0.0.1's password:
    Last login: Sat Aug 20 17:25:03 2022 from 127.0.0.1
    [root@vms153 ~]# exit
    登出
    Connection to 127.0.0.1 closed.
    [root@vms153 ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    当然,也可以交互式的使用,下面的脚本实现通过SHH远程到一台机器,并查看主机名,然后把终端交给标准输入

    [root@vms153 ~]# cat su.ctl
    #!/usr/bin/expect
    
    spawn ssh root@192.168.26.152
    
    expect {
           "*connecting*" { send "yes\r"}
           "*pass*" { send "redhat\r"}
           }
    
    expect {
           "#" {send "\r"}
           "*pass*" { send "redhat\r"}
           }
    
    expect "#"
    
    send "hostname \r"
    expect "#"
    interact
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行脚本,我们可以直接操作SSH机器

    [root@vms153 ~]# ./su.ctl
    spawn ssh root@192.168.26.152
    root@192.168.26.152 s password:
    Last login: Sat Aug 20 17:31:07 2022 from 192.168.26.153
    [root@vms152 ~]#
    [root@vms152 ~]# hostname
    vms152.rhce.cc
    [root@vms152 ~]# ls
    anaconda-ks.cfg  calico_3_14.tar  calico.yaml  one-client-install.sh  set.sh  soft
    [root@vms152 ~]# exit
    登出
    Connection to 192.168.26.152 closed.
    [root@vms153 ~]#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    expect 配置root免密

    [root@vms152 soft]# cat host_list
    192.168.26.153
    192.168.26.154
    
    • 1
    • 2
    • 3
    [root@vms152 soft]# cat mianmi.sh
    #!/bin/bash
    
    #@File    :   mianmi.sh
    #@Time    :   2022/08/20 17:45:53
    #@Author  :   Li Ruilong
    #@Version :   1.0
    #@Desc    :   None
    #@Contact :   1224965096@qq.com
    
    
    /usr/bin/expect <<-EOF
    spawn ssh-keygen
    expect "(/root/.ssh/id_rsa)" {send "\r"}
    expect {
           "(empty for no passphrase)" {send "\r"}
           "already" {send "y\r"}
           }
    
    expect {
           "again" {send "\r"}
           "(empty for no passphrase)" {send "\r"}
           }
    
    expect {
           "again" {send "\r"}
           "#" {send "\r"}
           }
    expect "#"
    expect eof
    EOF
    
    for IP in $( cat host_list )
    do
    
    if [ -n IP ];then
    
    /usr/bin/expect <<-EOF
    spawn ssh-copy-id root@$IP
    
    expect {
           "*yes/no*"   { send "yes\r"}
           "*password*" { send "redhat\r" }
           }
    expect {
           "*password" { send "redhat\r"}
           "#"         { send "\r"}
           }
    expect "#"
    expect eof
    EOF
    fi
    
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    这里需要说明的是 expect 中有些特殊关键字用于匹配过程,代表某些特殊的含义或状态,可能会和shell 脚本中的冲突,所以一般只用于expect命令中而不能在expect命令单独使用,比如 eof,timeout等,如果密码中存在特殊字符,且在脚本里冲突,那么可以使用一些python模块来处理,比如Paramiko,fabric 等。

    博文参考

    linux expect 详解:https://blog.csdn.net/zxycyj1989/article/details/125837697

  • 相关阅读:
    第2关:子节点创建、列出、删除
    720云手机电动云台全新上市,让手机能自动拍摄亿万像素VR全景
    【c++ primer 笔记】第 16章 模板与泛型编程
    mysql XA 分布式事务
    Win10安装Maven与环境变量配置
    深入理解重写equals()方法
    一个月速刷leetcodeHOT100 day13 二叉树结构 以及相关简单题
    idea软件的快捷键
    Spring IOC容器的启动 AbstractApplicationContext详解
    JDBC数据库连接
  • 原文地址:https://blog.csdn.net/sanhewuyang/article/details/126474157