Najlepszy sposób na zmianę hasła roota na ponad 3000 serwerach Solaris, AIX i Linux?

12

Krótko mówiąc: Wielka stara korporacja, wiele serwerów UNIX / Linux.

Odziedziczyłem odpowiedzialność za kilka skryptów, które opuściły kilka lat temu. Jednym z nich był skrypt, który będzie uruchamiany co miesiąc X dolarów w celu globalnej aktualizacji hasła roota na wszystkich naszych serwerach.

Skrypt jest bałaganem Shell Script and Expect i działa na zaufaniu SSH, które jest ustawione między wszystkimi naszymi serwerami a centralnym serwerem dowodzenia i kontroli.

Problem polega na tym, że scenariusz to ogromny bałagan. Polecenia Expect próbują uwzględnić każdą możliwą wersję „passwd”, która istnieje na dowolnym urządzeniu z systemem UNIX / Linux - i różnią się one nieco.

Ponieważ rozbudowujemy i aktualizujemy dużą część naszej infrastruktury, skrypt staje się naprawdę niemożliwy do zarządzania.

Moje pytanie brzmi: czy jest na to lepszy sposób? Zakładając, że istnieje już zaufanie SSH, jaki jest najlepszy sposób na zmianę hasła roota na ponad 3000 serwerów jednocześnie?

Ricapar
źródło
2
Używanie sudoi eliminowanie haseł roota nie jest opcją, prawda?
Dmitrij Chubarow
5
Zatrudnić stażystę? :)
EEAA
1
@DmitriChubarov przy użyciu „sudo” oznaczałoby posiadanie innego konta do utrzymywania (i zmiany) hasła na - więc gdzie jest sens?
the-wabbit
1
@ syneticon-dj inne konta mogą być tworzone od nowa i przechowywane w centralnie zarządzanej bazie danych, np. LDAP lub NIS, cokolwiek jest lepiej obsługiwane. To nie jest to samo, co odrywanie lokalnego roota i zastępowanie go tym, który pochodzi z ldap.
Dmitrij Chubarow
2
Jeśli masz> 3k maszyn, potrzebujesz narzędzi do zarządzania ... wczoraj!
warren

Odpowiedzi:

17

Użyj marionetki .

Puppet jest bardzo elastyczny, łatwy w utrzymaniu i korzysta z SSL. Może zabrzmi to nieco przesadnie i będziesz musiał włożyć dodatkowy wysiłek w budowę systemu Lalek.

Ale. Najprawdopodobniej nie jest to ostatnia masowa aktualizacja, którą zrobisz na tych komputerach. Puppet zaoszczędzi ci dużo czasu, gdy rozpocznie się faktyczna procedura masowej aktualizacji, a skrypty będą bardzo czytelne / wielokrotnego użytku.

Przynajmniej działało to dla mnie kilka lat temu i nadal jestem w stanie ponownie wykorzystać niektóre z tych przepisów na kukiełki (inaczej skrypty). Użyłem go również w nieco mniejszych środowiskach, po prostu upewnij się, że każda maszyna faktycznie ma znany stan .

Wielokrotnie (w wielu firmach) udowodniłem, że wszystkie niestandardowe skrypty wdrożeniowe stają się kłopotliwe po pewnym czasie lub gdy wkracza następny facet. I dopóki nosisz telefon komórkowy, stare skrypty będą cię prześladować.

Jeśli uważasz, że to naprawdę brzmi dobrze, oto świetny samouczek Puppet z dołączonym wirtualnym środowiskiem, aby zacząć.

tomi
źródło
4
Znowu, ale nie używaj a user{"root":}do ustawienia hasła. Zamiast tego użyj exec{"chpasswd -e ..."}znacznie bezpieczniejszego.
Dennis Kaarsemaker
7
Popraw swoją odpowiedź, marionetka używa SSL, a nie SSH. Zgadzam się z resztą, choć ansible wydaje się być lekką alternatywą o wiele lepiej pasującą do tego przypadku użycia. Wystarczy pip install ansiblew oknie GNU / Linux zbudować listę hostów i ansible -m user -a "password=$crpyt". Nie potrzeba agentów. Zarządza systemami GNU / Linux, AIX i Solaris od razu po wyjęciu z pudełka.
dawud
To prawda, że ​​używa SSL, a nie SSH. Zwykle jestem opiekunem w systemie, w którym Puppet był używany przez SSH poprzez wykonanie krótkiego opowiadania o kliencie. Odpowiedź poprawiona. Dziękuję Dawud, że to podkreślił!
tomi
Podałem poniżej własną odpowiedź , ale akceptuję twoją, ponieważ jest to prawdopodobnie najbardziej „poprawne” i możliwe do rozwiązania długoterminowe rozwiązanie problemu. Wymaga to jednak znacznych inwestycji w infrastrukturę, planowanie, licencjonowanie i czas, aby wprowadzić Puppet w środowisku o naszych rozmiarach. Pewnego dnia się tam dostaniemy ...
Ricapar,
1
@DennisKaarsemaker: należy zgłosić ten błąd jako Puppet Labs. Byliby bardzo zainteresowani jego usłyszeniem.
Bill Weiss,
3

