BindOpenldap

18
Introdução Todos que trabalham com redes mistas, Windows e GNU/Linux , sabem que sempre há problemas com interoperabilidade entre elas no que diz respeito à base de usuários OpenLDAP, LDAP AD, Active Directory etc, já que algumas soluções trabalham com autenticação padrão, que pode ser tanto o LDAP do AD quanto OpenLDAP, enquanto outras são mais específicas. Especificamente, abordarei um cenário contendo Active Directory e OpenLDAP. Veremos como fazer a sincronização das bases para que, quando criarmos um usuário ou grupo, este será criado tanto na base OpenLDAP quanto na base Active Directory, também, posteriores alterações como mudança de grupos, nomes, descrição devem ser sincronizadas entre as bases deixando-as consistentes. Estudo de caso Este é o cenário apresentado: Um servidor Active Directory Windows 2008 Server (AD01); Um servidor OpenLDAP (LX01). O servidor Active Directory (AD01) pode fazer todos os serviços para a rede Microsoft funcionar com domínio, DNS, PDC etc, ou seja, uma rede Microsoft normal que é muito implementada. Teremos o servidor OpenLDAP que pode ser utilizado para qualquer aplicação que suporte consultas LDAP, tendo, como exemplo, a mais comum delas: um proxy Squid. Na prática, com a sincronização de bases, quando criarmos o usuário "evandro.nabor" na base OpenLDAP, o usuário será replicado para o AD01. Existe uma consideração a ser feita a respeito das senhas, pois não é possível ler a senha digitada pelo usuário no OpenLDAP e escrevê-la no Active Directory, mas este assunto será abordado mais a frente. Sendo assim, após o cenário implementado, teremos a criação de um único usuário com a mesma senha, tanto para domínio quanto para outras aplicações, como o já citado proxy. Solução Tratarei a sincronização neste sentido: OpenLDAP Active Directory Portanto, os usuários a partir de agora, deverão ser criados na base OpenLDAP para serem sincronizados para o AD01. O software para isso é o LSC , que faz vários tipos de sincronização entre bases LDAP e outras. Basicamente, ele será encarregado de testar todos os atributos configurados e efetuar a sincronização. Dados do cenário: LX01: OpenLDAP e LSC - Debian Squeeze - 172.31.1.28 AD01: Active Directory - Windows 2008 Server - 172.31.1.99 Instalação e configuração Não abordarei a instalação do Active Directory e nem do OpenLDAP, pois existem centenas de artigos a respeito na internet. AD01 Crie um usuário com privilégio administrador chamado LSC no Active Directory, o programa irá usá-lo para as importações. Instalar o serviço de Active Directory Certificate Services e exportar uma chave para utilizarmos no GNU/Linux : Configuring an SSL Certificate for Microsoft Active Directory « confluence.atlassian.com Object 1

Transcript of BindOpenldap

Page 1: BindOpenldap

IntroduçãoTodos que trabalham com redes mistas, Windows e GNU/Linux, sabem que sempre há problemas com interoperabilidade entre elas no que diz respeito à base de usuários OpenLDAP, LDAP AD, Active Directory etc, já que algumas soluções trabalham com autenticação padrão, que pode ser tanto o LDAP do AD quanto OpenLDAP, enquanto outras são mais específicas.

Especificamente, abordarei um cenário contendo Active Directory e OpenLDAP.

Veremos como fazer a sincronização das bases para que, quando criarmos um usuário ou grupo, este será criado tanto na base OpenLDAP quanto na base Active Directory, também, posteriores alterações como mudança de grupos, nomes, descrição devem ser sincronizadas entre as bases deixando-as consistentes.

Estudo de casoEste é o cenário apresentado:

• Um servidor Active Directory Windows 2008 Server (AD01);• Um servidor OpenLDAP (LX01).

O servidor Active Directory (AD01) pode fazer todos os serviços para a rede Microsoft funcionar com domínio, DNS, PDC etc, ou seja, uma rede Microsoft normal que é muito implementada.

Teremos o servidor OpenLDAP que pode ser utilizado para qualquer aplicação que suporte consultas LDAP, tendo, como exemplo, a mais comum delas: um proxy Squid.

Na prática, com a sincronização de bases, quando criarmos o usuário "evandro.nabor" na base OpenLDAP, o usuário será replicado para o AD01. Existe uma consideração a ser feita a respeito das senhas, pois não é possível ler a senha digitada pelo usuário no OpenLDAP e escrevê-la no Active Directory, mas este assunto será abordado mais a frente.

Sendo assim, após o cenário implementado, teremos a criação de um único usuário com a mesma senha, tanto para domínio quanto para outras aplicações, como o já citado proxy.

SoluçãoTratarei a sincronização neste sentido: OpenLDAP Active Directory→

Portanto, os usuários a partir de agora, deverão ser criados na base OpenLDAP para serem sincronizados para o AD01.

O software para isso é o LSC, que faz vários tipos de sincronização entre bases LDAP e outras.

Basicamente, ele será encarregado de testar todos os atributos configurados e efetuar a sincronização.

Dados do cenário:

• LX01: OpenLDAP e LSC - Debian Squeeze - 172.31.1.28• AD01: Active Directory - Windows 2008 Server - 172.31.1.99

Instalação e configuraçãoNão abordarei a instalação do Active Directory e nem do OpenLDAP, pois existem centenas de artigos a respeito na internet.

AD01Crie um usuário com privilégio administrador chamado LSC no Active Directory, o programa irá usá-lo para as importações.

Instalar o serviço de Active Directory Certificate Services e exportar uma chave para utilizarmos no GNU/Linux:

