Найкращий спосіб змінити кореневий пароль на серверах 3000+ Solaris, AIX та Linux?


12

Довга коротка історія: Велика стара корпорація, багато серверів UNIX / Linux.

Я успадкував відповідальність за купу сценаріїв, які залишилися кілька років тому. Одним із них був сценарій, який буде запускатися кожні $ X місяці для глобального оновлення кореневого пароля на всіх наших серверах.

Сценарій є безладом Shell Script і Expect, і він працює на довірі SSH, встановленому між усіма нашими серверами та центральним сервером команд і управління.

Проблема в тому, що сценарій - це гігантський безлад. Команди Expect намагаються врахувати кожну можливу версію "passwd", яка існує на будь-якому вікні UNIX / Linux там - і вони досить різняться.

Оскільки ми розширюємо та модернізуємо багато нашої інфраструктури, сценарій стає дійсно некерованим.

Моє запитання: чи є кращий спосіб зробити це? Якщо припустити, що вже існує довіра SSH, який найкращий спосіб одночасно змінити пароль root на 3000+ серверах?


2
Використання sudoта усунення кореневих паролів взагалі - це не варіант, чи не так?
Дмитро Чубаров

5
Найняти стажера? :)
EEAA

1
@DmitriChubarov використання "sudo" означало б мати інший обліковий запис, щоб підтримувати (і змінювати) пароль на - тож де сенс?
Вабіт

1
@ syneticon-dj, інші облікові записи можуть бути створені заново і зберігатися в централізованій базі даних, наприклад, LDAP або NIS, що краще підтримується. Це не те саме, що вирвати локальний корінь і замінити його на той, що походить від ldap.
Дмитро Чубаров

2
Якщо у вас є машини 3k, вам потрібні інструменти управління ... вчора!
warren

Відповіді:


17

Використовуйте лялечку .

Лялька дуже гнучка, проста в обслуговуванні та використовує SSL. Можливо, це звучить трохи надмірно, і вам доведеться докласти додаткових зусиль, щоб створити систему ляльок.

Але. Швидше за все, це не останнє масове оновлення, яке ви будете робити на цих машинах. Лялька допоможе вам заощадити чимало часу, коли починається процедура масового оновлення та сценарії дуже читаються / багаторазово використовуються.

Принаймні, це спрацювало для мене кілька років тому, і я все ще можу повторно використовувати деякі з тих лялькових рецептів (ака сценарії). Я також використовував його в трохи менших середовищах, просто переконайтесь, що кожна машина насправді має відомий стан .

Я багато разів доводив (у багатьох компаніях), що всі налаштовані сценарії розгортання через деякий час стають болем у задці або коли вступить цей наступний хлопець. І поки ви носите мобільний телефон, старі сценарії будуть вас переслідувати.

Якщо ви думаєте, що це насправді добре звучить, ось вам чудовий навчальний посібник для ляльок із включеним віртуальним середовищем для початку роботи.


4
Agred, але не використовуйте a user{"root":}для встановлення пароля. Замість цього скористайтеся exec{"chpasswd -e ..."}, що набагато безпечніше.
Денніс Каарсемейкер

7
Виправте свою відповідь, лялька використовує SSL, а не SSH. Погодьтеся з іншими, хоча анзібль здається як легка альтернатива набагато краще підходить для цього випадку використання. Просто pip install ansibleу вікні GNU / Linux складіть список хостів та ansible -m user -a "password=$crpyt". Агентів не потрібно. Керує GNU / Linux, AIX та Solaris поза коробкою.
dawud

Правда, він використовує SSL, а не SSH. Я використовую для підтримки в системі, в якій Лялька використовувалася через SSH, виконуючи клієнта - короткий короткий сюжет. Відповідь виправлена. Дякую, що Дауд вказував на це!
tomi

Я дав свою власну відповідь нижче , але приймаю вашу, оскільки це, мабуть, найбільш "правильне" та кероване довгострокове рішення проблеми. Однак це потребує значних вкладень в інфраструктуру, планування, ліцензування та час для того, щоб розгорнути лялечку в оточенні нашого розміру.
Колись