Z dużym powodzeniem korzystałem z modułu Perl Authen :: PAM w systemie Solaris. Oto przykładowy skrypt:

#!/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;
fortezza
źródło
2

Jeśli potrafisz pisać w Perlu, moduł Net :: OpenSSH :: Parallel pozwala dość łatwo pisać skrypty, które wykonują akcje równolegle na zdalnych hostach za pośrednictwem SSH.

Zawiera przykładowy skrypt do zmiany haseł, których można użyć jako podstawy. Wygląda na to, że masz heterogeniczne środowisko, w którym chciałbyś pogrupować hosty według typu i użyć dla każdego z nich innej podrzędnej obsługi dialogu.

salva
źródło
1

Nie wiem o „najlepszym” i czy jest to możliwe dla wszystkich maszyn innych niż Linux * nix w twoim miksie, ale czy widziałeś marionetkę lub cfengine dla tego rodzaju aktywności?

Istnieją również komercyjne (bardzo drogie) narzędzia do zarządzania tożsamością, dwa, które widziałem / używałem w przeszłości, to Oracle Identity Manager i Novel odpowiednik.

zadzwonić
źródło
1

Po dalszym badaniu tego nauczyłem się kilku rzeczy ...

Przede wszystkim jest to bardzo denerwujące zadanie automatyzacji, szczególnie w wielu różnych środowiskach. Najbardziej poprawną odpowiedzią na to pytanie jest prawdopodobnie @ tomi: użyj Puppet.

Ostatecznie mam nadzieję, że Puppet będzie zarządzał infrastrukturą, ale wdrożenie na serwerach UNIX całego przedsiębiorstwa w celu zmiany hasła roota nie jest obecnie wykonalne.

Po przeczytaniu wielu stron i wielu stron Google-fu udało mi się wymyślić skrypt, który zapętla listę serwerów docelowych, otwiera połączenie SSH i uruchamia jedną z następujących czynności:

# 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"

Robi to znacznie więcej niż uruchamianie tylko tych poleceń, ale te powyżej służą do magii.

Nie mogłem znaleźć żadnego prostego sposobu, aby nie iteracyjnie zmienić hasło w Solarisie, więc uciekliśmy się do modyfikacji /etc/shadoww locie.

Ricapar
źródło
2
Nie umieszczaj haseł w postaci czystego tekstu w linii poleceń, ponieważ są one rejestrowane w historii powłoki. Lub ustaw historię powłoki na /dev/nullzanim to zrobisz.
Marcin
1
tak, również nie wpisuj hasła w skrypcie, sprawdź mój skrypt, aby dodać zaszyfrowane hasło
Rahul Patil
1

Ostatnio zrobiłem to używając skryptu 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 [email protected]
_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 $*
Rahul Patil
źródło
1

To moje dotychczasowe rozwiązanie. wciąż muszę sprawdzić, czy działa na wielu systemach

#!/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 $*
duez
źródło
0

Możesz użyć pdsh, aby wykonać polecenie na wielu hostach jednocześnie.

Jacek
źródło
A jakie polecenie zamierzasz wykonać? passwdróżni się w zależności od różnych wymienionych wersji. pwnie zawsze dostępne ....
Chris S
Mamy dość dobrze działające polecenia na wszystkich polach. Problemem jest faktyczna zmiana hasła. O ile mi wiadomo, passwdzawsze jest interaktywny dla użytkownika.
Ricapar
passwdna RHEL Linux ma przynajmniej --stdinparametr
AngerClown
0

Oprócz marionetek: SaltStack Inne podejście - zautomatyzuj wykonywanie za pomocą bibliotek SSH, sekwencyjnie lub równolegle, za pomocą Fabric http://docs.fabfile.org/en/1.6/ , Capistrano lub podobnego, które nie wymagają dużo czasu / wysiłku do wdrożenia.

Eugene
źródło
0

Dwie opcje:

Użyj marionetki

Użyj pokładu run. Run deck to serwer, który pozwala na wykonywanie poleceń na setkach komputerów jednocześnie. Możesz grupować maszyny w grupy, aby wykonywać polecenia tylko na podzbiorze maszyn.

http://rundeck.org

spuder
źródło
-2

Myślę, że format /etc/shadowpliku jest dość standardowy we wszystkich dystrybucjach Linuksa. Czy możesz po prostu napisać prosty skrypt awk, aby zaktualizować hasło?

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

Zrobiłbym to, żeby to przetestować, żebyś nie zablokował się;)

HaxElit
źródło
Wierzę, że edytowanie / etc / shadow jest właściwą drogą. Jednak czy przekierowanie nie usunie pliku / etc / shadow przed edycją? To wygląda jak skrzynka dla ed lub ex.
mpez0
3
Format cienia może być, ale skróty nie są interpretowane przez ten sam algorytm wszędzie. Dodatkowo twój mały skrypt całkowicie usunął wszystkie wpisy z cienia. :}
zadzwonić
lol oops, powinno zostać naprawione. Mam nadzieję, że nie uruchomiłeś sudo;)
HaxElit