• Configuring an SSL Certificate for Microsoft Active Directory « confluence.atlassian.com

Object 1

Page 2: BindOpenldap

LX01Java:

# cd /usr/src# wget http://javadl.sun.com/webapps/download/AutoDL?BundleId=73850 -O java.tar.gz -O java.tar.gz# tar zxvf java.tar.gz# mv jre1.7.0_13 /usr/local/java# export JAVA_HOME=/usr/local/java && echo "export JAVA_HOME=/usr/local/java" >> ~/.bashrc

Certificado:

# $JAVA_HOME/bin/keytool -import -keystore $JAVA_HOME/lib/security/cacerts -file ChaveDoWin2008.crt

Obs.: Quando for solicitada, a senha padrão é: changeit

LSC# cd /usr/src# wget http://tools.lsc-project.org/attachments/download/317/lsc-core-1.2.2-dist.tar.gz# tar zxvf lsc-core-1.2.2-dist.tar.gz# mv lsc-1.2.2/ /usr/local/lsc && cd /usr/local/lsc

O arquivo de configuração do LSC é o etc/lsc.properties.

Este é um exemplo que montei para fazer a sincronia do nosso cenário. Você deverá modificá-lo conforme suas necessidades. Todas as documentações são encontradas na página do LSC, mas de qualquer maneira, este arquivo foi extremamente comentado por min:

#/usr/local/lsc/etc/lsc.properties# Evandro Nabor################# Origem ################## base OpenLDAPsrc.java.naming.security.principal=cn=Manager,dc=texas,dc=localsrc.java.naming.security.credentials=3v4ndrOsrc.java.naming.security.authentication=simplesrc.java.naming.referral=ignoresrc.java.naming.provider.url=ldap://172.31.1.28/dc=texas,dc=localsrc.java.naming.ldap.version=3src.java.naming.ldap.derefAliases=neversrc.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory

###################### Destino ####################### base ActiveDirectory# repare que utilizo SSL com exportacao do certificado do AD e importacao pro java do linuxdst.java.naming.security.principal=CN=LSC,CN=Users,DC=texas,DC=localdst.java.naming.security.credentials=3v4ndrOdst.java.naming.security.authentication=simpledst.java.naming.referral=ignoredst.java.naming.provider.url=ldaps://172.31.1.99/DC=texas,DC=localdst.java.naming.ldap.version=3dst.java.naming.ldap.derefAliases=neverdst.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactorydst.java.naming.ldap.pageSize = 1000#dst.java.naming.tls = true

################## Tarefas ###################definindo tarefa para sincronia de usuarioslsc.tasks=user#definindo tarefa para sincronia de gruposlsc.tasks=group

Page 3: BindOpenldap

### User ####opcoes de permissao para update, deletar e criar em ambas as baseslsc.tasks.user.condition.create = 1lsc.tasks.user.condition.update = 1lsc.tasks.user.condition.delete = 1lsc.tasks.user.condition.modrdn = 1

#esta opcao serve pra decidir como sera criado o usuario no activedirectory. ex. cn=evandro.nabor,cn=users,dc=texas,dc=locallsc.tasks.user.bean=org.lsc.beans.SimpleBeanlsc.tasks.user.dn = "CN=" + srcBean.getAttributeValueById("uid") + ",CN=Users"

# Source#opcoes de selecao dos usurios no ldap, perceba os filtros para que o programa funciona dos dois lados, tanto quando cria um usuario e ele eh replicado pra o#AD quanto pra quando deleta um usuario ele compara as duas bases e deleta o usuario no ADlsc.tasks.user.srcService=org.lsc.jndi.SimpleJndiSrcServicelsc.tasks.user.srcService.filterAll=(&(objectClass=inetOrgPerson)(uid=*)(!(givenName=MailList)))lsc.tasks.user.srcService.filterId = (&(objectClass=inetOrgPerson)(|(uid={uid})(uid={sAMAccountName})))lsc.tasks.user.srcService.baseDn=ou=pessoas# campos que serao replicados, eh importante colocar todos que serao replicados e mais tarde nas opcoes de sincronia definir como sera a sincronialsc.tasks.user.srcService.attrs= uid sambaLogonScript homeDirectory postalCode postOfficeBox# campo de volta, eh a pesquisa reversa que ele faz para que quando seja deletado algum usuario do OpenLDAP ele seja tambem deletado do ADlsc.tasks.user.srcService.pivotAttrs = uid

# Destination# opcoes para selecao de usuarios no AD repare que filtro algumas contas padrao do windows para q elas nunca sofrao alteracoes e nao tenha problemalsc.tasks.user.dstService=org.lsc.jndi.SimpleJndiDstServicelsc.tasks.user.dstService.baseDn=cn=Users# idem sourcelsc.tasks.user.dstService.attrs = sAMAccountName userAccountControl objectClass userPrincipalName pwdLastSet scriptPath homeDirectory displayName givenName unicodePwdlsc.tasks.user.dstService.filterAll=(&(sAMAccountName=*)(objectClass=user)(!(sAMAccountName=Administrator))(!(sAMAccountName=Guest))(!(sAMAccountName=krbtgt))(!(sAMAccountName=LSC)))lsc.tasks.user.dstService.filterId = (&(objectClass=user)(sAMAccountName={uid}))# idem sourcelsc.tasks.user.dstService.pivotAttrs = sAMAccountName

### Group #### tarefa para sincronizar grupos#regras de update, criar e deletarlsc.tasks.group.condition.create = 1lsc.tasks.group.condition.update = 1lsc.tasks.group.condition.delete = 1lsc.tasks.group.condition.modrdn = 1

