加载中…
个人资料
liujun_live
liujun_live
  • 博客等级:
  • 博客积分:0
  • 博客访问:425,391
  • 关注人气:13
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

SSH 使用小记(附批量修改远程主机密码)

(2014-09-09 09:58:48)
标签:

ssh

ssh-agent

ssh-keygen

expect

sshpass

分类: Common
openssh加密密钥代理验证

sshpass非交互登录
sshpass+ssh可以实现完全非交互式密码访问远程主机,可直接跳过第一次访问时的yes/no,现如今炙手可热的ansible安装时也会一并安装上sshpass噢
格式:sshpass -p 密码 ssh -o StrictHostKeyChecking=no 用户@主机
如:sshpass -p password ssh -o StrictHostKeyChecking=no foo@192.168.1.1

expect非交互登录
示例:
将如下内容保存为expect脚本,foo.exp

#!/usr/bin/expect

set timeout 5

set user foo

set password foo123

set host 10.10.4.12

spawn ssh $user@$host

expect {

        "Connection refused" exit

        "Name or service not known" exit

        "continue connecting" {send "yes\r";exp_continue}

        "password:" {send "$password\r";exp_continue}

}

expect eof 

interact


运行时执行,expect -f foo.exp即可自动登录

SSH服务端加速
提示1:Ubuntu发行版默认不允许root ssh远程登录,注释掉/etc/ssh/sshd_config 中的如下一行即可开启root远程登录
PermitRootLogin without-password
提示2:禁用ssh DNS反解,加快访问速度,修改或添加如下行即可
UseDNS no
提示3: 未使用Kerberos时,可以设置
GSSAPIAuthentication no

SSH客户端
ControlPersist

版本新一点的openssh,如centos7默认自带的版本。

在ssh客户端配置文件/etc/ssh/ssh_config中加入如下内容,可以在~/.ssh/目录下生成访问缓存文件,第一次访问会生成临时的socket隧道,之后再次连接时无需输入再次输入密码

 Host *

   SendEnv LANG LC_*

   ControlMaster auto

   ControlPath ~/.ssh/%h-%p-%r

   ControlPersist yes


jlive@MacBook-Pro:~ $pstree |grep ssh

 | |   \--= 00751 jlive ssh root@192.168.130.254

 |     \--- 00876 jlive grep ssh

 |--= 00752 jlive /usr/bin/ssh-agent -l

 |--= 00755 jlive ssh: /Users/jlive/.ssh/192.168.130.254-22-root [mux] 

 

 |--= 00816 jlive ssh: /Users/jlive/.ssh/10.157.20.8-22-wasadmin [mux] 

jlive@MacBook-Pro:~ $ls .ssh/

10.157.20.8-22-wasadmin id_rsa                  known_hosts

192.168.130.254-22-root id_rsa.pub


忽略主机指纹检查(第一次访问远程主机时不用输yes确认)
/etc/ssh/ssh_config或者~/.ssh/config
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null


一.本地用户密码验证
ssh正常登录某主机会提示输入密码,如没有指定以谁的身份登录则以当前用户的身份来验证
root@jun-live:~#ssh 192.168.2.104
The authenticity of host '192.168.2.104 (192.168.2.104)' can't be established.
RSA key fingerprint is 81:9a:a5:90:4d:4b:2d:b1:df:45:39:33:1a:7f:af:d5.
Are you sure you want to continue connecting (yes/no)? yes  
Warning: Permanently added '192.168.2.104' (RSA) to the list of known hosts.
root@192.168.2.104's password:
Last login: Tue Sep  9 10:04:14 2014

二.公私钥验证
A.通过ssh-keygen在本机生成公私钥对
提示: 静默生成ssh-keygen  -t rsa -N '' -f ~/.ssh/id_rsa -q -b 2048

root@vhost4:~#ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):     
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
c8:07:b6:d5:f4:26:91:7e:1b:97:86:5d:8a:b2:39:e2 root@vhost4
The key's randomart image is:

+---[RSA 2048]----+

          .BE++|

|         +..o |

      . .... o |

