多数の「外部」サーバーの管理には、お客様のデータを保護する責任が伴います。 サーバーへのsshアクセス権を持つユーザーのリストを確実に制御するために、ホストの限られたセットを持つ許可システムを考慮することが決定されました。
問題文にあるもの:
- 400台を超える物理マシン。
- すべてのクライアントサービスは、openvz仮想コンテナーに格納されます(ほとんど)。
- すべてのサーバーへのルートアクセスはsshによって閉じられます。
- 物理サーバーの管理者のみがsudoを介してルート権限にアクセスできます。
- 当社が所有するいくつかのサーバー。その半分は地理的に分散しています。 それらを「アクセスサーバー」と呼びましょう。
行われたこと:
- 最初のステップでは、構成管理システムを使用して、パスワードなしでアクセスサーバーからキーを入力するために、すべての物理sshサーバーにキーを配布しました。 各管理者には独自のキーがあります。
- 2番目のステップは、アクセスサーバーを除くすべてのホストから物理サーバーへのsshアクセスを閉じることです。
もちろん、このようなスキームには例外がありますが、これはすべて個別です。
ここで、このようなソリューションのセキュリティの問題が発生します。アクセスサーバーでアカウントを破ると、すべてのサーバーに無制限にアクセスでき、パスワードなしのキーでアクセスできます。
控えめに言っても、あまり良くありません!
ファイアウォールを介してアクセスサーバーへのsshアクセスを制限し、従業員のIPからのみアクセスを許可するという提案がありました。 いいね しかし、ここに問題があります:私たちには多くの管理者がいて、多くは動的IPを持っています。 はい、旅行中などに緊急に「働く」必要がある場合はどうなりますか?
レポートにとどまることにしました。 つまり、特定のログインが許可されているもののリストにないipで正常に認証されるたびに、このイベントの高いステータスの問題はredmineで私たちに落ち、そして中毒の尋問を使用して何が起こったのかを見つけます。
実装:
現在のssh監査の既成のソリューションを調べましたが、非常に恐ろしいこともそうでないことも、適切なものは見つかりませんでした。
そしていつものように、あなたの自転車、つまりスクリプトを書くことに決めました。 どれ:
- 許可が成功したかどうかsshログを分析します。
- 過去10分間のデータを取得します。
- 対応するリストからユーザー名/ IPペアを比較します
- 成功した場合、何もしません
- 一致しない場合、アラートを送信します。アラートはその後、redmineのタスクになります。
スクリプトはpythonで書かれています。 私は私の人生で2回目のpythonで書いたので、コードに関するコメントは客観的な方法で受け入れられます。 さらに、機能します!
添付のリスト:
#!/usr/bin/env python import sys, os, time from datetime import datetime, timedelta, date, time as dt_time import socket hostname = socket.gethostname() fileList = "./List.ip" date = datetime.now() - timedelta(minutes=10) date = date.strftime('%H:%M:%S') from commands import * import smtplib def mail(message): smtp_server = "localhost" smtp_port = 25 smtp_user= "root@%s" % hostname subject = 'Ahtung!! Security SSH audit alert' to = "mail@example.ru" mail_lib = smtplib.SMTP(smtp_server, smtp_port) msg = 'From: %s\r\nTo: %s\r\nContent-Type: text/html; charset="utf-8"\r\nSubject: %s\r\n Return-Path: <root@%s>\r\n\r\n' % (smtp_user, to, subject, hostname) msg += message mail_lib.sendmail(smtp_user, to, msg) listLog = getoutput('''cat /var/log/secure |grep "Accepted password for" | awk '{if($3>="'''+date+'''"){print $3 " " $9 " " $11 }}' ''') if listLog: for line in listLog.split('\n'): matchIp = 0 matchName = 0 curIp = line.split()[2] for lineLs in open(fileList): if len(lineLs.strip()) == 0 or lineLs[0] == "#" or lineLs[0] == " ": continue if line.split()[1] == lineLs.split()[0]: matchName = 1 listIp = lineLs.split()[1] i = 0 for c in listIp.strip().split("."): if c.strip() == "0": break i = i + 1 if listIp.strip().split(".")[0:i] == curIp.split(".")[0:i]: matchIp = 1 if not matchIp: if not matchName: print("This user %s not found !!!" % line.split()[1]) message = "This user %s not found !!!" % line.split()[1] mail(message) else: print("Ahtung! User {0} logged from unknown IP {1} in time {2}").format(line.split()[1], line.split()[2], line.split()[0]) message = "Ahtung! User "+line.split()[1]+" logged from unknown IP "+line.split()[2]+" in time "+line.split()[0] mail(message)
List.ipファイルの形式は次のとおりです。
#Vasya vasya 1.2.3.4 vasya 12.13.14.0
関連するアクション:
- スクリプトをcronに入れて、10分ごとに実行します。
- 深夜にsshログの毎日のローテーションを構成します。
- アクセスサーバー上のキーによる認証を無効にします。
- パロノイド性を高めるために、ユーザー名/ IPリストをギスに保存し、フックを介してアクセスサーバーに分散させることができます。
このスキームの追加(相対)プラス:従業員を解雇する必要がある場合(ただし、これはまだ発生します:()、アクセスサーバー上のセッションを強制終了するだけです。