# como sera criado o grupo no AD, ex. cn=IT,cn=users,dc=texas,dc=locallsc.tasks.group.dn = "CN=" + srcBean.getAttributeValueById("cn") + ",CN=Users"lsc.tasks.group.bean=org.lsc.beans.SimpleBean

# Source# opcoes para selecao de grupos no OpenLDAP, repare os filtros para alguns grupos nunca sejam replicados pro AD como Domain Users, para nao confindir com os padroes do Win.lsc.tasks.group.srcService=org.lsc.jndi.SimpleJndiSrcServicelsc.tasks.group.srcService.filterAll = (&(objectClass=posixGroup)(cn=*)(!(cn=Print Operators))(!(cn=Backup Operators))(!(cn=Administrators))(!(cn=Domain Users))(!(cn=Admins))(!(cn=Default))(!(cn=Domain Admins))(!(cn=Domain Computers))(!(cn=Domain Guests))(!(cn=Replicators))(!(cn=Account Operators)))lsc.tasks.group.srcService.filterId = (&(objectClass=posixGroup)(cn={cn}))lsc.tasks.group.srcService.baseDn=ou=Gruposlsc.tasks.group.srcService.attrs=cn objectClass memberUid

Page 4: BindOpenldap

lsc.tasks.group.srcService.pivotAttrs = cn

# Destination# opcpes para o destino, mesmo padrao de selecao para q os grupos default do Win nao sejam deletadoslsc.tasks.group.dstService=org.lsc.jndi.SimpleJndiDstServicelsc.tasks.group.dstService.baseDn=cn=Userslsc.tasks.group.dstService.attrs = cn objectClass member sAMAccountNamelsc.tasks.group.dstService.pivotAttrs = cnlsc.tasks.group.dstService.filterAll = (&(objectClass=group)(sAMAccountName=*)(!(sAMAccountName=DnsAdmins))(!(sAMAccountName=DnsUpdateProxy))(!(sAMAccountName=Domain Computers))(!(sAMAccountName=Domain Controllers))(!(sAMAccountName=Schema Admins))(!(sAMAccountName=Enterprise Admins))(!(sAMAccountName=Cert Publishers))(!(sAMAccountName=Domain Admins))(!(sAMAccountName=Domain Users))(!(sAMAccountName=Domain Guests))(!(sAMAccountName=Group PolicyCreator Owners))(!(sAMAccountName=RAS and IAS Servers))(!(sAMAccountName=Allowed RODC Password Replication Group))(!(sAMAccountName=Denied RODC Password Replication Group))(!(sAMAccountName=Read-only Domain Controllers))(!(sAMAccountName=Enterprise Read-only Domain Controllers)))lsc.tasks.group.dstService.filterId = (&(objectClass=group)(cn={cn}))

###################### Syncoptions ####################### opcoes de sicronia, ou seja, quais campos serao sincornizados entre bases e se eh necessario algum remanejamento de campo, ou incluir texto,# ex. o campo de script de logon no ldap do AD chama-se scriptPath no openldap chama-se sambaLogonScript portanto# eh preciso fazer um mapemaento para que o campo sambaLogonScript do OpenLDAP seja escrito no scriptPath do AD.

# OpenLDAP -> AD### User ###lsc.syncoptions.user = org.lsc.beans.syncoptions.PropertiesBasedSyncOptionslsc.syncoptions.user.default.action = Flsc.syncoptions.user.objectClass.action = F# o que inserir de atributoslsc.syncoptions.user.objectClass.force_value = "top";"user";"person";"organizationalPerson"# uid -> DisplayNamelsc.syncoptions.user.displayName.create_value = srcBean.getAttributeValueById("uid")# uid -> givenNamelsc.syncoptions.user.givenName.create_value = srcBean.getAttributeValueById("uid")# uid -> sAMAccountNamelsc.syncoptions.user.sAMAccountName.create_value = srcBean.getAttributeValueById("uid")# sambaLogonScript -> scriptPathlsc.syncoptions.user.scriptPath.action = Flsc.syncoptions.user.scriptPath.force_value = srcBean.getAttributeValueById("postalCode")# uid -> userPrincipalNamelsc.syncoptions.user.userPrincipalName.force_value = srcBean.getAttributeValueById("uid") + "@texas.local"# homeDirectory -> homeDirectorylsc.syncoptions.user.homeDirectory.action = Flsc.syncoptions.user.homeDirectory.force_value = srcBean.getAttributeValueById("postOfficeBox")# opcoes de controle do ADlsc.syncoptions.user.userAccountControl.create_value = AD.userAccountControlSet( "0", [ AD.UAC_SET_PASSWD_NOTREQD,AD.UAC_SET_NORMAL_ACCOUNT ])# password nao precisa ser mudado no proximo logonlsc.syncoptions.user.pwdLastSet.create_value = "-1"# senha padrao setada na importacao do usuario do OpenLDAP pro ADlsc.syncoptions.user.unicodePwd.action = Flsc.syncoptions.user.unicodePwd.create_value = AD.getUnicodePwd("3v4ndrO")

### Group ### # opcoes de sincronia para gruposlsc.syncoptions.group = org.lsc.beans.syncoptions.PropertiesBasedSyncOptions# nome do grupo# cn -> sAMAccountNamelsc.syncoptions.group.sAMAccountName.create_value = srcBean.getAttributeValueById("cn")lsc.syncoptions.group.default.action = F# atributos de grupo

Page 5: BindOpenldap