1
@DennisKaarsemaker: ви повинні повідомити про це як про помилку в Лялькових лабораторіях. Їм було б дуже цікаво почути це.
Білл Вайс

3

Я з великим успіхом використовував модуль 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;

2

Якщо ви можете написати Perl, модуль Net :: OpenSSH :: Parallel дозволяє писати сценарії, які виконують дії паралельно на віддалених хостах через SSH.

Він містить зразок сценарію для зміни паролів, який ви можете використовувати в якості основи. Оскільки здається, що у вас є неоднорідне середовище, ви хочете згрупувати хости за типом та використовувати для кожного з них різні підрозділи для обробки діалогів.


1

Я не знаю про "найкраще", і чи можливо це для всіх нелінукс * nix машин у вашій суміші, але ви подивилися на маріонетку чи cfengine для цього виду діяльності?

Існують також комерційні (дуже дорогі) інструменти для управління ідентифікацією, два, які я бачив / використовував у минулому, - Oracle Identity Manager та еквівалент роману.


1

Продовживши дослідження цього, я дізнався кілька речей ...

По-перше, це справді дратувальне завдання автоматизації, особливо у багатьох різних середовищах. Найбільш правильна відповідь на це питання - це, мабуть, @ tomi: використовуйте Лялечку.

Врешті-решт, я сподіваюся отримати Puppet для управління інфраструктурою, але розгортання на серверах UNIX всього підприємства для зміни кореневих паролів зараз не є такою можливою можливістю.

Прочитавши багато руководств і безлічі Google-фу, мені вдалося придумати сценарій, який перебирає список цільових серверів, відкриває 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на ходу.


2
Будь ласка, не ставте паролі чіткого тексту в командному рядку, оскільки він потрапляє в історію оболонки. Або встановіть історію оболонки /dev/nullперед тим, як це зробити.
Марцін

1
так, також не ставте пароль у скрипті, перевірте мій сценарій, щоб додати зашифрований пароль
Рахул Патіл

1

Нещодавно я це робив за допомогою сценарію Bash ..

#!/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 $*

1

Це моє рішення поки що. ще потрібно перевірити, чи працює він у кількох системах

#!/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 $*

0

Ви можете використовувати pdsh для виконання вашої команди на кількох хостах одночасно.


І яку команду ви збираєтеся виконувати? passwdвідрізняється у різних згаданих версіях. pwне завжди доступний ....
Chris S

У нас є частина запущених команд у всіх полях досить добре. Проблема полягає в фактичній зміні пароля. Наскільки я знаю, passwdце завжди інтерактивний користувач.
Рікапар

passwdУ RHEL Linux принаймні є --stdinпараметр
AngerClown

0

На додаток до лялькових: SaltStack Ще один підхід - автоматизувати виконання за допомогою послідовностей SSH або послідовно, або паралельно, використовуючи Fabric http://docs.fabfile.org/en/1.6/ , Capistrano або подібні, які не потребують багато часу / зусиль для розгортання.


0

Два варіанти:

Використовуйте лялечку

Використовуйте біг колоди. Run deck - це сервер, який дозволяє виконувати команди на сотнях машин одночасно. Можна згрупувати машини в групи, щоб виконувати команди лише на підмножині машин.

http://rundeck.org


-2

Я думаю, що формат /etc/shadowфайлу є досить стандартним для Linux-дистрибутивів. Чи можете ви просто написати простий скрипт для оновлення пароля.

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

Я би переконався, що випробуєте це, щоб ви не заблокували себе;)


Я вважаю, що це саме шлях для редагування / тощо / тіні. Однак, чи не переспрямування буде стерти / etc / shadow перед редагуванням? Це схоже на випадок для редактора чи колишнього.
mpez0

3
Формат тіні може бути, але хеші не гарантуються, що їх інтерпретуватимуть всюди одним і тим же алгоритмом. Плюс ваш маленький сценарій просто видалив усі записи з тіні. :}
тинк

lol ой, слід виправити. Я сподіваюся, ви не судо запустили цей тинк;)
HaxElit
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.