|     . .  .. oo +|

  o o S ... ..+|

|     * = =.   .o |

  . = =.B    o |

|     . ..*.*  |

|       ..o*=+.   |

+----[SHA256]-----+


加密算法默认采用的是rsa加密,dsa可选。
ssh-keygen生成公钥和私钥时会“问”,公私钥存放的位置及名称,如果不指定则默认放在~/.ssh这个目录,并且默认叫id_rsa(私钥), id_rsa.pub(公钥),known_hosts里存放的则是所有远程主机的信息,每个主机一条标识,当远程主机名一样但IP等信息发生变化时会提示信息不匹配,这里只需要把known_hosts里对应的那条记录删掉,再重新建立连接一次,这里该主机的信息会再次自动添加known_hosts文件。可以通过你喜欢的编辑器来打开~/.ssh/known_hosts这个文件删除对应的行,我这里直接用sed流编辑器
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
c7:b3:03:2f:7c:ab:9e:75:fe:c9:a3:45:63:1b:55:3f.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending key in /root/.ssh/known_hosts:66
RSA host key for 192.168.2.251 has changed and you have requested strict checking.
Host key verification failed.
lost connection


sed  -i  '/192.168.2.251/d'  ~/.ssh/know_hosts
在提示公私钥的存放位置后还会问,是否给公私钥设置密码,直接回车则不设置密码,如果设置了密码则每次去连接远程主机时都会提示输入公私钥的密码。

问题:
1.没有设置密码的公私钥,配对成功后访问远程主机更方便但不安全,随便copy到另外一台主机就可以无密码直接ssh到已经经过该公私钥配对验证成功的主机
2.设置密码后的公私钥更安全,即便被窃取,但在使用时会提示输入密码,破解也是需要时间的,但每次访问某台主机都需要输入本地公私钥对的密码,不太方便,麻烦。
3.远程主机非常多,并且需要非交互地远程执行一些脚本或命令,这时如果登录一台就输入一次公私钥对的密码,那也很麻烦,怎么办---代理

root@vhost4:~#pwd
/root
root@vhost4:~#ls .ssh/
id_rsa  id_rsa.pub  known_hosts
root@vhost4:~#cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAtDgmYibO4iuwRj0mAhHvWxvAF1uxCPEtif3yDiISJJncvHGB99V17F/AodzIFv9SOV9F4qekcjmnjNu95VJ7bdAQUnKUJIEABGo4LjhPZB3BJd2RxAdCXvP/IiDIlNjT7RzOd5n9peVmbaMX2wpslvNxdHV3FbHnIa3RrbwfiQ6EitvtOthlOGQgkOgYAEnVbX8RyKAj5ATSW4yrHO1vIyPOe/9/ng0nlwgEoLQnmcetbjJGbcgcdAfY31dE3GTnFVKwbpYWLKnDSGRNj1fPUe2ytBEI4cGMp7uYezROt8m0yd95d4+m6O+6BhO2FYtjaYN1+PlVA8pNiQEyp+Rb0Q== root@vhost4


B.将本机的公钥copy到远程主机的~/.ssh/authorized_keys
root@vhost4:~#ssh-copy-id -i .ssh/id_rsa.pub 192.168.2.250
root@192.168.2.250's password:
/root/.bashrc: line 48: bind: warning: line editing not enabled
/root/.bashrc: line 54: bind: warning: line editing not enabled
/root/.bashrc: line 59: bind: warning: line editing not enabled
Now try logging into the machine, with "ssh '192.168.2.250'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

默认情况下都是放在远程主机的~/.ssh/authorized_keys这个文件中,除远程主机的/etc/ssh/sshd_config配置文件有重新定义,下面是截取的一段,大概在49行的样子,不同版本可能有些微差异。
47 #RSAAuthentication yes
48 #PubkeyAuthentication yes
49 #AuthorizedKeysFile     .ssh/authorized_keys
50 #AuthorizedKeysCommand none
51 #AuthorizedKeysCommandRunAs nobody

ssh-copy-id   #自动将本地公钥添加到远程主机~/.ssh/authorized_keys的脚本,一般在安装了openssh后就会有
ssh-copy-id  install  your  public  key in a remote machine’s authorized_keys

