Назад | Перейти на главную страницу

Как лучше всего изменить пароль root на более чем 3000 серверах Solaris, AIX и Linux?

Короче говоря: большая старая корпорация, много серверов 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 - это сервер, который позволяет выполнять команды на сотнях машин одновременно. Вы можете сгруппировать машины в группы, чтобы выполнять команды только на подмножестве машин.

http://rundeck.org

Я думаю, что формат /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

Я обязательно протестирую это, чтобы вы не блокировали себя;)