分类
devops

ssh-keygen+ssh-keyscan+ssh-copy-id三条命令实现ssh non interactive登录

ssh-keygen+ssh-keyscan+ssh-copy-id三条命令实现ssh免密 non interactive登录

如下代码实现从A机器(192.168.1.100)到B机器(192.168.1.111)的ssh免密non interactive登录。

## 在A机上操作如下三句
ssh-keygen -t rsa -b 4096 -N '' -m PEM <<<$'\ny\n'
ssh-keyscan -H 192.168.1.111 >> ~/.ssh/known_hosts
ssh-copy-id -i ~/.ssh/id_rsa.pub jerry@192.168.1.111

解释

ssh-keygen -t rsa -b 4096 -N '' -m PEM <<<$'\ny\n'

这句是生成密钥对,不产生交互,如果以前存在则删除重建。

参考https://stackoverflow.com/questions/43235179/how-to-execute-ssh-keygen-without-prompt

ssh-keyscan -H 192.168.1.111 >> ~/.ssh/known_hosts

这句是把ssh fingerprint加入到A机器~/.ssh/known_hosts

参考https://www.techrepublic.com/article/how-to-easily-add-an-ssh-fingerprint-to-your-knownhosts-file-in-linux/

ssh-copy-id -i ~/.ssh/id_rsa.pub jerry@192.168.1.111

这句是附加公钥(即A机器的~/.ssh/id_rsa.pub)到B机器~/.ssh/authorized_keys,第一次提示输入密码。

20220826更新

想了以下,认为这个也不叫免密登陆,叫ssh 通过私钥实现无交互登陆

20220827更新

更简洁的使用两条命令就可以了,无需增加 ssh-keyscan 这一条,但是需要通过-o增加ssh参数。参考

## 测试用例
ssh-keygen -f "$HOME/.ssh/known_hosts" -R "192.168.1.111" > /dev/null;
ssh-copy-id -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_rsa.pub jim@192.168.1.111

第一次输入密码可以通过sshpass or expect方式实现自动完成。参考

20220929更新

脚本:批量根据密码拷贝公钥到目标机器的bash脚本

#!/bin/bash
# cat > hosts <<'EOF'
# #hostname         user    password    port    identity_file
# 192.168.1.111 root    password    22  
# EOF


auto_ssh_copy_id() {
    #ssh-keygen -R "$1" -f "$HOME/.ssh/known_hosts" > /dev/null;
    expect -c "set timeout -1;
        spawn ssh-copy-id -p $3 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null  $1;
        expect {
            *(yes/no)* {send -- yes\r;exp_continue;}
            *assword:* {send -- $2\r;exp_continue;}
            eof        {exit 0;}
        }";
}

ssh_copy_id_to_all() {
    while IFS= read -r line || [ -n "$line" ]; do
        if [[ "$line" =~ ^\#.* ]]; then
            continue
        fi

        server=$(echo "${line}" | awk -F " " '{print $1}')
        user=$(echo "${line}" | awk -F " " '{print $2}')
        password=$(echo "${line}" | awk -F " " '{print $3}')
        port=$(echo "${line}" | awk -F " " '{print $4}')
        echo "${line}" && auto_ssh_copy_id "${user}@${server}" "${password}" "${port}"
    done < hosts
}

ssh_copy_id_to_all

参考资料