ssh-copy-id가 스크립트 루프(클러스터)에서 비정상적으로 작동합니다.

ssh-copy-id가 스크립트 루프(클러스터)에서 비정상적으로 작동합니다.

Ubuntu 20.04를 실행하는 RPi4 세트(7개)가 있습니다. 그 중 하나는 GUI이고 거기에서 명령을 실행합니다. 관리자 3명과 직원 3명이 있습니다(/etc/hosts가 모두 올바르게 설정되어 있습니다).

처음에는 모두 동일한 이름과 비밀번호를 가진 사용자가 있습니다.

비밀번호 없는 SSH를 사용할 수 있도록 gui(gui0)에서 한 번 실행되는 단일 스크립트에서 SSH를 설정하고 싶습니다.

gui* 시스템은 모든 것에 액세스할 수 있어야 하며, Manager* 시스템은 관리자와 작업자에 액세스할 수 있어야 하며 작업자는 다른 작업자에만 액세스할 수 있어야 합니다.

그 이유는 GlusterFS(및 기타 몇 가지 사항)를 사용하여 스토리지를 설정하므로 머신이 이들 간에 통신할 수 있어야 하기 때문입니다.

나는 어느 정도 작동하는 스크립트를 개발했습니다. 특정 명령 사이에 잠을 자는 시간에 따라 실제로 복사되는 키는 더 많지만 오랫동안 잠을 자고 있으며 여전히 100%는 아닙니다.

스크립트:

#!/bin/bash

################################################################################
##  source                                    ##
################################################################################
source  lib/libalx/sh/sysexits.sh;  ## This provides EX_USAGE=64


################################################################################
##  definitions                               ##
################################################################################
ARGC=0;

guis="gui0";
managers="manager0 manager1 manager2";
workers="worker0 worker1 worker2";
all_machines="${guis} ${managers} ${workers}";
gui_accessible_machines="${all_machines}";
manager_accessible_machines="${managers} ${workers}";
worker_accessible_machines="${workers}";


################################################################################
##  functions                                 ##
################################################################################
## XXX: Pair calls to this function with "unset SSHPASS"!!!
function read_ssh_password()
{

    echo "This script will set up keyless ssh."
    echo "After this script, ssh will not accept passwords again."
    echo "Enter the current password for ssh connections."

    read -s -p "Password to use: " SSHPASS;
    echo;
    export SSHPASS;
}

function create_ssh_keys()
{

    for remote in ${all_machines}; do
        echo "  SSH-KEYGEN  ${remote};"
        sshpass -e ssh ${remote} "
            ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa;
        ";
    done
}

function distribute_ssh_keys_to()
{
    local   accessible_machines="$1";
#   local   ssh_opts="-o PreferredAuthentications=keyboard-interactive";
#   ssh_opts="${ssh_opts} -o PubkeyAuthentication=no";

    for remote in ${accessible_machines}; do
        echo "  SSH-COPY-ID $(cat /etc/hostname)    ${remote};"
        sshpass -e ssh-copy-id -i ~/.ssh/id_rsa.pub ${remote}   \
        2>&1 | grep -e WARNING -e ERROR -e added;
        sleep 60;
    done
}

function distribute_ssh_keys_from()
{
#   ssh_opts="-o PreferredAuthentications=keyboard-interactive";
#   ssh_opts="${ssh_opts} -o PubkeyAuthentication=no";
    local   machines="$1";
    local   accessible_machines="$2";

    for remote in ${machines}; do
        sshpass -e ssh ${remote} "
            $(declare -fg);
            export SSHPASS=${SSHPASS};
            distribute_ssh_keys_to  \"${accessible_machines}\";
            unset SSHPASS;
        ";
        sleep 300;
    done
    sleep 300;
}

function distribute_ssh_keys()
{

    distribute_ssh_keys_from "${guis}" "${gui_accessible_machines}";
    distribute_ssh_keys_from "${managers}" "${manager_accessible_machines}";
    distribute_ssh_keys_from "${workers}" "${worker_accessible_machines}";

    for remote in ${all_machines}; do
        ssh ${remote} "
            $(declare -fg);
            secure_ssh;
        ";
        sleep 60;
    done
}

function secure_ssh()
{

    :; ## TODO
}

function create_distribute_ssh_keys()
{

    read_ssh_password;

    create_ssh_keys;
    sleep 300;
    distribute_ssh_keys;

    unset SSHPASS;
}


################################################################################
##  main                                      ##
################################################################################
function main()
{

    create_distribute_ssh_keys;
}