SYNOPSIS
       ssh-copy-id [-i [identity_file]] [user@]machine

DESCRIPTION
       ssh-copy-id is a script that uses ssh to  log  into  remote  machine
       (presumably  using  a login password, so password authentication should
       be enabled, unless you’ve done some clever use of multiple  identities)
       It  also changes the permissions of the remote user’s home, ~/.ssh, and
       ~/.ssh/authorized_keys to remove group writability (which would  other-
       wise  prevent  you  from logging in, if the remote sshd has StrictModes
       set in its configuration).  If the -i option is given then the identity
       file  (defaults  to  ~/.ssh/id_rsa.pub)  is used, regardless of whether
       there are any keys in your ssh-agent
ssh-copy-id能很方便地将本地公钥添加到远程主机对应的认证文件中,当然如果没有这个工具要怎么办呢,通常我们搜索到的文章讲述的时手动copy到远程主机,再把公钥追加到认证文件authorized_keys中。

scp -p ~/.ssh/id_rsa.pub  192.168.2.250:/tmp      #把本地的公钥copy到远程的某个目录
ssh 192.168.2.250       #登录到远程主机
cat /tmp/id_rsa.pub >>~/.ssh/authorized_keys   #把公钥追加到authorized_keys,这所以要追加是因为远程主机的认证文件authorized_keys中可能已经有了其它客户端的公钥了,如果直接覆盖则其它主机又得重新验证。
rm -rf /tmp/id_rsa.pub   #删掉公钥,以确保安全。

C.ssh-agent公私钥代理认证
1.启用代理,当登录远程主机时会提示输入key的密码,这个密码就时用ssh-keygen生成公私钥对时设置的密码。每次登录都会要求输入密码验证,
root@vhost4:ssh#ssh 192.168.2.250
Enter passphrase for key '/root/.ssh/id_rsa':

2.启用代理
    There are two main ways to get an agent set up: The first is that the agent starts a new subcommand
     into which some environment variables are exported, eg ssh-agent xterm & The second is that the
     agent prints the needed shell commands (either sh(1) or csh(1) syntax can be generated) which can be
     evaluated in the calling shell, eg eval ‘ssh-agent -s‘ for Bourne-type shells such as sh(1) or ksh(1)
     and eval ‘ssh-agent -c‘ for csh(1) and derivatives.
 从上面的man帮助中我们可以知道,有2种方式来设置代理,

a. 代理subcommand  如,ssh-agent xterm &,通过ssh-agent代理开启了一个xterm后台会话,只要在这个xterm终端中输入ssh-add然后再提示并正确输入公私钥对密码后,通过这个xterm发出的ssh连接都不需要再输入任何密码(前提是针对已经通过该公私钥验证过的远程主机)。

b.直接代理shell进程,如,eval 'ssh-agent -s' 代理sh,ksh; eval 'ssh-agent -c'代理csh,tcsh;
注意:这两种方式都只是代理某个进程及由该进程衍生的子进程,举例来说,代理xterm,那么其它的终端去连远程主机照样需要输入本地公私钥的密码,代理的sh,也只局限于该sh进程,也就时在eval 'ssh-agent -s'这条命令回车后在该终端发起的远程连接,如果Ctrl+D回到上层sh,则代理失效。
下面的进程树可以说明这个问题,

$ ssh-agent bash
$ ssh-add ~/.ssh/id_rsa
启用代理前
root@vhost4:~#ps aux|grep ssh-agent
root      2138  0.0  0.1 103252   808 pts/0    R+   11:32   0:00 grep --color=auto ssh-agent
root@vhost4:~#pstree|grep pstree -A3 -B3
     |-6*[mingetty]
     |-rsyslogd---3*[{rsyslogd}]
     |-sshd---sshd---bash-+-grep
                                     `-pstree
     `-udevd---2*[udevd]

