짧은 이야기 : 큰 오래된 회사, 많은 UNIX / Linux 서버.
몇 년 전에 남은 스크립트에 대한 책임을 물려 받았습니다. 그중 하나는 모든 서버에서 루트 암호를 전체적으로 업데이트하기 위해 $ X 개월마다 실행되는 스크립트였습니다.
이 스크립트는 Shell Script and Expect의 혼란이며 모든 서버와 중앙 명령 및 제어 서버 사이에 설정된 SSH 트러스트에서 작동합니다.
문제는 스크립트가 큰 혼란입니다. Expect 명령은 UNIX / Linux 상자에 존재하는 가능한 모든 “passwd”버전을 설명하려고합니다.
많은 인프라를 확장하고 업그레이드함에 따라 스크립트는 실제로 관리하기가 어렵습니다.
내 질문은 : 더 좋은 방법이 있습니까? 이미 설정된 SSH 신뢰가 있다고 가정하면 3000 개 이상의 서버에서 동시에 루트 암호를 변경하는 가장 좋은 방법은 무엇입니까?
답변
꼭두각시를 사용하십시오 .
Puppet은 매우 유연하고 유지 관리가 쉽고 SSL을 사용합니다. 약간 과잉 소리를 낼 수 있으므로 꼭두각시 시스템을 구축하기 위해 약간의 노력을 기울여야합니다.
그러나. 아마도 이것은 당신이이 머신들에 대해 수행 할 마지막 대량 업데이트가 아닐 것입니다. 꼭두각시는 실제 대량 업데이트 절차가 시작되고 스크립트가 매우 읽기 쉽고 재사용 가능한 많은 시간을 절약 해줍니다.
적어도 이것은 몇 년 전에 저에게 효과가 있었지만 여전히 Puppet 레시피 (일명 스크립트)를 재사용 할 수 있습니다. 또한 좀 더 작은 규모의 환경에서도 사용했는데 모든 컴퓨터가 실제로 알려진 상태 인지 확인하십시오 .
나는 모든 사용자 정의 된 배포 스크립트가 잠시 후 또는 다음 사람이 들어올 때 엉덩이에 통증이되는 것으로 여러 번 입증했습니다.
이것이 실제로 좋은 것으로 생각되면 시작하기 위해 가상 환경이 포함 된 훌륭한 Puppet 자습서가 있습니다.
답변
솔라리스에서 Perl 모듈 Authen :: PAM을 성공적으로 사용했습니다. 샘플 스크립트는 다음과 같습니다.
#!/usr/bin/perl
use Authen::PAM;
my $username = 'root';
my $password = '1234567';
die qq{Error: Unknown user\n} unless getpwnam($username);
die qq{Error: You must run this as root.\n} unless ($> == 0);
my $pamh;
sub my_conv_func
{
my @res;
while ( @_ )
{
my $code = shift;
my $msg = shift;
my $ans = "";
if ($code == PAM_PROMPT_ECHO_OFF() )
{
if (($msg =~ /^New Password:/i) or ($msg =~ /^Re-enter new Password:/i))
{
$ans = $password;
}
else
{
die qq{Unknown message: $msg\n};
}
}
else
{
print qq{$msg\n};
}
push @res, (PAM_SUCCESS(), $ans);
}
push @res, PAM_SUCCESS();
return @res;
}
ref($pamh = new Authen::PAM("passwd", $username, \&my_conv_func)) || die "Error code $pamh during PAM init!";
my $res = $pamh->pam_chauthtok;
print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
exit 0;
답변
Perl을 작성할 수 있으면 Net :: OpenSSH :: Parallel 모듈을 사용하면 SSH를 통해 원격 호스트에서 병렬로 작업을 수행하는 스크립트를 매우 쉽게 작성할 수 있습니다.
기본으로 사용할 수있는 비밀번호 변경을위한 샘플 스크립트 가 포함되어 있습니다 . 이기종 환경이있는 것처럼 호스트를 유형별로 그룹화하고 모든 대화 처리 하위를 사용하려고합니다.
답변
나는 “최상의”에 대해 모른다. 그리고 당신의 믹스에있는 모든 비 리눅스 * nix 머신이 가능한지 아닌지, 이런 종류의 활동을 위해 꼭두각시 나 cfengine을 보았는가?
아이덴티티 관리를위한 상용 (고가의) 툴도 있습니다. 과거에 보았거나 사용했던 두 가지는 Oracle Identity Manager와 Novel에 해당합니다.
답변
이것을 계속 연구 한 후에, 나는 몇 가지를 배웠습니다 …
무엇보다도, 이것은 특히 여러 환경에서 자동화하는 정말 성가신 작업입니다. 이 질문에 대한 가장 정확한 답변은 @ tomi ‘s : use Puppet입니다.
결국 Puppet이 인프라를 관리하게하려고했지만 루트 암호 변경을 위해 전체 엔터프라이즈의 UNIX 서버에 배포하는 것은 현재로서는 불가능합니다.
많은 맨 페이지와 많은 Google-fu를 읽은 후 대상 서버 목록을 반복하고 SSH 연결을 열고 다음 중 하나를 실행하는 스크립트를 만들었습니다.
# Solaris
# Generate new pass via crypt(newpass,salt) and insert it into /etc/shadow
# AIX
$ echo "root:newpass" | chpasswd -f NOCHECK
# Linux
$ echo "newpass" | passwd root --stdin
# IBM VIO (Virtual I/O)
$ echo "echo \"padmin:newpass\" | chpasswd -f NOCHECK" | oem_setup_env
# IBM HMCs (Hardware Management Consoles)
$ chhmcusr -u hscroot -t passwd -v "newpass"
그것은 단지 그 명령을 실행하는 것보다 훨씬 더 많은 일을하지만, 위의 것들은 마술을 작동시키는 것입니다.
솔라리스에서 비밀번호를 반복적으로 변경하는 간단한 방법을 찾을 수 없었기 때문에 /etc/shadow
즉시 수정 했습니다.
답변
최근에 Bash Script를 사용 하여이 작업을 수행했습니다.
#!/usr/bin/env bash
# Change Password of Remote Server Using SSH
#--------------------------------------------
# Define User which you want to
# Change Password in remote server
#--------------------------------------------
Uname="root"
# Create Password in Encrpyted Form Using below command,
# and store in this script
# perl -e'print crypt("YourPassword", "salt")' ; echo -e
# then copy and past in following varible,
# password should be single qouted*
Password='safv8d8ESMmWk'
Update_Pass() {
ssh $ruser@$Server_ip -p $port "echo ${Uname}:${Password} | chpasswd -e"
}
Show_Help(){
cat <<_EOF
Usage $0 [OPTION]..
Mandatory arguments to long options are mandatory for short options too.
-i, --ip <IP_ADDR_OF_SREVER> IP Address Of Remote Server
-u, --user <Username> Username Of Remote Server <Default User is root>
-p, --port <port> Port Of Remote Server <Default is 22>
Note:- For Security Reason Do Not Provide Password to the script, because
it will get save in history, so do not provide it,
script will prompt for password
Report $0 bugs to loginrahul90@gmail.com
_EOF
}
Main() {
case $1 in
-i|--ip) Server_ip=$2;
ruser="$4"; [[ -z $ruser ]] && ruser=root
port="$6"; [[ -z $port ]] && port=22
Update_Pass ;;
*) Show_Help ;;
esac
}
Main $*
답변
이것은 지금까지 내 솔루션입니다. 여전히 여러 시스템에서 작동하는지 확인해야합니다.
#!/usr/bin/env bash
ChangePassword()
{
echo "changing password for server $ServerIp"
ssh root@$ServerIp "echo root:${NewPassword} | chpasswd" < /dev/null
}
CreatePassword()
{
while true;
do
echo "Please enter the new password :"
read -s NewPassword <&0
echo "Confirm the password :"
read -s ConfirmPassword <&0
# /proc/${PPID}/fd/0
if [ "$NewPassword" == "$ConfirmPassword" ]
then
break
else
echo "Passwords do not match"
echo "Try again..."
fi
done
ChangePassword
echo "end of createpassword"
}
SetUpPasswordlessSSH()
{
echo "enter the old password from server $ServerIp when asked"
ssh root@$ServerIp mkdir -p .ssh
cat .ssh/id_rsa.pub | ssh root@$ServerIp 'cat >> .ssh/authorized_keys'
echo "Passwordless SSH is now available"
echo "Now you can change the password"
CreatePassword
}
NoSSH()
{
echo "Passwordless SSH for this server with ip $ServerIp is not yet set up."
read -p "Do you want to set it up now? " -n 1 -r <&0
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
break
else
SetUpPasswordlessSSH
fi
}
AcceptHostKey()
{
read -p "Do you trust the server? " -n 1 -r <&1
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
break
else
SetUpPasswordlessSSH
fi
}
Main()
{
while read -r ServerIp <&9
do
echo "Server $ServerIp ..."
status=$(ssh -o BatchMode=yes -o ConnectTimeout=5 $ServerIp echo ok 2>&1)
if [[ $status == ok ]]
then
echo "creating password"
CreatePassword
echo "password changed"
elif [[ $status == "Permission denied"* ]]
then
NoSSH
elif [[ $status == "Host key verification failed"* ]]
then
echo "Error: $status"
AcceptHostKey
else
echo "ERROR OCCURED FOR SERVER WITH IP: $ServerIp"
echo "Error: $status"
fi
done 9< servers.txt
history -cw
clear
}
Main $*