簡単に言えば、古い大企業、多くのUNIX/Linuxサーバーです。
私は数年前に残された多くのスクリプトの責任を引き継ぎました。それらの1つは、すべてのサーバーでrootパスワードをグローバルに更新するために$ Xヶ月ごとに実行されるスクリプトでした。
スクリプトはシェルスクリプトと期待の混乱であり、すべてのサーバーと中央のコマンドアンドコントロールサーバーとの間に設定されたSSH信頼で動作します。
問題は、スクリプトが非常に混乱していることです。 Expectコマンドは、UNIX/Linuxボックスに存在する "passwd"のすべての可能なバージョンを考慮に入れようとしています。それらはかなり異なります。
インフラストラクチャの多くを拡張およびアップグレードしているため、スクリプトは非常に扱いにくくなっています。
私の質問は、これを行うより良い方法はありますか?すでに確立されたSSH信頼があると仮定して、3000以上のサーバーで同時にrootパスワードを変更する最良の方法は何ですか?
Puppet を使用します。
Puppetは非常に柔軟で、保守が簡単で、SSLを使用します。少しやり過ぎに聞こえるかもしれませんが、Puppetシステムを構築するために追加の労力を費やす必要があります。
だが。おそらくこれは、これらのマシンに対して行う最後の大量更新ではありません。 Puppetを使用すると、大量の更新手順が実際に開始され、スクリプトが非常に読みやすく、再利用できる場合に、多くの時間を節約できます。
少なくともこれは私にとって数年前にはうまくいきましたが、それでも私はそれらのパペットレシピ(別名スクリプト)の一部を再利用することができます。私は少し小さい環境でも使用していますが、すべてのマシンが実際に既知の状態であることを確認してください。
私は何度も(多くの企業で)カスタマイズされたすべての展開スクリプトがしばらくすると、または次の人が介入するとお尻に痛みを感じることを証明しました。
これが実際にいいと思うなら、ここに 仮想環境が含まれた素晴らしいPuppetチュートリアル があります。
私はSolarisで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経由でリモートホスト上で並列アクションを非常に簡単に実行するスクリプトを記述できます。
これには、ベースとして使用できるパスワードを変更するための サンプルスクリプト が含まれています。異種環境があるように見えるので、ホストをタイプごとにグループ化し、ホストごとに異なるダイアログ処理サブを使用したいとします。
「最高」について、そしてあなたのミックスのLinux以外のすべての* nixマシンでそれが可能かどうかはわかりませんが、この種の活動のためにパペットまたはcfengineを調べましたか?
ID管理のための商用(非常に高価な)ツールもあります。これまでに見たり使用したりしているのは、Oracle Identity ManagerとNovelの同等のものです。
最近、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 $*
これがこれまでの私の解決策です。それが複数のシステムで動作するかどうかを確認する必要があります
#!/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 $*
これを研究し続けた後、私はいくつかのことを学びました...
何よりもまず、これは、特に多くの異なる環境にわたって、自動化するのが本当に面倒なタスクです。この質問に対する最も正しい答えは、おそらく@ tomi'sです。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"
それはそれらのコマンドだけを実行するよりもかなり多くのことを行いますが、上記のものは魔法を働かせるものです。
Solarisで非反復的にパスワードを変更する簡単な方法が見つからなかったため、/etc/shadow
をその場で変更することにしました。
Puppetに加えて:SaltStack別のアプローチ-SSHライブラリを使用して、Fabricを使用して順次または並列で実行を自動化 http://docs.fabfile.org/en/1.6/ 、Capistranoなど、必要のないもの展開するのに多くの時間/労力。
2つのオプション:
人形を使う
ランデッキを使用します。ランデッキは、何百ものマシンで同時にコマンドを実行できるサーバーです。マシンのサブセットでコマンドを実行するために、マシンをグループにグループ化できます。
pdsh を使用して、複数のホストで同時にコマンドを実行できます。