直接代理bash
root@vhost4:~#ssh-agent bash
root@vhost4:~#ps aux|grep ssh-agent
root      2142  0.0  0.1  57700   744 ?        Ss   11:33   0:00 ssh-agent bash
root      2153  0.0  0.1 103252   812 pts/0    S+   11:33   0:00 grep --color=auto ssh-agent

验证代理凭据

root@vhost4:~#ssh-add
Enter passphrase for /root/.ssh/id_rsa:
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)

启用代理后,代理ssh-agent是上一bash衍生出的子bash的子进程
root@vhost4:~#pstree|grep pstree -A3 -B3
     |-6*[mingetty]
     |-rsyslogd---3*[{rsyslogd}]
     |-sshd---sshd---bash---bash-+-grep
                                                 |-pstree
                                                 `-ssh-agent
     `-udevd---2*[udevd]

所以说,以后有什么需要非交互远程处理的一个折中办法就是利用ssh-agent代理机制,既增加了连接的安全系数又极大地减少了输入密码的麻烦。
提示:修改ssh私钥密码
ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
root@jun-live:~#ssh-keygen -p
Enter file in which the key is (/root/.ssh/id_rsa):
Enter old passphrase:
Key has comment '/root/.ssh/id_rsa'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
passphrase too short: have 4 bytes, need > 4
Saving the key failed: /root/.ssh/id_rsa.


  
修改远程主机某用户密码

1.直接修改/etc/shadow中对应栏位,并且通过openssl加密的
User=root                                         定义用户
UserPasswd_Clear=hello                #定义明文密码
NewLine_User=$(grep ^$User: /etc/shadow|awk -v UserPasswd_Encrypted=$(openssl passwd -1 UserPasswd_Clear) 'BEGIN { FS=":"} {print $1":"UserPasswd_Encrypted":"$3":"$4":"$5":"$6":"$7":"$8":"$9}')          #生成1行新的shadow密码
echo $NewLine_User>/tmp/ps                                                                          #将该行导到一个临时文件
scp -rp /tmp/ps $Wan:/tmp/ps &>/dev/null                                                     #copy到远程主机
ssh root@$Wan "sed -i '/root:/d' /etc/shadow && sed -i '1R /tmp/ps' /etc/shadow && rm -rf /tmp/ps" 2>/dev/null                                   #删掉/etc/shadow对应的行,并插入刚生成的新行及清除临时文件
rm -rf /tmp/ps &>/dev/null           #清除本地临时文件  
                                         

2.通过passwd --stdin参数,标准输出通过pipi作为passwd的标准输入
注意:ssh 主机 “命令”,命令或命令组一定要用“”引起来,不然不生效,虽然提示密码己更新但实际没有修改。
    ssh root@$Wan "echo hello|passwd --stdin root" 2>/dev/null        #静态密码

    ssh root@$Wan "Wan_End=$(ifconfig eth0|grep -w 'inet addr'|awk '{print $2}'|cut -d: -f2|cut -d. -f4) && echo '^Foo_$'$Wan_End|passwd --stdin root" 2>/dev/null             #动态密码

3.通过chpasswd
格式,   用户名:密码 
    ssh root@$Wan "echo root:hello|chpasswd"  2>/dev/null                 #静态密码
    ssh root@$Wan "Wan_End=$(ifconfig eth0|grep -w 'inet addr'|awk '{print $2}'|cut -d: -f2|cut -d. -f4) && echo root:'^Foo_$'$Wan_End|chpasswd"  2>/dev/null                      #动态密码


批量建用户并设置密码
用户列表格式:pw_name:pw_passwd:pw_uid:pw_gid:pw_gecos:pw_dir:pw_shell

pwunconv      #creates passwd from passwd and shadow and then removes shadow.
newusers  <<font color="22b14c">user.txt

pwconv         #creates shadow from passwd and an optionally existing shadow.




#################################################################
#!/bin/bash
#To distribute programs and scripts automaticlly
#Made by LiuJun, liujun_live@msn.com ,  2014-08-25
#################################################################

#Source function library.
. /etc/init.d/functions

#Export PATH
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games


