Server Administration
6 March 2012

Связка LightSquid + Active Directory

Использую на прокси-сервере squid анализатор логов LightSquid, и вот, однажды захотелось чтобы статистика была в виде компьютер – реальное имя, а так как править конфигурационный файл для 100+ юзеров показалось делом рутинным, ну и при изменении имени или добавлении новых пользователей лазить опять в конфиг не хотелось, решил брать автоматом имена из Active Directory. За деталями прошу под кат.

У меня используется Active Directory, но с минимальными изменениями скрипт должен работать и с обычной LDAP.
Описывать установку LightSquid не буду, она довольно проста, гугл вам в помощь. Для преобразования IP в hostname будем использовать DNS, описывается ето в конфигурационном файле lightsquid.cfg строчкой:

$ip2name=«dns»;

Парсер перечитывает файлы realname.cfg и group.cfg и берет оттуда реальные имена юзеров, привязаных к хостам. Формат файлов такой:

realname.cfg:
«hostname» «real name»

group.cfg:
«hostname» «group number» «group name»

Что нам надо?


Надо взять с АД хосты, имена юзеров привязаных к хостам, группы в каких содержатся юзеры; потом пишем всё ето в конфигурационные файлы в соответственном формате.

Вот собственно скрипт, который ето делает:

#!/usr/local/bin/perl
#
# ldap2lightsquid (c) Roman Melko <romanmelko@gmail.com>
# Description:  Synchronize users and computers of LightSquid with LDAP server
# Requirements: Should run periodically
# Version:      2012030601
# License:      BSD
#

use strict;
use Net::LDAP;

my $domain = "example.ua"; # Domain is supposed to have 2 levels
my @parts = split(/\./,$domain);
my $domain0 = $parts[1];
my $domain1 = $parts[0];
my $user = "<username>"; # LDAP user
my $password = "<password>"; # LDAP password
my $cfgpath = "/usr/local/etc/lightsquid/"; # depends on OS
my $realname = "$cfgpath/realname.cfg";
my $group = "$cfgpath/group.cfg";
# departments OU
my @units = (
        "MGT",
        "OPR",
        "PRO",
        "Sales
");
# computers OU
my @pcunits = (
        "Developer servers",
        "Servers",
        "Workstation OPR",
        "Workstations PRO",
        "Workstations Sales",
        "Workstations Telemarketing"
);
my @dep = ("no in group");
my $ldap = Net::LDAP->new("$domain") or die "$0";
$ldap->bind("CN=$user,DC=$domain1,DC=$domain0", password=>$password);
my $base_path = "OU=<some path>,OU=<some path>,DC=$domain1,DC=$domain0"; # base LDAP path, change to yours
my $num = @units;
my $pcnum = @pcunits;
my $attrs = "sn, givenname, department, samaccountname";
my $filter = "(objectcategory=CN=Person,CN=Schema,CN=Configuration,DC=$domain1,DC=$domain0)";
my $pcattrs = "cn, managedBy";
my $pcfilter = "(objectcategory=CN=Computer,CN=Schema,CN=Configuration,DC=$domain1,DC=$domain0)";
my $count;
my $results;
my %department_id = ();
my %department_name = ();

sub get_host_info {
        for (my $i=0; $i<$count; $i++) {
                my $entry = $results->entry($i);
                my $hostname = join(".",lc($entry->get_value('cn')),$domain);
                my @tmp_array = split(/,/,$entry->get_value('managedBy'));
                @tmp_array = split(/=/,$tmp_array[0]);
                my $fullname = $tmp_array[1];
                if(!$fullname) {
                        next;
                }
                print(REALNAME "$hostname\t$fullname\n");
                print(GROUP "$hostname\t$department_id{$fullname}\t$department_name{$fullname}\n");
        }
}

sub get_user_info {
        for (my $i=0; $i<$count; $i++) {
                my $entry = $results->entry($i);
                my $depnum = @dep;
                my $depid = $depnum;
                $depid++;
                foreach $depnum (0 .. @dep) {
                        if ($entry->get_value('department') eq $dep[$depnum]) {
                                $depid = $depnum;
                        }
                }
                if ($depid > $depnum) {
                        $dep[$depid] = $entry->get_value('department');
                }
                if (length $depid < 2) {
                        $depid = "0".$depid;
                }
                my $name = $entry->get_value('givenname');
                my $surname = $entry->get_value('sn');
                $name =~ s/^\s+//;
                $name =~ s/\s+$//;
                $surname =~ s/^\s+//;
                $surname =~ s/\s+$//;
                my $fullname = join(" ",$name,$surname);
                $department_id{$fullname} = $depid;
                $department_name{$fullname} = $entry->get_value('department');
        }
}

open (REALNAME, ">", $realname) or die $!;
open (GROUP, ">", $group) or die $!;

# Getting real names and departments

foreach $num (0 .. @units) {
        my $base = 'OU='.$units[$num].','.$base_path;
        $results = $ldap->search(base=>$base,filter=>$filter,attrs=>$attrs);
        $count = $results->count;
        if ($count > 0) {
                get_user_info();
        }
}

# Getting pc names and owners, writing results to conf files

foreach $pcnum (0 .. @pcunits) {
        my $base = 'OU='.$pcunits[$pcnum].',OU=Resources,'.$base_path;
        $results = $ldap->search(base=>$base,filter=>$pcfilter,attrs=>$pcattrs);
        $count = $results->count;
        if ($count > 0) {
                get_host_info();
        }
}

# Closing connection to LDAP and files

$ldap->unbind;
close (REALNAME);
close (GROUP);

exit 0


Важные моменты:
— в каждом хосте в АД должно быть заполнено поле managedby, так привязывается хост к юзеру;
— в каждого юзера в АД должно быть заполнено поле department, так привязывается юзер к группе (у меня пока что так, до реальных групп руки не дошли, так как у меня один юзер может принадлежать к многим группам с похожыми именами);
— units и pcunits вы должны заполнить сами своими данными;
— скрипт должен выполняться периодически, например в cron;
— юзер, под каким осуществляется доступ скрипта в AD, должен быть в корне AD, по другому меня не пускало;
— для того чтобы заставить работать скрипт с стандартной базой LDAP курите маны, там есть различия с АД.

+4
10.8k 42
Comments 14