lsc.syncoptions.group.objectClass.force_value = "top";"group"# membro dos grupos, eh um javascript que entra dentro dos grupos do OpenLDAP e busca usuarios# e replica para o determinado grupo no ADlsc.syncoptions.group.member.delimiter = $lsc.syncoptions.group.member.force_value = \ var umembers = \ srcBean.getAttributeValuesById("memberUid").toArray() ; \ for (var i=0; i p\try { \ umembers[i] = ldap.attribute(ldap.list("CN=Users","(sAMAccountName=" + (umembers[i]) + ")").get(0), 'distinguishedName').get(0) \ } catch (e) { \ umembers[i]=null; \ } \ } \ var members = new Array(); \ var j=0; \ for (var i=0; i<umembers.length; i++) { \ if (umembers[i]!=null) members[j++]=umembers[i]; \ } \ members;

OpenLDAPPara exemplificar, criei uma base com seis usuários e três grupos, insira o conteúdo em um arquivo ldif e importe para dentro do seu servidor LDAP:

# baseteste.ldifdn: dc=texas,dc=localobjectClass: topobjectClass: dcObjectobjectClass: organizationdc: texaso: Texas LDAP

dn: ou=pessoas,dc=texas,dc=localobjectClass: topobjectClass: organizationalUnitou: pessoas

dn: ou=grupos,dc=texas,dc=localou: gruposobjectClass: organizationalUnitobjectClass: top

dn: uid=enabor,ou=pessoas,dc=texas,dc=localobjectClass: posixAccountobjectClass: topobjectClass: inetOrgPersongidNumber: 0givenName: evandrosn: nabordisplayName: enaboruid: enaborhomeDirectory: /home/enaborcn: enaboruidNumber: 27635

dn: uid=sman,ou=pessoas,dc=texas,dc=localobjectClass: posixAccountobjectClass: topobjectClass: inetOrgPersongidNumber: 0givenName: supersn: man

Page 6: BindOpenldap

displayName: smanuid: smanhomeDirectory: /home/smancn: smanuidNumber: 10548

dn: uid=lluthor,ou=pessoas,dc=texas,dc=localobjectClass: posixAccountobjectClass: topobjectClass: inetOrgPersongidNumber: 0givenName: lexsn: luthordisplayName: lluthoruid: lluthorhomeDirectory: /home/lluthorcn: lluthoruidNumber: 37975

dn: uid=lverde,ou=pessoas,dc=texas,dc=localobjectClass: posixAccountobjectClass: topobjectClass: inetOrgPersongidNumber: 0givenName: lanternasn: verdedisplayName: lverdeuid: lverdehomeDirectory: /home/lverdecn: lverdeuidNumber: 24873

dn: uid=bwayne,ou=pessoas,dc=texas,dc=localobjectClass: posixAccountobjectClass: topobjectClass: inetOrgPersongidNumber: 0givenName: brucesn: waynedisplayName: bwayneuid: bwaynehomeDirectory: /home/bwaynecn: bwayneuidNumber: 25788

dn: cn=it,ou=grupos,dc=texas,dc=localobjectClass: posixGroupobjectClass: topcn: itmemberUid: enabormemberUid: bwaynememberUid: smangidNumber: 58946

dn: cn=managers,ou=grupos,dc=texas,dc=localobjectClass: posixGroupobjectClass: topcn: managersgidNumber: 61470memberUid: lluthormemberUid: lverdeIniciando a sincronização

Para iniciar a sincronização, acesse /usr/local/lsc e execute o comando:

# bin/lsc -f etc/ -s all -c all

Se tudo ocorrer bem, a saída deverá ser igual a essa:

Page 7: BindOpenldap

Feb 04 22:02:59 - INFO - Starting sync for userFeb 04 22:02:59 - INFO - Connecting to LDAP server ldap://172.31.1.28/dc=texas,dc=local as cn=Manager,dc=texas,dc=localFeb 04 22:03:00 - INFO - Connecting to LDAP server ldaps://172.31.1.99/DC=texas,DC=local as CN=LSC,CN=Users,DC=texas,DC=localFeb 04 22:03:01 - INFO - # Adding new entry CN=lverde,CN=Users for userdn: CN=lverde,CN=Users,DC=texas,DC=localchangetype: adduserPrincipalName: [email protected]: -1sAMAccountName: lverdeunicodePwd:: IgAzAHYANABuAGQAcgBPACIAuserAccountControl: 544objectClass: organizationalPersonobjectClass: personobjectClass: userobjectClass: topgivenName: lverdedisplayName: lverde

Feb 04 22:03:01 - INFO - # Adding new entry CN=bwayne,CN=Users for userdn: CN=bwayne,CN=Users,DC=texas,DC=localchangetype: adduserPrincipalName: [email protected]: -1sAMAccountName: bwayneunicodePwd:: IgAzAHYANABuAGQAcgBPACIAuserAccountControl: 544objectClass: organizationalPersonobjectClass: personobjectClass: userobjectClass: topgivenName: bwaynedisplayName: bwayne

Feb 04 22:03:01 - INFO - # Adding new entry CN=lluthor,CN=Users for userdn: CN=lluthor,CN=Users,DC=texas,DC=localchangetype: adduserPrincipalName: [email protected]: -1sAMAccountName: lluthorunicodePwd:: IgAzAHYANABuAGQAcgBPACIAuserAccountControl: 544objectClass: organizationalPersonobjectClass: personobjectClass: userobjectClass: topgivenName: lluthordisplayName: lluthor

Feb 04 22:03:02 - INFO - # Adding new entry CN=sman,CN=Users for userdn: CN=sman,CN=Users,DC=texas,DC=localchangetype: adduserPrincipalName: [email protected]: -1sAMAccountName: smanunicodePwd:: IgAzAHYANABuAGQAcgBPACIAuserAccountControl: 544objectClass: organizationalPersonobjectClass: personobjectClass: userobjectClass: topgivenName: smandisplayName: sman

