web-dev-qa-db-ja.com

サーバー間のユーザーパスワードリストの単純な一方向同期

RedHat派生ディストリビューション(CentOS)を使用して、通常のユーザー(UIDが500を超える)のリストと、バックアップサーバーにプッシュされたグループ(およびシャドウファイル)のリストを保持します。
同期は、メインサーバーからバックアップサーバーへの一方向のみです。

LDAPやNISに対処する必要は本当にありません。
必要なのは、バックアップサーバーを最新の状態に保つために毎晩実行できる単純なスクリプトだけです。
メインサーバーはバックアップシステムにSSH接続できます。

なにか提案を?

編集:
これまでの提案に感謝しますが、十分に明確にしていないと思います。
IDが500以上である通常のユーザーの同期のみを確認しています。
システム/サービスユーザー(UIDが500未満)は、両方のシステムで異なる場合があります。
だから、私が恐れているファイル全体を同期することはできません。

5
Renaud Bompuis

まあ、自分で解決策を用意しなくても使えるものがあると思ったのですが、すぐに何かをしなければなりませんでした。

以下は、私が必要とするものだけを実行するスクリプトです。

指示

それが機能するためには、最小および最大UIDがnormalユーザーおよびリモートホスト名またはIPアドレスと見なされるように、いくつかの構成変数を変更します。

パスワードを入力せずにローカルサーバーのrootユーザーからの着信SSHセッションを受け入れるようにリモートサーバーを設定する必要があります。
コマンダーキーン このページの彼の答えでそれがどのように行われるかを示唆しましたが、 password-less SSH login の詳細な手順。

使い方

スクリプトが行うことは、リモートpasswdgroupshadowgshadowファイルをリモートサーバーからlcoalサーバー上の一時的な場所にコピーします。
次に、すべての「通常の」ユーザーからこれらの一時ファイルを取り除き、システムユーザーへの参照のみを保持します。

次のステップでは、passwdgroupshadowgshadowと「通常の」ユーザーのみを対応する一時ファイルに追加し、それぞれをリモートサーバーにアップロードして、古いファイルを置き換えます。

警告

何かを試す前に、passwdgroupshadowgshadowローカルサーバーとリモートサーバーの両方。

安全保障

ファイルの所有権と属性は保持されます。
一時ファイルは/tmpに保存され、同期が成功したかどうかに関係なく削除されます。
ローカルサーバーには、バックアップへのパスワードなしのrootアクセスが必要です(ただし、その逆はできません)。これは、ユーザーアカウント構成ファイルを取得できるようにするために必要です(他の方法で制限されています)。

コード

これは最初の試みであり、少し面倒です(美しいコードではありません)が、うまく機能し、他の誰かが便利だと思うかもしれません。

これは、サーバー間でファイルを安全にコピーするための Net::SCP モジュールにのみ依存するPerlスクリプトです。

#!/usr/bin/Perl -w
use Net::SCP qw(scp);
use strict;

use constant TRUE  => (1==1);
use constant FALSE => (1==0);

#--------------------------------------------------------
# Configuration
# Modify as needed
#--------------------------------------------------------
my $remoteHost = '10.13.113.2';  # email backup server
my $minUID     = 500;
my $maxUID     = 30000;
my $minGID     = 500;
my $maxGID     = 30000;

#--------------------------------------------------------
# Internal variables, normally not to be modified.
#--------------------------------------------------------
my $systemConfigDir = '/etc';
my $tmpDir = $ENV{TMPDIR} || $ENV{TMP} || $ENV{TEMP} || '/tmp';

#--------------------------------------------------------
#  Main
#--------------------------------------------------------
# STEP 1
# Get the remote files to /tmp and
# clean them of their normal users
ProcessFiles('remote');

# STEP 2
# Append the local normal users to the temp files
# and then send them back to the remote
ProcessFiles('local');

