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