Feb 04 22:03:02 - INFO - # Adding new entry CN=enabor,CN=Users for userdn: CN=enabor,CN=Users,DC=texas,DC=localchangetype: adduserPrincipalName: [email protected]: -1sAMAccountName: enabor

Page 8: BindOpenldap

unicodePwd:: IgAzAHYANABuAGQAcgBPACIAuserAccountControl: 544objectClass: organizationalPersonobjectClass: personobjectClass: userobjectClass: topgivenName: enabordisplayName: enabor

Feb 04 22:03:02 - INFO - All entries: 5, to modify entries: 5, modified entries: 5, errors: 0Feb 04 22:03:02 - INFO - Starting clean for userFeb 04 22:03:02 - INFO - All entries: 5, to modify entries: 0, modified entries: 0, errors: 0Feb 04 22:03:02 - INFO - Starting sync for groupFeb 04 22:03:02 - INFO - # Adding new entry CN=it,CN=Users for groupdn: CN=it,CN=Users,DC=texas,DC=localchangetype: addmember: CN=bwayne,CN=Users,DC=texas,DC=localmember: CN=enabor,CN=Users,DC=texas,DC=localmember: CN=sman,CN=Users,DC=texas,DC=localcn: itsAMAccountName: itobjectClass: groupobjectClass: top

Feb 04 22:03:02 - INFO - # Adding new entry CN=managers,CN=Users for groupdn: CN=managers,CN=Users,DC=texas,DC=localchangetype: addmember: CN=lverde,CN=Users,DC=texas,DC=localmember: CN=lluthor,CN=Users,DC=texas,DC=localcn: managerssAMAccountName: managersobjectClass: groupobjectClass: top

Feb 04 22:03:02 - INFO - All entries: 2, to modify entries: 2, modified entries: 2, errors: 0Feb 04 22:03:02 - INFO - Starting clean for groupFeb 04 22:03:02 - INFO - All entries: 2, to modify entries: 0, modified entries: 0, errors: 0

Consulte o Active Directory e verá que os usuários e grupos foram criados na base.

Caso a saída apresente erros, fique atento para as configurações no arquivo "lsc.properties" e com a questão do certificado, pois perceba que estou sempre utilizando LDAPS para acessar o AD.

Senhas

O único problema da solução é com relação às senhas, pois não é possível empurrar os Hashs dos usuários do OpenLDAP para dentro do Active Directory, já que este usa um tipo diferente de Hash. Também não é possível ler senhas do Active Directory.

A solução que encontrei para este caso, foi a padronização de uma tela para os usuários alterarem suas senhas. Esta tela pode ser uma página em PHP que insira o Hash da senha digitada, tanto na base OpenLDAP quanto no Active Directory.

Existem muitos tutoriais sobre como desenvolver uma página desse tipo para inserir a senha no OpenLDAP. Para o Active Directory, chame esse script em sua página com os devidos parâmetros (créditos a: www.barncrew.com) que ele irá inserir a senha de maneira correta na base:

# chpass_ad.pl## Para usar: ./chpass_ad.pl usuario senha##!/usr/bin/perl -w

use Net::LDAP;use Unicode::String qw(utf8);

# ARGV dos parametros usuario e senhamy $username = $ARGV[0];

Page 9: BindOpenldap

my $passwd = $ARGV[1];

### ActiveDirectory Servermy $adsvr='172.31.1.99';my $adbinddn='cn=LSC,cn=users,dc=texas,dc=local';my $adpw='3v4ndrO';

########## ActiveDirectory ############## Conecta do ADmy $ad=Net::LDAP->new($adsvr, version => 3, scheme => 'ldaps', port => 636, )or die "nao eh possivel conectar $adsvr: $@";

# faz a busca com o usuario passado$result=$ad->bind($adbinddn, password=>$adpw);

# procura o usuario q sera trocada senha$result = $ad->search( base => "cn=users,dc=texas,dc=local", filter => "(samAccountName=$username)", attrs => ['distinguishedName'] );

$result->code && die $result->error;if ($result->entries != 1 ) { die "ERRO: Usuario nao encontrado no AD: $username" };

my $entry = $result->entry(0);my $dnad = $entry->get_value('distinguishedName');my $unicodePwd = utf8(chr(34).$passwd.chr(34))->utf16le();

# muda a senha !$result = $ad->modify($dnad, replace => { unicodePwd => $unicodePwd, });

$result->code && die $result->error;print "AD : FEITO: ${username} password mudado.\n";

$ad->unbind();

ConclusãoA solução proposta é capaz de resolver problemas em redes que precisam de centralização de usuários quando a necessidade de operação com bases diferentes é imprescindível.

Os parâmetros usados nos programas envolvidos foram preparados para o cenário proposto, mas, posteriores alterações podem e devem ser feitas para correta implementação em um ambiente de produção.

Introdução

A ideia principal do artigo é a centralização do ambiente em uma base única, no caso uma das melhores o Ldap. Imaginemos o cenário, uma empresa denominada Acme Lun, fará seu atual servidor de DNS(Bind), em vez de consultar as zonas em arquivos locais (.db), consultar em uma base LDAP.

Partirei do princípio que já temos um servidor LDAP operante e um DNS Bind com suas zonas prontas, e mais um servidor no qual faremos o novo Bind. Utilizei Debian 5 em todas as maquinas.

Page 10: BindOpenldap

