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.