################################################################################
##  run                                   ##
################################################################################
argc=$#;
if [ ${argc} -ne ${ARGC} ]; then
    echo    "Illegal number of parameters (Requires ${ARGC})";
    exit    ${EX_USAGE};
fi

main;

산출:

ubuntu@gui0:~$ ./bin/setup_ssh.sh 
This script will set up keyless ssh.
After this script, ssh will not accept passwords again.
Enter the current password for ssh connections.
Password to use: 
    SSH-KEYGEN  gui0;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  manager0;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  manager1;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  manager2;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  worker0;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  worker1;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  worker2;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-COPY-ID gui0    gui0;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    manager0;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    manager1;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    manager2;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    worker0;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    worker1;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    worker2;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.

    SSH-COPY-ID manager0    manager0;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID manager0    manager1;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID manager0    manager2;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID manager0    worker0;
Number of key(s) added: 1
    SSH-COPY-ID manager0    worker1;
    SSH-COPY-ID manager0    worker2;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID manager1    manager0;
    SSH-COPY-ID manager1    manager1;
    SSH-COPY-ID manager1    manager2;
    SSH-COPY-ID manager1    worker0;
    SSH-COPY-ID manager1    worker1;
    SSH-COPY-ID manager1    worker2;
    SSH-COPY-ID manager2    manager0;
    SSH-COPY-ID manager2    manager1;
    SSH-COPY-ID manager2    manager2;
    SSH-COPY-ID manager2    worker0;
    SSH-COPY-ID manager2    worker1;
    SSH-COPY-ID manager2    worker2;
    SSH-COPY-ID worker0 worker0;
    SSH-COPY-ID worker0 worker1;
    SSH-COPY-ID worker0 worker2;
    SSH-COPY-ID worker1 worker0;
    SSH-COPY-ID worker1 worker1;
    SSH-COPY-ID worker1 worker2;
    SSH-COPY-ID worker2 worker0;
    SSH-COPY-ID worker2 worker1;
    SSH-COPY-ID worker2 worker2;

추가된 키 수나 오류 또는 경고를 나타내는 줄을 항상 받고 싶습니다. 하지만 어떤 경우에는 INFO 줄만 수신합니다(나는 grep을 사용하여 해당 줄을 노이즈로 삭제합니다). 보시다시피, 처음 몇 개는 잘 작동합니다(처음 실행한 것이 아니기 때문에 경고가 표시되므로 이전 실행에서 키가 이미 설치되어 있지만 괜찮습니다). 실패하고 모든 실패가 실패했습니다.

잠을 적게 자면 더 일찍 실패하기 시작합니다.

grep을 사용하지 않을 때 어떤 일이 발생하는지에 대한 예는 다음과 같습니다.

    SSH-COPY-ID manager0;   worker0;
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ubuntu/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'worker0'"
and check to make sure that only the key(s) you wanted were added.

    SSH-COPY-ID manager0;   worker1;
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ubuntu/.ssh/id_rsa.pub"
    SSH-COPY-ID manager0;   worker2;
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ubuntu/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'worker2'"
and check to make sure that only the key(s) you wanted were added.

왜 그렇게 불규칙하게 실패합니까?

답변1

나는 당신이 왜 그렇게 긴 말을 퍼뜨렸는지 이해할 수 없으며 sleep, 나는 당신의 프로그램의 흐름을 올바르게 추적했다고 믿지 않습니다. 그러나 요구 사항에 따라 다음이 필요합니다.

gui* 머신은 모든 것에 접근할 수 있어야 하며, Manager* 머신은 관리자와 작업자에 접근할 수 있어야 하며 작업자는 다른 작업자에만 접근할 수 있어야 합니다.

그래서

  • GUI → GUI 관리자 작업자
  • 관리자 → 관리자 작업자
  • 노동자 → 노동자

그러면 그렇게 해. 여러분은 자신만의 진행 상황 업데이트와 종료 상태를 추가하고 싶을 것이라고 확신하지만, 이 기본 요소가 도움이 될 것입니다.

#!/bin/bash
#
guis=(gui0)
managers=(manager0 manager1 manager2)
workers=(worker0 worker1 worker2)

# Grab the password
#
IFS= read -rsp "Master password: " sshpass && echo


# First, GUI to everything
#
if [[ ! -f "$HOME/.ssh/id_rsa" ]] || [[ ! -f "$HOME/.ssh/id_rsa.pub" ]]
then
    # Start clean
    rm -f "$HOME/.ssh/id_rsa" "$HOME/.ssh/id_rsa.pub"
    ssh-keygen -t rsa -b 4096 -f "$HOME/.ssh/id_rsa" -P ""