Compilando o BIND com suporte ao LDAPO bind dos repositórios não vem com suporte ao LDAP, então não adianta instalá-lo com apt-get que este não funcionará, portanto teremos de compilar do fonte ativando então o suporte a LDAP.

Comecemos baixando o fonte do bind9 e o back-end bind-ldap.

Bind9:ftp://ftp.epix.net/pub/isc/bind9/9.7.1rc1/bind-9.7.1rc1.tar.gz

Back-End ldap sdb:http://bind9-ldap.bayour.com/bind-sdb-ldap-1.0.tar.gz

# cd /root# mkdir -p bind/tars# cd bind/tars# wget ftp://ftp.epix.net/pub/isc/bind9/9.7.1rc1/bind-9.7.1rc1.tar.gz # wget http://bind9-ldap.bayour.com/bind-sdb-ldap-1.0.tar.gz # tar -zxvf bind-sdb-ldap-1.0.tar.gz# tar -zxvf bind-9.7.1rc1.tar.gz# mv bind-* ..

Copiando os arquivos necessários para a compilação com suporte a LDAP:

# cd /root/bind-sdb-ldap-1.0# cp ldapdb.c ../bind-9.7.1rc1/bin/named/# cp ldapdb.h ../bind-9.7.1rc1/bin/named/include/

Agora faremos alterações em alguns arquivos antes de compilar:

# cd /root/bind/bind-9.7.1rc1/bin/named/# vim(rules!) Makefile.in

Procure pelas linhas e altere-as deixando como mostrado abaixo:

DBDRIVER_OBJS = ldapdb.@O@DBDRIVER_SRCS = ldapdb.cDBDRIVER_INCLUDES = -I/usr/local/includeDBDRIVER_LIBS = -L/usr/local/lib -lldap -llber -lresolv

No mesmo diretório do Makefile.in, edite o arquivo main.c.

Procure pela linha que contem /* #include "xxdb.h" */ e adicione logo abaixo dela #include <ldapdb.h>.

No mesmo arquivo procure a linha /* xxdb_init(); */ substitua por ldapdb_init();

Por último procure a linha /* xxdb_clear(); */ e substitua por ldapdb_clear();

Salve o arquivo e feche-o.

Agora estamos prontos para compilar o bind com suporte a nova base.

Antes de iniciarmos certifique-se que tem os pacotes necessários instalados:

# apt-get install gcc make libldap2-dev openssl libssl-dev

Feito isso proceda:

# cd /root/ bind-9.7.1rc1/# ./configure --with-openssl=/usr --disable-ipv6# make# make install

Ok, temos o bind instalado, agora precisamos acertar configurações e diretórios.

Sempre preferi trabalhar com o bind no conceito de chroots para aumentar a segurança, então, vamos configurar a gaiola.

Page 11: BindOpenldap

Criando a chroot

Criar diretórios:

# mkdir -p /chroot/named# cd /chroot/named # mkdir dev etc logs# mkdir -p var/run# mkdir - p conf/secondaries

Trazer o arquivo timezone para a chroot:

# cp /etc/localtime /chroot/named/etc

Criar os nodes:

# mknod /chroot/named/dev/null c 1 3# mknod /chroot/named/dev/zero c 1 5# mknod /chroot/named/dev/random c 1 8

Criar um usuário e grupo para o bind:

# groupadd named# useradd -g named -d /chroot/named -s /bin/true named# passwd -l named

Montando os arquivos de configuraçãoPrimeiro criaremos o named.conf, que é o arquivo principal do bind, repare que as zonas de root servers e as outras zonas padrões ficaram na própria máquina, ou seja, não consultará no ldap.

# vim /chroot/named/etc/named.conf

Por hora adicione este conteúdo dentro do arquivo:

options { directory "/conf"; pid-file "/var/run/named.pid"; statistics-file "/var/run/named.stats"; dump-file "/var/run/named.db"; empty-zones-enable no;

# esconda sua "verdadeiro" numero de versao version "[seguro]";};

# root serverszone "." { type hint; file "db.rootcache";};

# localhost - zona de encaminhamentozone "localhost" { type master; file "db.localhost"; notify no;};

# localhost - zona reversazone "0.0.127.in-addr.arpa" { type master; file "db.127.0.0"; notify no;};

Page 12: BindOpenldap

Cria também um link simbólico do named.conf para o /etc para facilitar administração:

# ln -sf /chroot/named/etc/named.conf /etc/named.conf

Perceba que nosso named.conf aponta para três arquivos:

• db.127.0.0• db.localhost• db.rootcache

Criaremos agora eles, então a começar pelo db.rootcache.

Se a máquina que estamos instalando tem acesso a internet, ele pode ser criado com o comando:

# dig @a.root-servers.net . ns > /chroot/named/conf/db.rootcache

Criando os outros dois:

# vim /chroot/named/conf/db.127.0.0

E cole o conteúdo:

; db.127.0.0

$TTL 86400@ IN SOA localhost. root.localhost. ( 1 ; Serial 28800 ; Refresh 14400 ; Retry 3600000 ; Expire 86400 ) ; Minimum IN NS localhost.1 IN PTR localhost.

Salve e feche o arquivo.

# vim /chroot/named/conf/db.localhost

e cole o conteúdo:

; db.localhost

$TTL 86400

@ IN SOA @ root ( 42 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum

IN NS @ IN A 127.0.0.1

Salve e feche o arquivo.

Checando permissões no CHROOTEste script gerencia perfeitamente todas as permissões que precisamos dentro do diretório chroot.

# verifica.permissoes

cd /chroot/named

Page 13: BindOpenldap

chown -R root.named .

find . -type f -print | xargs chmod u=rw,og=r # regular filesfind . -type d -print | xargs chmod u=rwx,og=rx # directories

chmod o= etc/*.conf

touch conf/secondaries/.empty # placeholderfind conf/secondaries/ -type f -print | xargs chown named.namedfind conf/secondaries/ -type f -print | xargs chmod ug=r,o=

chown root.named conf/secondaries/chmod ug=rwx,o= conf/secondaries/

chown root.root var/chmod u=rwx,og=x var/

chown root.named var/run/chmod ug=rwx,o=rx var/run/

chown root.named logs/chmod ug=rwx,o=rx logs/

Copie o conteúdo acima e cole num arquivo novo em /chroot/verifica.permissoes.

Agora é só executarmos:

# sh -x /chroot/verifica.permissoes

A saída será algo como:

+ cd /chroot/named+ chown -R root.named .+ find . -type f -print+ xargs chmod u=rw,og=r+ find . -type d -print+ xargs chmod u=rwx,og=rx+ chmod o= etc/named.conf etc/rndc.conf+ touch conf/secondaries/.empty+ find conf/secondaries/ -type f -print+ xargs chown named.named+ find conf/secondaries/ -type f -print+ xargs chmod ug=r,o=+ chown root.named conf/secondaries/+ chmod ug=rwx,o= conf/secondaries/+ chown root.root var/+ chmod u=rwx,og=x var/+ chown root.named var/run/+ chmod ug=rwx,o=rx var/run/

Agora as permissões dos nossos diretórios estão todas ok.

Script para inicialização do serviço:

#start.named

cd /chroot/named

touch named.runchown named.named named.runchmod ug=rw,o=r named.run

PATH=/usr/local/sbin:$PATH named \ -t /chroot/named \

Page 14: BindOpenldap

-u named \ -c /etc/named.conf

Crie um arquivo start.named dentro do /chroot/ e cole o conteúdo acima nele.

Transforme o mesmo em executável com o comando:

# chmod a+x /chroot/start.named

Não execute o script ainda!

Configurando o rndcCrie o arquivo rndc.conf dentro de /chroot/named/etc/rndc.conf e adicione o seguinte conteúdo:

#rndc.conf

options { default-server 127.0.0.1; default-key "rndckey";};

server 127.0.0.1 { key "rndckey";};

key "rndckey" { algorithm "hmac-md5"; secret "COLOQUE SUA CHAVE";};

Adicione as seguintes entradas no início do arquivo /chroot/named/etc/named.conf:

controls { inet 127.0.0.1 allow { 127.0.0.1; } keys { rndckey; };};

key "rndckey" { algorithm "hmac-md5"; secret "COLOQUE SUA CHAVE";};

Perceba que nos dois arquivos temos a frase COLOQUE SUA CHAVE, então, substituiremos esta por a respectiva chave.

Para gerar a chave faça:

# dnssec-kegen -a HMAC-MD5 -b 256 -n HOST rndc

Então você terá dois arquivos no diretório onde executou o comando.

Os nomes serão algo como Krndc.+157+48683.private e Krndc.+157+48683.key, mas nos estamos interessados somente no Krndc.+157+48683.private, dentro dele terá uma linha como essa informando a chave Key: QQMI5z8cceUIzA0UkPlbOEP3RH3sLEfSNVfWGmawjPo=, copie somente a chave e cole nos arquivos substituindo a frase COLOQUE SUA CHAVE.

Remova os dois arquivos que foram gerados.

Feito isso estamos prontos para iniciar o serviço e verificar se tudo está ok.

# cd /chroot/named# ./start.named

Verifique se tudo está ok através do comando:

Page 15: BindOpenldap

# rndc status

A saída deve ser algo parecido com:

version: 9.7.1rc1 ([seguro])number of zones: 3debug level: 0xfers running: 0xfers deferred: 0soa queries in progress: 0query logging is OFFrecursive clients: 0/0/1000tcp clients: 0/100server is up and running

Para facilitar a administração utilize o seguinte script:

#named init

export PATH=/usr/local/sbin:$PATH # needed for rndc

case "$1" instart) # Start daemons. echo -n "Levantando o named: " sh /chroot/start.named echo ;;stop) # Stop daemons. echo -n "Derrubando o named: " rndc stop echo "done" ;;esac

exit 0

Cole o conteúdo dentro de um novo arquivo chamado named em /etc/init.d e de permissão de execução para ele.

Assim quando quiser levantar o processo use:

# /etc/init.d/named start

e pra derrubar:

# /etc/init.d/named stop

Inicialize o serviço e faça um teste com o dig, não se esqueça de alterar no arquivo /etc/resolv.conf apontar para o 127.0.0.1.

# dig www.google.com.br

Obrigatoriamente devemos ter algo parecido com o seguinte resultado:

; <<>> DiG 9.7.1rc1 <<>> www.google.com.br;; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53404;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 4, ADDITIONAL: 4

;; QUESTION SECTION:;www.google.com.br. IN A

;; ANSWER SECTION:www.google.com.br. 345600 IN CNAME www.google.com.www.google.com. 604800 IN CNAME www.l.google.com.

Page 16: BindOpenldap

www.l.google.com. 300 IN A 64.233.163.104

;; AUTHORITY SECTION:google.com. 172799 IN NS ns2.google.com.google.com. 172799 IN NS ns1.google.com.google.com. 172799 IN NS ns3.google.com.google.com. 172799 IN NS ns4.google.com.

;; ADDITIONAL SECTION:ns1.google.com. 345600 IN A 216.239.32.10ns2.google.com. 345600 IN A 216.239.34.10ns3.google.com. 345600 IN A 216.239.36.10ns4.google.com. 345600 IN A 216.239.38.10

;; Query time: 1784 msec;; SERVER: 127.0.0.1#53(127.0.0.1);; WHEN: Mon Jan 24 20:31:15 2011;; MSG SIZE rcvd: 235

Ok, agora temos um servidor de DNS configurado e funcionando, esperando somente as zonas do LDAP.

Montando as zonas

Novo schema dnszone.

É necessária a inclusão de um novo schema no servidor openldap.

• http://www.venaas.no/ldap/bind-sdb/dnszone-schema.txt

Baixe o arquivo, salve no diretório schemas do servidor ldap, adicione mais uma entrada no arquivo slapd.conf e reinicie o serviço.

Exemplo de zona em ldap:

dn: ou=DNS,dc=acme,dc=lunobjectClass: topobjectClass: organizationalUnitou: DNS

dn: zoneName=acme.lun,ou=DNS,dc=acme,dc=lunzoneName: acme.lunrelativeDomainName: acme.lunobjectClass: dNSZoneobjectClass: top

dn: relativeDomainName=@,zoneName=acme.lun,ou=DNS,dc=acme,dc=lunobjectClass: topobjectClass: dNSZonezoneName: acme.lunrelativeDomainName: @dNSTTL: 86400dNSClass: INsOARecord: ns1.acme.lun. root.acme.lun. 2010083102 604800 86400 2419200 604800nSRecord: ns1.

dn: relativeDomainName=ns1,zoneName=acme.lun,ou=DNS,dc=acme,dc=lunzoneName: acme.lunrelativeDomainName: ns1dNSTTL: 86400dNSClass: INobjectClass: dNSZoneobjectClass: topaRecord: 10.1.1.2

dn: relativeDomainName=www,zoneName=acme.lun,ou=DNS,dc=acme,dc=lunzoneName: acme.lunrelativeDomainName: www

Page 17: BindOpenldap

dNSTTL: 604800dNSClass: INobjectClass: dNSZoneobjectClass: topcNAMERecord: www.acme.lunaRecord: 10.1.1.3

dn: relativeDomainName=cacti,zoneName=acme.lun,ou=DNS,dc=acme,dc=lunobjectClass: topobjectClass: dNSZonezoneName: acme.lunrelativeDomainName: cactidNSTTL: 604800dNSClass: INcNAMERecord: cacti.acme.lun.ARecord: 10.1.1.5

Exemplo de zona reversa em ldap:

dn: zoneName=1.1.10.in-addr.arpa,ou=DNS,dc=acme,dc=lunzoneName: 1.1.10.in-addr.arparelativeDomainName: 1.1.10.in-addr.arpaobjectClass: dNSZoneobjectClass: top

dn: relativeDomainName=@,zoneName=1.1.10.in-addr.arpa,ou=DNS,dc=acme,dc=lunzoneName: 1.1.10.in-addr.arparelativeDomainName: @dNSTTL: 3600dNSClass: INobjectClass: dNSZoneobjectClass: top

dn: relativeDomainName=2,zoneName=1.1.10.in-addr.arpa,ou=DNS,dc=acme,dc=lunzoneName: 1.1.10.in-addr.arparelativeDomainName: 2dNSTTL: 3600dNSClass: INobjectClass: dNSZoneobjectClass: toppTRRecord: ns1.acme.lun.

dn: relativeDomainName=3,zoneName=1.1.10.in-addr.arpa,ou=DNS,dc=acme,dc=lunzoneName: 1.1.10.in-addr.arparelativeDomainName: 3dNSTTL: 3600dNSClass: INobjectClass: dNSZoneobjectClass: toppTRRecord: www.acme.lun.

dn: relativeDomainName=5,zoneName=1.1.10.in-addr.arpa,ou=DNS,dc=acme,dc=lunzoneName: 1.1.10.in-addr.arparelativeDomainName: 5dNSTTL: 3600dNSClass: INobjectClass: dNSZoneobjectClass: toppTRRecord: cacti.acme.lun.

Configure seus arquivos seguindo estes como modelo, para incluí-los para dentro da base ldap salve-os como .ldif e use o slapadd, por exemplo:

# slapadd -l acme.ldif

Agora que temos as zonas prontas no servidor ldap, vamos fazer os apontamentos, edite o arquivo

Page 18: BindOpenldap

/chroot/named.conf e adicione as seguintes linhas com as devidas alterações de acordo com suas zonas:

# zona acme.lun

zone "acme.lun" { type master; database "ldap ldap://10.1.1.28/ou=DNS,dc=acme,dc=lun 10800"; notify yes;};

# reverso acme.lunzone "1.1.10.in-addr.arpa" { type master; database "ldap ldap://10.1.1.28/ou=DNS,dc=acme,dc=lun 10800"; notify yes;};

Agora é só iniciarmos o serviço e acompanhar nos logs para identificar possíveis erros.

Os logs ficam em /var/log/messages.

TestandoPara testarmos o funcionamento do nosso servidor de DNS gosto da maneira clássica com a dupla dinâmica nslookup e dig.

ConclusãoSempre gosto de lembrar a ideia de centralização, o que nos possibilita grandes vantagens, principalmente quando temos um cenário misto em serviços.

Vale ressaltar também em nossa integração ldap+dns que podemos considerar alguns itens como performance, que será um pouco prejudicada pois a consulta DNS não está sendo mais local, o que envolve vários outros fatores.

Mas asseguro-lhes que este tipo de desvantagem poderá ser levando em consideração quando temos um serviço extremamente estressado com uma taxa de acesso realmente grande.

Espero que aproveitem o artigo!