#--------------------------------------------------------
# ProcessFiles sub does one of two things:
# - if the passed argument is 'remote', then fetch each
#   user account file from the remote server, then remove
#   all normal users from each file, only keeping the
#   system users.
# - if the passed argument is 'local', then appends all
#   normal local users to the previously fetched and
#   cleaned-up files, then copies them back to the remote.
#--------------------------------------------------------
sub ProcessFiles {
        my $which = shift;
        my $tmpfile;
        my %username = ();
        my %usergroup = ();
        my %userUID = ();
        my %userGID = ();
        my @info;
        foreach my $f ('passwd','group','shadow','gshadow') {
                my $tmpfile = "$tmpDir/$f.REMOTE";
                if ($which eq 'remote') {
                        # Fetch the remote file
                        unlink $tmpfile if -e $tmpfile;
                        scp("$remoteHost:$systemConfigDir/$f", $tmpfile)
                                or die ("Could not get '$f' from '$remoteHost'");
                }
                # Glob the file content
                open CONFIGFILE, (($which eq 'remote') ? $tmpfile : "$systemConfigDir/$f");
                my @lines = <CONFIGFILE>;
                close CONFIGFILE;
                # Open the temp file, either truncating it or in append mode
                open TMPFILE,  (($which eq 'remote') ? ">$tmpfile" : ">>$tmpfile" )
                        or die "Could not open '$tmpfile' for processing";
                foreach my $line (@lines) {
                         # Skip comments, although they should be illegal in these files
                        next if $f =~ /^\s*#/;
                        @info = (split ':', $line);
                        if ($f eq 'passwd') {
                                my $uid = $info[2];
                                my $isnormaluser = ($uid > $minUID) && ($uid < $maxUID);
                                next if (($which eq 'remote') ? $isnormaluser : !$isnormaluser);
                                $username{$info[0]} = TRUE;
                                $userUID{$uid} = TRUE;
                                $userGID{$info[3]} = TRUE;
                        } elsif ($f eq 'group') {
                                my $gid = $info[2];
                                my $isnormalgroup = ($gid > $minGID) && ($gid < $maxGID);
                                next if (($which eq 'remote') ? $isnormalgroup : !$isnormalgroup);
                                $usergroup{$info[0]} = TRUE;
                        } elsif ($f eq 'shadow') {
                                next if !exists $username{$info[0]};
                        } else {
                                next if !exists $usergroup{$info[0]};
                        }
                        # Any line that reaches this point is valid
                        print TMPFILE $line;
                }
                close TMPFILE;
                if ($which eq 'local') {
                        # send the file back
                        scp($tmpfile, "$remoteHost:$systemConfigDir/$f") or
                                die ("Could not send '$f' to '$remoteHost'");
                        unlink $tmpfile;
                }
        }
}

#--------------------------------------------------------
# Make sure we cleanup the temp files when we exit
#--------------------------------------------------------
END {
        my $tmpfile;
        foreach my $f ('passwd','group','shadow','gshadow') {
                $tmpfile = "$tmpDir/$f.REMOTE";
                unlink $tmpfile if -e $tmpfile;
        }
}

2010年5月21日更新:グループIDの同期を改善するためにコードを更新

2
Renaud Bompuis

Awkを使用して、IDが500以上のユーザー/グループを抽出できます。私はまた、しばしば「nobody」ユーザーのために予約されているユーザーID 65534を除外する自由を取っています(ディストリビューションによって異なります。CentOSがそうする場合の手がかりはありません)。

awk -F: '($3>=500) && ($3!=65534)' /etc/passwd > passwd.new
awk -F: '($3>=500) && ($3!=65534)' /etc/group > group.new
awk -F: '($3>=500) && ($3!=65534) {print $1}' /etc/passwd | grep -f - /etc/shadow > shadow.new

次に、rsync、scp、または選択したファイル転送方法を使用して、ファイルをバックアップシステムにコピーします。これらのファイルは、復元する必要があるときに「クリーン」なpasswd、group、またはshadowファイルの最後に追加できます(つまり、ID /ユーザー名の意図しない重複を防ぐため、デフォルトのシステムユーザー/グループのみ)。