fi

for dst in "${guis[@]}" "${managers[@]}" "${workers[@]}"
do
    # Using the password we entered at the beginning, copy the keys everywhere
    SSHPASS=$sshpass sshpass -ev ssh-copy-id -o StrictHostKeyChecking=no -i "$HOME/.ssh/id_rsa" "$dst"
done


# Now generate a key on each host in turn
#
for dst in "${managers[@]}" "${workers[@]}"
do
    # Ensure the target is clean and then generate a new key
    ssh -n "$dst" 'rm -f .ssh/id_rsa .ssh/id_rsa.pub'
    ssh -n "$dst" 'ssh-keygen -t rsa -b 4096 -f .ssh/id_rsa -P ""'
done


# Grab each host's key pair
#
for src in "${managers[@]}" "${workers[@]}"
do
    scp -p "$src:.ssh/id_rsa" "$HOME/.ssh/id_rsa.$src"
    scp -p "$src:.ssh/id_rsa.pub" "$HOME/.ssh/id_rsa.$src.pub"
done


# Push each Manager key out to the Managers and Workers
#
for src in "${managers[@]}"
do
    for dst in "${managers[@]}" "${workers[@]}"
    do
        ssh-copy-id -i "$HOME/.ssh/id_rsa.$src" "$dst"
    done
done


# Push each Worker key out to the Workers
#
for src in "${workers[@]}"
do
    for dst in "${workers[@]}"
    do
        ssh-copy-id -i "$HOME/.ssh/id_rsa.$src" "$dst"
    done
done


# Now fix up the "authenticity of host" warnings by connecting everywhere
#
for src in "${managers[@]}"
do
    for dst in "${managers[@]}" "${workers[@]}"
    do
        ssh -n "$src" ssh -n -o StrictHostKeyChecking=no "$dst" id >/dev/null
    done
done

for src in "${workers[@]}"
do
    for dst in "${workers[@]}"
    do
        ssh -n "$src" ssh -n -o StrictHostKeyChecking=no "$dst" id >/dev/null
    done
done


# Delete the unwanted key pairs from this host
#
for src in "${managers[@]}" "${workers[@]}"
do
    rm -f "$HOME/.ssh/id_rsa.$src" "$HOME/.ssh/id_rsa.$src.pub"
done


# All done
#
exit 0

모든 것은 gui0클라이언트( )에 의해 제어되며 이 프로세스 중에 관리자나 작업자가 다른 컴퓨터로 파일 복사본을 시작하지 않습니다.

답변2

주된 이유는 SSH가 호스트( )를 모르기 ~/.ssh/known_hosts때문에 파일에 새 호스트를 추가하라는 메시지가 표시되기 때문입니다. 물론 스크립트는 이에 반응할 수 없습니다.

@roaima가 그의 답변에 대한 의견에서 지적했듯이 해결책은 간단합니다. ssh ... -o StrictHostKeyChecking=no

내 스크립트에 몇 가지 다른 문제가 있어서 이를 수정했습니다(코드를 제공한 @roaima 덕분에 몇 가지 사항도 개선했습니다).

나중에 이 작업을 수행해야 하는 사람을 위해 제 작업 스크립트는 다음과 같습니다.

#!/bin/bash
set -Eeo pipefail
################################################################################
##
## Set up ssh network
## ==================
##
##  Run this script from a guiX machine
##
################################################################################


################################################################################
##  source                                    ##
################################################################################
source  lib/libalx/sh/sysexits.sh;


################################################################################
##  definitions                               ##
################################################################################
ARGC=0;

guis=(gui0);
managers=(manager0 manager1 manager2);
workers=(worker0 worker1 worker2);
all_machines="${guis[*]} ${managers[*]} ${workers[*]}";
gui_accessible_machines="${all_machines}";
manager_accessible_machines="${managers[*]} ${workers[*]}";
worker_accessible_machines="${workers[*]}";

ssh_opts='-o StrictHostKeyChecking=no';


################################################################################
##  functions                                 ##
################################################################################
## XXX: Pair calls to this function with "unset SSHPASS"!!!
function read_ssh_password()
{

    echo "This script will set up keyless ssh."
    echo "After this script, ssh will not accept passwords again."
    echo "Enter the current password for ssh connections."

    read -s -p "Password to use: " SSHPASS;
    echo;
    export SSHPASS;
}

function create_ssh_keys()
{

    for remote in ${all_machines}; do
        echo "  SSH-KEYGEN  ${remote};"
        sshpass -e ssh ${ssh_opts} ${remote} "
            ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -P '' ||:;
        ";
    done
}