#Define hosts related variables
Foo_Hosts=$(pwd)/test.txt
Node_Name=$(cat $Foo_Hosts |awk '{print $1}'|cut -d'=' -f2)
Node_Wan=$(cat $Foo_Hosts |awk '{print $2}'|cut -d'=' -f2)
Node_Lan=$(cat $Foo_Hosts |awk '{print $3}'|cut -d'=' -f2)
Node_Counts=$(cat $Foo_Hosts|grep -v ^$|grep -v ^#|wc -l)
Node_Start=1
Node_End=

#Check files are exist whether or not
if [ ! -f $Foo_Hosts ];then
    echo "$Foo_Hosts is not exist"
    exit 1
fi
#if ! [ -f $Copy_From -o -d $Copy_From ];then
   echo "$Copy_From is not exist"
   exit 1
#fi

#Define functions
DNS_Clean(){
    cp -f /etc/resolv.conf /tmp  >/dev/null 2>&1
    echo "" >/etc/resolv.conf
}

DNS_Restore(){
    rm -rf /etc/resolv.conf   >/dev/null 2>&1
    mv -f /tmp/resolv.conf /etc  >/dev/null 2>&1
}

Max_Num(){
if [ "$Node_End" == "" ];then
    if [ "$Node_Start" == "" ];then
    Max_Num=$((${Node_Start:-1}+${Node_End:-$Node_Counts}-$Node_Start+1+1))
    else
    Max_Num=$((${Node_Start:-1}+${Node_End:-$Node_Counts}-$Node_Start+1))
    fi
        else
        Max_Num=$((${Node_End:-$Node_Counts}+1))
fi
}

Password(){
Max_Num
for ((i=${Node_Start:-1};i<$Max_Num;i++))
do
    Name=$(cat $Foo_Hosts|grep -w Node_Name$i|grep -v grep |awk '{print $1}'|cut -d'=' -f2)
    Wan=$(cat $Foo_Hosts|grep -w Node_Name$i|grep -v grep |awk '{print $2}'|cut -d'=' -f2)
    Wan_End=$(cat $Foo_Hosts|grep -w Node_Name$i|grep -v grep |awk '{print $2}'|cut -d'=' -f2|cut -d. -f4)

###############
    #Define passwd related variables
    #User=root
    #UserPasswd_Clear=hello
    #NewLine_User=$(grep ^$User: /etc/shadow|awk -v UserPasswd_Encrypted=$(openssl passwd -1 $UserPasswd_Clear) 'BEGIN { FS=":"} {print $1":"UserPasswd_Encrypted":"$3":"$4":"$5":"$6":"$7":"$8":"$9}')
    #echo $NewLine_User>/tmp/ps
    #scp -rp /tmp/ps $Wan:/tmp/ps &>/dev/null
    #ssh root@$Wan "sed -i '/root:/d' /etc/shadow && sed -i '1R /tmp/ps' /etc/shadow && rm -rf /tmp/ps" 2>/dev/null
    #rm -rf /tmp/ps &>/dev/null
###############
    #echo "LyAliyun@3$$Wan_End"
    #ssh root@$Wan "echo hello|passwd --stdin root" 2>/dev/null
    #ssh root@$Wan "Wan_End=$(ifconfig eth0|grep -w 'inet addr'|awk '{print $2}'|cut -d: -f2|cut -d. -f4) && echo '^Foo_$'$Wan_End|passwd --stdin root" 2>/dev/null

    #ssh root@$Wan "echo root:hello|chpasswd" 2>/dev/null
    ssh root@$Wan "Wan_End=$(ifconfig eth0|grep -w 'inet addr'|awk '{print $2}'|cut -d: -f2|cut -d. -f4) && echo root:'^Foo_$'$Wan_End|chpasswd" 2>/dev/null

###############
    echo -e "\e[36;1m(\e[0m\e[35;1m$Name\e[0m No.\e[31;1m$i\e[0m/\e[35;1m$Node_Counts\e[0m\e[36;1m)\e[0m\e[0m\e[31;1m$Wan\e[0m's password is \e[32;1mupdated\e[0m\r"
done
}


##############################################
DNS_Clean
Password
DNS_Restore
##############################################

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有