cat passwd.new >> /etc/passwd
cat group.new >> /etc/group
cat shadow.new >> /etc/shadow
10
goldPseudo

NIS/NIS +は、まさにこの理由で発明されました。

しかし、それらはちょっと醜く、集中化されている(LDAP/Kerberos/SMBなど)認証は、それが可能であればはるかに優れたアイデアです。 NIS/NIS +をセットアップするには、次のものが必要です。

パッケージ:

yp-tools ypbind ypserv portmap

そして/etc/yp.confのようなもの:

domain example.org server nis.example.org
ypserver nis.example.org

そして/ etc/sysconfig/network:

NISDOMAIN=example.org

そして私は怠惰になりました、ここに良いハウツーがあります: http://www.wains.be/index.php/2007/02/28/setting-up-nis-under-centos-4/ thatそれについて説明します。

個人的にはバックアップのために、/ etc /ディレクトリ全体をバックアップし、それで完了します。せいぜい数メガしかありません。

3
Kurt

cppwとcpgrを使用します。

CPPW(8)

名前
cppw、cpgr-指定されたファイルをパスワードまたはグループファイルにロックしてコピー

あらすじ
cppw [-h] [-s] password_file cpgr [-h] [-s] group_file

説明
cppwとcpgrは、ロックされた状態で、指定されたファイルをそれぞれ/ etc/passwdと/ etc/groupにコピーします。 -sフラグを指定すると、これらのファイルのシャドウバージョンがそれぞれ/ etc/shadowおよび/ etc/gshadowにコピーされます。 -hフラグを指定すると、コマンドは短いヘルプメッセージを表示し、警告なしで終了します。

も参照
vipw(8)、vigr(8)、group(5)、passwd(5)、shadow(5)、gshadow(5)

著者
cppwとcpgrは、Guy Maorが作成したvipwとvigrに基づいて、Stephen Frostが作成しました。

3
Vish

ここには多くの方法と解決策がありますが、元の質問に答えるには3つのステップがあります。

  1. サーバー上にパスワードなしのSSHキーを作成します。

    ssh-keygen -b 4096

  2. .ssh/id_rsa.pubをクライアントの.ssh/authorized__keys2にコピーします。

    scp ~/.ssh/id_rsa.pub client:.ssh/authorized_keys2

  3. / etc/crontabに次のようなものを追加します(またはcrontab -eで編集します)。

    0 0 * * * scp /etc/{passwd,shadow,group} root@backupbox:/var/mybackupdir

2
Commander Keen

部分的な同期のみを要求するということは、スクリプトがはるかに複雑である必要があることを意味し、したがって、何らかのバグが発生する可能性が高くなります。個人的には、少し時間をかけて、他のアカウントを修正するだけでどれだけの労力が必要かを調査しました。話しているサービスの数はわかりませんが、サービスアカウントのIDの調整を変更した後に行う必要があるのは、いくつかのファイルの所有者を更新することだけでしょう。

本当に簡単なことをしたい場合は、 rdistintro )のように設定して、ファイルを他のサーバーにプッシュするだけです。これを安全に保つには、rdistプロセスが使用するために、鍵ベースのsshアクセスをセットアップする必要があります。

0
Zoredache

Crontabエントリでrsyncを使用して、同じことを実行する簡単なバックアップを実行します。残念ながら、私はsshを介してそれを行いません。私のcrontabエントリは次のようになります。

0 4 * * 0 rsync -av --delete/etc// backup/etc /

実際に私のcrontabはmy NASサーバー、つまり上記の2番目のパスであるwake-on-lanを介して起動し、いくつかのバックアップを実行します。これはそれらの1つだけです。Cronは私にバックアップされたもの、つまり同期されたファイルなどを通知する電子メール.

Sshでこれを行うことは検討していませんが、これが役立つことを願っています。

0
user3146