function distribute_ssh_keys_to()
{
    local   accessible_machines="$1";

    for remote in ${accessible_machines}; do
        echo "  SSH-COPY-ID $(cat /etc/hostname)    ${remote};"
        sshpass -e ssh-copy-id -i ~/.ssh/id_rsa.pub ${ssh_opts} \
                    ${remote}           \
        2>&1 | { grep -e WARNING -e ERROR ||:; };
    done
}

function distribute_ssh_keys_from()
{
    local   machines="$1";
    local   accessible_machines="$2";

    for remote in ${machines}; do
        sshpass -e ssh -n ${ssh_opts} ${remote} "
            set -Eeo pipefail
            $(declare -fg);
            export SSHPASS=\"${SSHPASS}\";
            ssh_opts=\"${ssh_opts}\";
            distribute_ssh_keys_to  \"${accessible_machines}\";
            unset SSHPASS;
        ";
    done
}

function distribute_ssh_keys()
{

    distribute_ssh_keys_from "${guis[*]}" "${gui_accessible_machines}";
    distribute_ssh_keys_from "${managers[*]}" "${manager_accessible_machines}";
    distribute_ssh_keys_from "${workers[*]}" "${worker_accessible_machines}";

    for remote in ${all_machines}; do
        ssh -n ${remote} "
            $(declare -fg);
            secure_ssh;
        ";
    done
}

function secure_ssh()
{

    :; ## TODO
}

function create_distribute_ssh_keys()
{

    read_ssh_password;
    create_ssh_keys;
    distribute_ssh_keys;

    unset SSHPASS;
}


################################################################################
##  main                                      ##
################################################################################
function main()
{

    create_distribute_ssh_keys;
}


################################################################################
##  run                                   ##
################################################################################
argc=$#;
if [ ${argc} -ne ${ARGC} ]; then
    echo    "Illegal number of parameters (Requires ${ARGC})";
    exit    ${EX_USAGE};
fi

main;


################################################################################
##  end of file                               ##
################################################################################

출력은 다음과 같습니다.

$ ./bin/setup_ssh.sh
This script will set up keyless ssh.
After this script, ssh will not accept passwords again.
Enter the current password for ssh connections.
Password to use: 
    SSH-KEYGEN  gui0;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  manager0;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  manager1;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  manager2;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  worker0;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  worker1;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-KEYGEN  worker2;
Generating public/private rsa key pair.
/home/ubuntu/.ssh/id_rsa already exists.
Overwrite (y/n)? n
    SSH-COPY-ID gui0    gui0;
/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
    SSH-COPY-ID gui0    manager0;
    SSH-COPY-ID gui0    manager1;
    SSH-COPY-ID gui0    manager2;
    SSH-COPY-ID gui0    worker0;
    SSH-COPY-ID gui0    worker1;
    SSH-COPY-ID gui0    worker2;
    SSH-COPY-ID manager0    manager0;
    SSH-COPY-ID manager0    manager1;
    SSH-COPY-ID manager0    manager2;
    SSH-COPY-ID manager0    worker0;
    SSH-COPY-ID manager0    worker1;
    SSH-COPY-ID manager0    worker2;
    SSH-COPY-ID manager1    manager0;
    SSH-COPY-ID manager1    manager1;
    SSH-COPY-ID manager1    manager2;
    SSH-COPY-ID manager1    worker0;
    SSH-COPY-ID manager1    worker1;
    SSH-COPY-ID manager1    worker2;
    SSH-COPY-ID manager2    manager0;
    SSH-COPY-ID manager2    manager1;
    SSH-COPY-ID manager2    manager2;
    SSH-COPY-ID manager2    worker0;
    SSH-COPY-ID manager2    worker1;
    SSH-COPY-ID manager2    worker2;
    SSH-COPY-ID worker0 worker0;
    SSH-COPY-ID worker0 worker1;
    SSH-COPY-ID worker0 worker2;
    SSH-COPY-ID worker1 worker0;
    SSH-COPY-ID worker1 worker1;
    SSH-COPY-ID worker1 worker2;
    SSH-COPY-ID worker2 worker0;
    SSH-COPY-ID worker2 worker1;
    SSH-COPY-ID worker2 worker2;

시험:

ubuntu@gui0:~$ ssh manager0 'ssh worker2 cat /etc/hostname'
worker2
ubuntu@gui0:~$ ssh worker2 'ssh manager1 cat /etc/hostname'
Host key verification failed.

관련 정보