Короче говоря: большая старая корпорация, много серверов UNIX / Linux.
Я унаследовал ответственность за кучу скриптов, которые остались несколько лет назад. Одним из них был сценарий, который запускался каждые X месяцев для глобального обновления пароля root на всех наших серверах.
Сценарий представляет собой беспорядок Shell Script и Expect, и он работает с доверием SSH, которое установлено между всеми нашими серверами и центральным сервером управления и контроля.
Проблема в том, что сценарий представляет собой гигантский беспорядок. Команды Expect пытаются учесть каждую возможную версию "passwd", которая существует в любом устройстве UNIX / Linux, и они довольно сильно различаются.
Поскольку мы расширяем и модернизируем большую часть нашей инфраструктуры, сценарий становится действительно неуправляемым.
Мой вопрос: есть ли лучший способ сделать это? Предполагая, что SSH-доверие уже установлено, как лучше всего изменить пароль root на более чем 3000 серверах одновременно?
Использовать Кукольный.
Puppet очень гибок, прост в обслуживании и использует SSL. Это может показаться излишним, и вам придется приложить дополнительные усилия для создания системы Puppet.
Но. Скорее всего, это не последнее массовое обновление, которое вы будете делать для этих машин. Puppet сэкономит и действительно сэкономит вам много времени, когда начинается фактическая процедура массового обновления, а сценарии становятся легко читаемыми / повторно используемыми.
По крайней мере, это сработало для меня несколько лет назад, и все же я могу повторно использовать некоторые из этих рецептов Puppet (они же сценарии). Я также использовал его в немного меньших средах, просто убедитесь, что на каждой машине действительно есть известное состояние.
Я много раз доказывал (во многих компаниях), что все настраиваемые сценарии развертывания становятся головной болью через некоторое время или когда вмешивается следующий парень. И пока вы носите с собой мобильный телефон, старые сценарии будут преследовать вас.
Если вы думаете, что это звучит хорошо, вот отличное руководство по Puppet с включенной виртуальной средой чтобы вы начали.
Я с большим успехом использовал Perl-модуль Authen :: PAM в Solaris. Вот пример сценария:
#!/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 :: параллельный позволяет легко писать сценарии, которые выполняют действия параллельно на удаленных хостах через SSH.
Он содержит образец сценария для смены паролей, которые можно использовать в качестве основы. Поскольку кажется, что у вас неоднородная среда, вы хотели бы сгруппировать хосты по типу и использовать для каждого отдельную подпрограмму обработки диалогов.
Продолжив исследовать это, я узнал несколько вещей ...
Прежде всего, это действительно неприятная задача для автоматизации, особенно во многих различных средах. Вероятно, наиболее правильный ответ на этот вопрос - @ tomi: используйте Puppet.
В конце концов, я надеюсь, что Puppet сможет управлять нашей инфраструктурой, но развертывание на серверах UNIX всего предприятия для смены пароля root прямо сейчас не является возможным вариантом.
После прочтения множества руководств и множества 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"
Он делает немного больше, чем просто выполнение этих команд, но те, что указаны выше, творит чудеса.
Я не смог найти простого способа без итеративного изменения пароля в Solaris, поэтому мы прибегли к изменению /etc/shadow
на лету.
Я не знаю, что такое «лучший» и возможно ли это для всех машин без Linux * nix в вашем миксе, но смотрели ли вы на puppet или cfengine для такого рода деятельности?
Существуют также коммерческие (очень дорогие) инструменты для управления идентификацией, два из которых я видел / использовал в прошлом - это Oracle Identity Manager и его аналог в Novel.
Недавно я сделал это с помощью 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 $*
Вы могли бы использовать пдш для выполнения вашей команды на нескольких хостах одновременно.
В дополнение к марионетке: SaltStack Другой подход - автоматизация выполнения с использованием библиотек SSH последовательно или параллельно с использованием Fabric http://docs.fabfile.org/en/1.6/, Capistrano или аналогичные, которые не требуют много времени / усилий для развертывания.
Два варианта:
Использовать марионетку
Используйте колоду бега. Run deck - это сервер, который позволяет выполнять команды на сотнях машин одновременно. Вы можете сгруппировать машины в группы, чтобы выполнять команды только на подмножестве машин.
Я думаю, что формат /etc/shadow
file является стандартным для всех дистрибутивов Linux. Можете ли вы написать простой скрипт на awk для обновления пароля.
cat /etc/shadow| awk -v pass='NEWPASSHASH' -v now=`date '+%s'` 'BEGIN{ OFS=FS=":"} /^root/ {$2=pass; $3=now} {print}' > /tmp/shadow && mv /tmp/shadow /etc/shadow
Я обязательно протестирую это, чтобы вы не блокировали себя;)