ssh-copy-idはスクリプトループ(クラスタ)で異常に動作します。

ssh-copy-idはスクリプトループ(クラスタ)で異常に動作します。

Ubuntu 20.04を実行するRPi4セット(7個)があります。そのうちの1つは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.

関連情報