sábado, 6 de agosto de 2016

Configurando OpenLDAP com certificado SSL/TLS

Intodução

Se formos utilizar um serviço de diretórios como o OpenLDAP para fornecer autenticação, com certeza você irá querer fazer isso utilizando um protocolo criptografado. Sem a criptografia as informações irão passar como texto pela rede e é muito fácil captura-las sendo possível obter informação de usuários e algumas vezes até senhas.

Apenas como exemplo, suponha que você tenha um servidor LDAP fornecendo autenticação para seus servidores Linux.

Um servidor Linux que se autentica utilizando o servidor LDAP faz uma pesquisa no serviço de diretórios utilizando as credenciais de administrador pela porta ldap:/// que não fornece criptografia.

$ ldapsearch –D cn=manager,dc=example,dc=com –w secret –b dc=example,dc=com –s base -LLL

dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: Dominio example.com
dc: example

No servidor LDAP utilize o comando tcpdump na porta 386 com a opção –X para mostrar o cabeçalho e os dados do pacote em Hexadecimal e ASCII

[root@ldap01 ~]# tcpdump –nvvv –i eth0 port 389 –X

10:53:20.498082 IP (tos 0x0, ttl 64, id 35989, offset 0, flags [DF], proto TCP (6), length 100)
192.168.206.101.41992 > 192.168.206.200.ldap: Flags [P.], cksum 0xa5c4 (correct), seq 1:49, ack 1, win 229, options [nop,nop,TS val 5200896 ecr 5236832], length 48
0x0000: 4500 0064 8c95 4000 4006 8f7f c0a8 ce65 E..d..@.@......e
0x0010: c0a8 cec8 a408 0185 1fce d094 8014 31dd ..............1.
0x0020: 8018 00e5 a5c4 0000 0101 080a 004f 5c00 .............O\.
0x0030: 004f e860 302e 0201 0160 2902 0103 041c .O.`0....`).....
0x0040: 636e 3d6d 616e 6167 6572 2c64 633d 6578 cn=manager,dc=ex
0x0050: 616d 706c 652c 6463 3d63 6f6d 8006 7365 ample,dc=com..se
0x0060: 6372 6574 cret

Veja que o usuário cn=manager,dc=example,dc=com com a senha secret aparece claramente na saída do comando tcpdump. Você pode rodar esse comando no servidor cliente ou em um servidor firewall intermediário na rede e ainda assim verá esse tipo de informação trafegando na sua rede sem segurança alguma.

Acho que não preciso me prolongar mais sobre o assunto, certo ? = )

Pois bem. Neste post iremos ver como configurar o nosso servidor OpenLDAP com a base de dados em OLC (cn=config) para operar com protocolo ldaps:/// fornecendo criptografia com SSL/TLS. O Sistema Operacional utilizado é o CentOS 7, mas pode ser facilmente replicado para o RedHat 7 ou outras distribuições.

Para saber como subir um servidor OpenLDAP com a base cn=config consulte o post Servidor OpenLDAP (cn=config) no CentOS 7

Criando um Certificado


Antes de configurar o servidor precisamos de um certificado SSL. Neste post iremos utilizar um certificado Self-Signed (auto-assinado). Para criar o certificado Self-Sign no CentOS 7 siga o procedimento abaixo a partir do servidor LDAP:

Primeiro geramos a chave do certificado

# cd /etc/pki/tls/certs/

# make server.key
umask 77 ; \
/usr/bin/openssl genrsa -aes128 2048 > server.key
Generating RSA private key, 2048 bit long modulus
..................................+++
..........................................+++
e is 65537 (0x10001)
Enter pass phrase: secret
Verifying - Enter pass phrase: secret

Removemos a senha da chave gerada acima

# openssl rsa -in server.key -out server.key
Enter pass phrase for server.key:
writing RSA key

Geramos o arquivo .csr (Certificate Sign Request) com a chave gerada acima

# make server.csr
umask 77 ; \
/usr/bin/openssl req -utf8 -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
----- Country Name (2 letter code) [XX]:BR
State or Province Name (full name) []:Sao Paulo
Locality Name (eg, city) [Default City]:Sao Paulo
Organization Name (eg, company) [Default Company Ltd]:HOME
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:ldap01.example.com
Email Address []:rafaelrb@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Por último assinamos o certificado gerado por um período de 10 anos

# openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 3650
Signature ok
subject=/C=BR/ST=Sao Paulo/L=Sao Paulo/O=HOME/CN=ldap01.example.com/emailAddress=rafaelrb@gmail.com
Getting Private key

Agora que temos o certificado copiamos os arquivos para o diretório de certificados do OpenLDAP

# cp /etc/pki/tls/certs/server.key \
/etc/pki/tls/certs/server.crt \
/etc/pki/tls/certs/server.csr \
/etc/pki/tls/certs/ca-bundle.crt /etc/openldap/certs/

Ajustamos as permissões para o usuário ldap e grupo ldap

# chown -R ldap.ldap /etc/openldap/certs/

Configurando o certificado no OpenLDAP

Agora que temos os arquivos do certificado podemos configurar o servidor OpenLDAP para utilizá-los. Criamos então o arquivo mod_ssl.ldif com o seguinte conteúdo:

dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/openldap/certs/ca-bundle.crt
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/server.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/server.key

Usamos então o comando ldapmodify para adicionar as configurações de certificado na base cn=config do nosso servidor LDAP

[root@ldap01 ~]# ldapmodify -Y EXTERNAL -H ldapi:/// -f mod_ssl.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"

Editamos o parâmetro SLAPD_URLS no arquivo /etc/sysconfig/slapd para habilitar o protocolo ldaps:///

# OpenLDAP server configuration
# see 'man slapd' for additional information

# Where the server will run (-h option)
# - ldapi:/// is required for on-the-fly configuration using client tools
# (use SASL with EXTERNAL mechanism for authentication)
# - default: ldapi:/// ldap:///
# - example: ldapi:/// ldap://127.0.0.1/ ldap://10.0.0.1:1389/ ldaps:///
SLAPD_URLS="ldapi:/// ldap://ldap01/ ldaps://ldap01/"

# Any custom options
#SLAPD_OPTIONS=""

# Keytab location for GSSAPI Kerberos authentication
#KRB5_KTNAME="FILE:/etc/openldap/ldap.keytab"

Reiniciamos o serviço slapd para carregar as configurações de SSL

# systemctl restart slapd.service

Agora podemos verificar se o serviço SSL está no ar com o comando netstat

# netstat -lpn | grep 636 tcp 0 0 192.168.206.200:636 0.0.0.0:* OUÇA 2627/slapd

A porta 636 é do protocolo LDAPS. Na saída do comando acima podemos ver que o serviço está no ar. Podemos verificar se o certificado foi carregado corretamente utilizando o comando openssl

# openssl s_client -connect 192.168.206.200:636
CONNECTED(00000003)
depth=0 C = BR, ST = Sao Paulo, L = Sao Paulo, O = HOME, CN = ldap01.example.com, emailAddress = rafaelrb@gmail.com
verify error:num=18:self signed certificate
verify return:1
depth=0 C = BR, ST = Sao Paulo, L = Sao Paulo, O = HOME, CN = ldap01.example.com, emailAddress = rafaelrb@gmail.com
verify return:1
---
Certificate chain
0 s:/C=BR/ST=Sao Paulo/L=Sao Paulo/O=HOME/CN=ldap01.example.com/emailAddress=rafaelrb@gmail.com
i:/C=BR/ST=Sao Paulo/L=Sao Paulo/O=HOME/CN=ldap01.example.com/emailAddress=rafaelrb@gmail.com
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDhjCCAm4CCQDXGQGvI9owSjANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMC
QlIxEjAQBgNVBAgMCVNhbyBQYXVsbzESMBAGA1UEBwwJU2FvIFBhdWxvMQ0wCwYD
VQQKDARIT01FMRswGQYDVQQDDBJsZGFwMDEuZXhhbXBsZS5jb20xITAfBgkqhkiG
9w0BCQEWEnJhZmFlbHJiQGdtYWlsLmNvbTAeFw0xNjA4MDYxNTIzMDlaFw0yNjA4
MDQxNTIzMDlaMIGEMQswCQYDVQQGEwJCUjESMBAGA1UECAwJU2FvIFBhdWxvMRIw
EAYDVQQHDAlTYW8gUGF1bG8xDTALBgNVBAoMBEhPTUUxGzAZBgNVBAMMEmxkYXAw
MS5leGFtcGxlLmNvbTEhMB8GCSqGSIb3DQEJARYScmFmYWVscmJAZ21haWwuY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA72pIzy0J6Ns3Vj8zwn65
Zew8HlnZS3VBdEwGf2cNXZ1mkcjGSqbBSkI6rCRHhMmi0lwAheezbB1GUuY2i4rQ
pbSVN+6+PfJJyqfaFuiXQy9TGtEhkqVI6398Jrfp3ZX1uHbX6ng4lBAqg0IYMrE9
ygp1xJc7dU2ZLWND6akPUQ5N+LMreI/jOaV1zOvJv61GXrX3IHbJ2hibAQanhDqO
5E4ZVuOWYSDGrm6BbeeTalFF4j4p5rNqGeQrIj2xLDV0hIa1NJjOJDZyNE5ohb1h
8vfPWhsbzHDNuN80S1V/CzeIt2oOqtPSB63WtWy8Gbpwc0ctYNu4RTDbZuiBhh/o
0QIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA4xBg0YdgQ5epznyCG2uEELrgxuJUK
QOMH+EDdY0o3ez6KjauW+obqpWj2UsgRv5n0+xUy7cRUs0GNg2TapkJXKBwOQj94
UO/GsOX8PVReiS7KUio+r/oDGhyea2+TVTZpT3umJJWQ15KabSDtcjtHRyhkEOsl
vz1v8yfucLDa+cGmssWTK84vQQ/MwBKnb+nYLKB6JSE0GIXJENVe+bu2iUQlOdr1
2Kt3kkYTkJFvlRGLaDUpG2zZx5qyx+0CTEvhZafn/LMPoLt0fOYW8xfWTfuxljL9
4dFJbw7O2fv+L5yGOZtAdjgQreKd9GG4h0MJkxgm/38pXmQ8MR8PxeNB
-----END CERTIFICATE-----
subject=/C=BR/ST=Sao Paulo/L=Sao Paulo/O=HOME/CN=ldap01.example.com/emailAddress=rafaelrb@gmail.com
issuer=/C=BR/ST=Sao Paulo/L=Sao Paulo/O=HOME/CN=ldap01.example.com/emailAddress=rafaelrb@gmail.com
---
No client certificate CA names sent
Server Temp Key: ECDH, prime256v1, 256 bits
---
SSL handshake has read 1396 bytes and written 373 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 0A437CC31B5082B02CBAC425D673446E70CA57F1EEEE189241D46B5BAD527689
Session-ID-ctx:
Master-Key: F117AD5975460891775B9CE9B787E6C7C541ABF759652E1C964644AA461D62FCDA2CF9C4E2CDC07F06AD4955D88015C3
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1470498253
Timeout : 300 (sec)
Verify return code: 18 (self signed certificate)
---

Configurando Servidores Clientes

Agora precisamos configurar o servidor cliente Linux para utilizar o serviço de diretórios com ldaps. No servidor cliente Linux CentOS 7 utilize o seguinte comando:

# authconfig --enableldaptls --update
getsebool: SELinux is disabled

Edite o arquivo /etc/nslcd.conf com o seguinte conteúdo:

uid nslcd
gid ldap
uri ldaps://192.168.206.200/
base dc=example,dc=com
tls_reqcert allow

Reinicie o serviço nslcd para carregar as alterações:

# systemctl restart nslcd.service

Edite o arquivo /etc/openldap/ldap.conf com o seguinte conteúdo:

BASE dc=example,dc=com
URI ldaps://192.168.206.200/
TLS_CACERTDIR /etc/openldap/cacerts
SASL_NOCANON on
TLS_REQCERT allow

Agora você pode se logar no servidor cliente normalmente. A comunicação entre cliente e servidor LDAP está acontecendo de forma criptografada através do protocolo LDAPS. Experimente fazer consultas no servidor cliente com o comando ldapsearch e monitore no servidor LDAP a porta 636 com o comando tcpdump –X e veja que toda a informação do pacote está criptografada.

Referências:

https://www.server-world.info/en/note?os=CentOS_7&p=openldap&f=4
https://www.server-world.info/en/note?os=CentOS_7&p=ssl

Até a próxima!

- Rafael Baena

domingo, 31 de julho de 2016

Servidor OpenLDAP (cn=config) no CentOS 7

Introdução

Neste post irei mostrar passo a passo como configurar um servidor OpenLDAP utilizando a base de dados de configuração cn=config. Ao final do post iremos ver como configurar um servidor Linux para se autenticar utilizando os usuários e grupos cadastrados em nossa base de dados.

Vamos aos requisitos:
  • 1 servidor Linux CentOS 7
  • 1 CPU
  • 1 GB de RAM
  • 20GB de Disco
  • FIREWALLD desligado
  • SELINUX desligado
A instalação do sistema operacional vai além do escopo deste post. Partirei do principio que você já possui um servidor Linux CentOS 7 instalado e funcionando na rede e com os serviços FIREWALLD e SELINUX desabilitados.

Vamos as configurações do servidor:

Hostname: ldap01.example.com
SO: CentOS 7
IP: 192.168.206.200
Netmask: 255.255.255.0
Gateway: 192.168.206.1
DNS: 192.168.206.1

Instalamos os pacotes do OpenLDAP servidor e cliente no servidor ldap01

# yum install openldap-servers openldap-clients

Editamos o arquivo /etc/sysconfig/slapd e alteramos a variável SLAPD_URLS para conter ldap://ldap01/

# OpenLDAP server configuration
# see 'man slapd' for additional information

# Where the server will run (-h option)
# - ldapi:/// is required for on-the-fly configuration using client tools
# (use SASL with EXTERNAL mechanism for authentication)
# - default: ldapi:/// ldap:///
# - example: ldapi:/// ldap://127.0.0.1/ ldap://10.0.0.1:1389/ ldaps:///
SLAPD_URLS="ldapi:/// ldap://ldap01/"

# Any custom options
#SLAPD_OPTIONS=""

# Keytab location for GSSAPI Kerberos authentication
#KRB5_KTNAME="FILE:/etc/openldap/ldap.keytab"

Se o servidor slapd estiver rodando, pare-o.

# systemctl stop slapd.service

Copie o arquivo DB_CONFIG de exemplo da documentação do pacote openldap-servers.

# cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG

Ajuste a permissão para o usuário ldap grupo ldap

# chown -R ldap:ldap /var/lib/ldap

Antes de iniciar a base de dados precisamos alterar alguns parâmetros na base cn=config. Utilizando o comando slapcat podemos ver as configurações padrões.

# slapcat -b cn=config

Começamos importando os principais schemas que vamos utilizar. Os esquemas estão disponíveis em formato ldif no diretório /etc/openldap/schema. Utilizamos o comando slapadd para importar os schemas

# slapadd -v -l /etc/openldap/schema/core.ldif -b cn=config
# slapadd -v -l /etc/openldap/schema/nis.ldif -b cn=config
# slapadd -v -l /etc/openldap/schema/cosine.ldif -b cn=config
# slapadd -v -l /etc/openldap/schema/inetorgperson.ldif -b cn=config

O schema core já vem na configuração padrão. O primeiro comando acima provavelmente irá retornar um erro dizendo que não foi possível incluir o schema na base de dados, você pode ignorar o erro e fazer os demais. Eu deixei o comando acima para referencia, caso você esteja criando uma base de dados do zero a ordem de importação dos schemas é importante e devem seguir esta ordem.

Ao executar os comandos acima será criado novos diretórios em /etc/openldap/slapd.d/cn=config/cn=schema.

# ls -ltr /etc/openldap/slapd.d/cn\=config/cn\=schema
total 32

-rw------- 1 ldap ldap 15578 Jul 31 11:00 cn={0}core.ldif
-rw------- 1 root root 11363 Jul 31 11:20 cn={1}nis.ldif
-rw------- 1 root root 11363 Jul 31 11:20 cn={1}cosine.ldif
-rw------- 1 root root  2857 Jul 31 11:20 cn={2}inetorgperson.ldif

Se você está pensando agora que a base de dados cn=config na verdade é uma estrutura de diretórios em /etc/openldap/slapd.d você está corretíssimo. Não altere esses arquivos diretamente na estrutura de diretórios, pois o servidor slapd irá reclamar. Sempre utilize os comandos do OpenLDAP client. Veja que ao executar o comando slapadd como root os arquivos foram criados com o usuário root. Precisamos então ajustar a permissão para que o servidor slapd possa ler os arquivos.

# chown -R ldap:ldap /etc/openldap/slapd.d

Também podemos verificar os schemas importados utilizando o comando slapcat

# slapcat -b cn=config -s cn=schema,cn=config | grep 'dn: cn={'
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}inetorgperson,cn=schema,cn=config

Habilite e inicie o servidor slapd

# systemctl enable slapd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/slapd.service to /usr/lib/systemd/system/slapd.service.
# systemctl start slapd.service

Agora vamos configurar a nossa base de dados. O cn=config por padrão vem com o domínio dc=my-domain,dc=com configurado.

# slapcat -b cn=config -s olcDatabase={2}hdb,cn=config
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=my-domain,dc=com
olcRootDN: cn=Manager,dc=my-domain,dc=com
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
structuralObjectClass: olcHdbConfig
entryUUID: 361014fe-eb7b-1035-8651-eb93d04be7e8
creatorsName: cn=config
createTimestamp: 20160731150006Z
entryCSN: 20160731150006.119309Z#000000#000#000000
modifiersName: cn=config

modifyTimestamp: 20160731150006Z

Precisamos alterar esses valores para a nossa base de dados. Para isso precisamos utilizar o comando ldapmodify com um arquivo ldif informando que vamos incluir um parametro olcRootPW e alterar os parametros olcSuffix e olcRootDN da entrada dn: olcDatabase={2}hdb,cn=config. Criamos então o arquivo configsuffix.ldif com o seguinte conteúdo:

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=example,dc=com
-
replace: olcRootDN
olcRootDN: cn=Manager,dc=example,dc=com
-
add: olcRootPW
olcRootPW: {SSHA}Sb6Z5tJi8u8BHFSNJt2J/ii6DsEFlf09

O parâmetro olcRootPW é a senha para o usuário cn=Manager,dc=example,dc=com. A senha é gerada pelo comando slappasswd. Utilizei a senha secret gerada pelo comando abaixo.  

# slappasswd -s secret
{SSHA}Sb6Z5tJi8u8BHFSNJt2J/ii6DsEFlf09

Executamos então o comando ldapmodify da seguinte forma:

# ldapmodify -Y EXTERNAL -H ldapi:/// -f configsuffix.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={2}hdb,cn=config"

Rodando o comando slapcat novamente iremos ver que os parâmetros foram alterados. Veja que a senha no parâmetro olcRootPW aparece criptografado, portando não espere ver o mesmo hash informado no arquivo ldif.

# slapcat -b cn=config -s olcDatabase={2}hdb,cn=config
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
structuralObjectClass: olcHdbConfig
entryUUID: 361014fe-eb7b-1035-8651-eb93d04be7e8
creatorsName: cn=config
createTimestamp: 20160731150006Z
olcSuffix: dc=example,dc=com
olcRootDN: cn=Manager,dc=example,dc=com
olcRootPW:: e1NTSEF9U2I2WjV0Smk4dThCSEZTTkp0MkovaWk2RHNFRmxmMDk=
entryCSN: 20160731154804.140139Z#000000#000#000000
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
modifyTimestamp: 20160731154804Z

Vamos dar uma olhada nas configurações da base cn=config agora usando o comando ldapsearch:

# ldapsearch -Y EXTERNAL -H ldapi:/// -b olcDatabase={0}config,cn=config -LLL
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,
cn=auth" manage by * none

Veja que uma vez o servidor slapd no ar podemos utilizar o comando ldapsearch para consultar a base cn=config. Vamos agora criar uma senha para a base cn=config. No servidor ldap01 crie o arquivo cnconfigpw.ldif com o seguinte conteúdo:

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}Sb6Z5tJi8u8BHFSNJt2J/ii6DsEFlf09

Executamos então o comando ldapmodify para fazer as modificações:

# ldapmodify -Y EXTERNAL -H ldapi:/// -f cnconfigpw.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={0}config,cn=config"

Agora execute o comando ldapsearch para verificar

# ldapsearch -H ldap://ldap01/ -D cn=config -w secret -b olcDatabase={0}config,cn=config -LLL
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external
,cn=auth" manage by * none
olcRootPW: {SSHA}Sb6Z5tJi8u8BHFSNJt2J/ii6DsEFlf09

Agora estamos prontos para popular a nossa base de dados LDAP com usuários e grupos. Crie o arquivo rootdomain.ldif com o seguinte conteúdo:

dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectclass: organization
o: Dominio example.com
dc: example

dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
cn: Manager
description: Administrador da base LDAP

dn: ou=Usuarios,dc=example,dc=com
objectClass: organizationalUnit
ou: Usuarios

dn: ou=Grupos,dc=example,dc=com
objectClass: organizationalUnit
ou: Grupos

NOTA: os valores em negrito precisão ser os mesmos valores.

Utilizamos então o comando ldapadd para adicionar as entradas em nossa base de dados:

# ldapadd -D cn=Manager,dc=example,dc=com -w secret -H ldapi:/// -f rootdomain.ldif
adding new entry "dc=example,dc=com"

adding new entry "cn=Manager,dc=example,dc=com"

adding new entry "ou=Usuarios,dc=example,dc=com"

adding new entry "ou=Grupos,dc=example,dc=com"

Podemos validar a criação dos objetos na base com o comando ldapsearch:

# ldapsearch -D cn=Manager,dc=example,dc=com -w secret -H ldapi:/// -b dc=example,dc=com -LLL
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: Dominio example.com
dc: example

dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
cn: Manager
description: Administrador da base LDAP

dn: ou=Usuarios,dc=example,dc=com
objectClass: organizationalUnit
ou: Usuarios

dn: ou=Grupos,dc=example,dc=com
objectClass: organizationalUnit
ou: Grupos

Agora vamos criar o grupo Usuarios e o usuário Angus McGyver incluindo-o no grupo Usuarios. Crie uma senha para o usuário utilizando o comando slappasswd

# slappasswd -s P@ssw0rd
{SSHA}A7WQ+zMFlrMrIBwFwJx+PCvyQ7UYb4pm

Edite o arquivo usuario.ldif com o seguinte conteúdo:

dn: cn=Angus McGyver,ou=Usuarios,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: Angus McGyver
sn: McGyver
givenName: Angus
uid: angus.mcgyver
userPassword: {SSHA}A7WQ+zMFlrMrIBwFwJx+PCvyQ7UYb4pm
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/angus.mcgyver

dn: cn=Usuarios,ou=Grupos,dc=example,dc=com
objectClass: posixGroup
cn: Usuarios
gidNumber: 1000
memberUid: angus.mcgyver

Utilizamos o comando ldapadd para criar o usuário na base:

# ldapadd -D cn=Manager,dc=example,dc=com -w secret -H ldapi:/// -f usuario.ldif 
adding new entry "cn=Angus McGyver,ou=Usuarios,dc=example,dc=com"

adding new entry "cn=Usuarios,ou=Grupos,dc=example,dc=com"


Podemos consultar a base com o comando ldapsearch para validar a criação dos objetos:

# ldapsearch -D cn=Manager,dc=example,dc=com -w secret -H ldapi:/// -b dc=example,dc=com -LLL '(|(objectClass=person)(objectClass=posixGroup))'
dn: cn=Usuarios,ou=Grupos,dc=example,dc=com
objectClass: posixGroup
cn: Usuarios
gidNumber: 1000
memberUid: angus.mcgyver

dn: cn=Angus McGyver,ou=Usuarios,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: Angus McGyver
sn: McGyver
givenName: Angus
uid: angus.mcgyver
userPassword:: e1NTSEF9QTdXUSt6TUZsck1ySUJ3RndKeCtQQ3Z5UTdVWWI0cG0=
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/angus.mcgyver

Agora que temos o nosso servidor OpenLDAP funcionando e populado com usuários e grupos. Vamos configurar um servidor Linux para se autenticar utilizando o nosso servidor. Em um servidor Linux CentOS 7 execute o seguinte comando:

# authconfig --enableldap --enableldapauth --ldapserver=192.168.206.200 --ldapbasedn="dc=example,dc=com" --enablemkhomedir --updateall
getsebool:  SELinux is disabled
getsebool:  SELinux is disabled

Agora tente efetuar login no servidor Linux com o usuário angus.mcgyver e senha P@ssw0rd e parabéns! Seu servidor OpenLDAP com base de dados em cn=config está configurado.

Você pode aprimorar essa solução criando ACLs, desabilitando autenticação simples e anônima, habilitando replicação e autenticação via SSL/TLS para criptografar os dados. Mais adiante irei abortar um pouco mais sobre o assunto OpenLDAP mostrando como ativar uma replicação N-Way multimaster e como ativar certificados SSL para autenticação com criptografia.

Referencias:

  
Até a próxima!
-
Rafael Baena
 

segunda-feira, 25 de julho de 2016

Active Directory com OpenLDAP proxy

Introdução

Neste post irei mostrar como configurar um servidor OpenLDAP como proxy para um ou mais servidores Active Directory na rede. No final iremos fazer um servidor Linux se autenticar utilizando a solução de proxy.

Esta solução é útil quando você deseja gerenciar os seus usuários de rede apenas pelo AD e permitir que servidores Linux se autentiquem utilizando a mesma base de dados de usuário.

Imagine que você tenha vários clientes e para cada um há um servidor Active Directory gerenciando os usuários. Os seus operadores possuem usuários cadastrados no Active Directory da sua empresa e você precisa fazer com que os servidores Linux do cliente se autentique via LDAP permitindo que tanto usuários da sua empresa quanto usuários do cliente possam se conectar em seus servidores Linux. Esta solução é chamada de Proxy LDAP.

Existem ao menos três formas de se configurar o Proxy LDAP mas para este post iremos focar na solução que adotei para resolver o cenário acima onde teremos uma base de LDAP contendo metadados dos usuários que estão cadastrados no AD e iremos utilizar SASL para que o servidor LDAP passe o serviço de autenticação para o AD.

A solução proposta neste post funcionará da seguinte forma:

  • O usuário irá solicitar autenticação na base de dados LDAP utilizando o uid e password cadastrados
  • O LDAP terá um parâmetro no campo userPassword no formato {SASL}usuario@dominio onde o LDAP irá interpretar que deverá passar a autenticação adiante para o serviço saslauthd
  • Ao receber a requisição de autenticação o serviço saslauthd irá fazer a comunicação com o serviço AD utilizando o Proxy LDAP que poderá fazer ponte com um ou mais ADs.
  • Se o usuário e senha forem validados corretamente pelo serviço AD, a mensagem de autenticação é respondida com sucesso para o serviço saslauthd que por sua vez irá responder ao LDAP que a autenticação foi bem sucedida.
Para atingir este objectivo iremos fazer as configurações no servidor LDAP em quatro passos:

  • Passo 1 - Configurar a base de dados para armazenamento de metadados onde usuários cadastrados terão em seu atributo userPassword o valor {SASL}usuario@dominio para instruir que este usuário deverá se autenticar utilizando o Proxy LDAP
  • Passo 2 - Configurar o proxy LDAP para que este normalize a base de dados do AD transformando o domínio ex. contoso.com em um domínio local do LDAP de forma que todo o domínio do AD possa ser consultado a partir de uma OU (Organizational Unit) LDAP1
  • Passo 3 - Configurar o serviço saslauthd para que este se comunique com o Proxy LDAP afim de autenticar os usuários cadastrados no AD. O saslauthd irá receber o usuário no formato usuario@LDAP1 onde usuário é o uid que será mapeado para o campo sAMAccountName cadastrado no AD
  • Passo 4 - Criaremos os usuário na base LDAP com o mesmo uid informando no atributo userPassword que este usuário deverá passar adiante o serviço de autenticação para o saslauthd que por sua vez irá se comunicar com o Proxy LDAP que irá se comunicar com o AD para realizar a autenticação   

Requisitos:

  • Servidor Active Directory ( Windows 2008 R2 ou Windows 2012 )
  • Usuário e senha no AD com permissão de consulta
  • Servidor OpenLDAP CentOS 7.x

Para este post iremos utilizar:

Servidor AD: ad.contoso.com
Usuário: openldap
Senha: secret
IP: 192.168.0.5

Servidor CentOS 7.x: openldap.local
Usuário: root
Senha: secret
IP: 192.168.0.10
SELINUX: disabled
FIREWALLD: disabled

A instalação do SO dos servidores mencionados acima vão além do escopo deste post. Vou assumir que você já tenha um servidor Active Directory instalado e funcionando na rede e que tenha instalado o servidor CentOS 7.x com o mínimo de pacotes necessários e com SELINUX e FIREWALLD desabilitados.

Passo 1


No servidor openldap instalamos os seguintes pacotes:

# yum install openldap-servers openldap-clients cyrus-sasl cyrus-sasl-ldap

Como preciso configurar uma base de dados LDAP vou simplificar essa instalação não utilizando a base de dados cn=config. Todas as configurações serão realizadas a partir de arquivos que serão disponibilizados no final do post como referencia para a sua instalação. Mais para frente irei disponibilizar um post abordando OpenLDAP com cn=config e replicação.

Primeiro paramos o serviço slapd e removemos o diretório /etc/openldap/slapd.d

# systemctl stop slapd
# rm -rf /etc/openldap/slapd.d

Gere um hash de senha para o usuário Manager:

# slappasswd -s secret
{SSHA}KR81a+hZjAgFFdMPcBFebVQFX4nwCDnp

Crie o arquivo /etc/openldap/slapd.conf com o conteúdo abaixo. Altere rootpw com o hash gerado pelo comando slappasswd acima

sasl-host localhost
sasl-secprops none

include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/ppolicy.schema
include /etc/openldap/schema/ldapns.schema
include /etc/openldap/schema/microsoft.minimal.schema

pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args

modulepath /usr/lib64/openldap
moduleload back_meta.la
moduleload back_ldap.la
moduleload rwm.la

database mdb
maxsize 1073741824
suffix "dc=local"
rootdn "cn=Manager,dc=local"
rootpw {SSHA}KR81a+hZjAgFFdMPcBFebVQFX4nwCDnp
directory /var/lib/ldap

index objectClass eq

Deixei disponível os schemas ldapns.schema e microsoft.minimal.schema no link https://drive.google.com/open?id=0B9k1h3Guk1hmWHVnQ1BXVEJCbmM. Os outros arquivos estão disponíveis na distribuição. Faça o download desses dois arquivos e os copie para a pasta /etc/openldap/schema

Teste o arquivo de configuração para verificar se há algum erro:

# slaptest -f /etc/openldap/slapd.conf -u
57956906 config_back_initialize: warning, unable to get "olcDbIDAssertPasswd" attribute description: 17: attribute type undefined

config file testing succeeded

Ignore a mensagem de WARNING acima. Se você receber a mensagem "config file testing succeeded" é porque o arquivo está OK. Senão receber essa mensagem reveja o arquivo de configuração antes de proceder.

Criando a base de dados LDAP que irá armazenar os metadados

Crie um arquivo mydomain.ldif com o seguinte conteúdo:

dn: dc=local
dc: local
objectClass: dcObject
objectClass: organizationalUnit
ou: local

Execute o comando slapadd para inicializar a base de dados:

# slapadd -v -l mydomain.ldif
57956ae0 config_back_initialize: warning, unable to get "olcDbIDAssertPasswd" attribute description: 17: attribute type undefined
57956ae0 mdb_monitor_db_open: monitoring disabled; configure monitor database to enable
added: "dc=local" (00000001)

_#################### 100.00% eta   none elapsed            none fast!         

Ignore a mensagem de WARNING. Se você visualizar added: "dc=local" e a barra de progresso aparecer 100.00% a inicialização da base foi concluída com sucesso.

Ajuste as permissões para que o serviço slapd tenha acesso aos arquivos da base de dados

# chown ldap:ldap -R /var/lib/ldap

Inicie o serviço slapd

# systemctl start slapd.service

Verifique se o serviço está no ar consultando a base com o comando ldapsearch

# ldapsearch -H ldap://localhost -D 'cn=Manager,dc=local' -w secret -b 'dc=local' -LLL
dn: dc=local
dc: local
objectClass: dcObject
objectClass: organizationalUnit
ou: local

Passo 2

Agora que temos o serviço LDAP com a base de dados para armazenar metadados iremos criar uma nova instancia ldap que fará a comunicação com o servidor AD.

Crie o diretório /etc/openldap/proxy para armazenar as configurações de proxy.

# mkdir /etc/openldap/proxy

Crie o arquivo /etc/openldap/proxy/LDAP1.conf contendo o seguinte conteúdo:

database ldap
suffix "ou=LDAP1,dc=local"
uri ldap://192.168.0.5:3268
idassert-bind bindmethod=simple
  binddn="cn=openldap,cn=Users,dc=contoso,dc=com"
  credentials="secret"
  mode=none
  flags=non-prescriptive
idassert-authzFrom "dn.exact:cn=Manager,dc=local"

overlay rwm
rwm-suffixmassage "ou=LDAP1,dc=local" "dc=contoso,dc=com"

rwm-map attribute uid sAMAccountName
rwm-map attribute * *

Substitua os parâmetros uri, binddn, bindpw e rwm-suffixmassage para os valores necessários para o funcionamento no seu ambiente.

Crie o arquivo /etc/openldap/slapd-proxy.conf com o seguinte conteúdo:

modulepath /usr/lib64/openldap
moduleload back_meta.la
moduleload back_ldap.la
moduleload rwm.la

include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/ppolicy.schema
include /etc/openldap/schema/ldapns.schema
include /etc/openldap/schema/microsoft.minimal.schema

#Database
database ldap
suffix "cn=Manager,dc=local"
rootdn "cn=Manager,dc=local"
rootpw secret

include /etc/openldap/proxy/LDAP1.conf

Agora iniciamos o serviço Proxy LDAP em outra porta para não conflitar com a instancia de metadados que já está rodando. Vamos utilizar o endereço localhost e a porta 390

# slapd -f /etc/openldap/slapd-proxy.conf -h ldap://localhost:390

Agora verificamos se o proxy está funcionando consultando o serviço LDAP que está rodando na porta 390

# ldapsearch -x -H ldap://localhost:390 -b "ou=LDAP1,dc=local" -D "cn=Manager,dc=local" -w secret '(sAMAccountName=openldap)' uid userPrincipalName -LLL
dn: cn=openldap,cn=Users,ou=LDAP1,dc=local
uid: openldap
userPrincipalName: openldap@contoso.com

Se o comando acima retornar os atributos dn, uid e userPrincipalName. Parabéns a sua instancia de Proxy está funcionando corretamente. Senão verifique os arquivos de configuração e tente novamente.

Passo 3

Agora vamos configurar o SASL para autenticar usuários pela instancia do Proxy LDAP. Edite o arquivo /etc/saslauthd.conf com o seguinte conteúdo:

ldap_servers: ldap://127.0.0.1:390
ldap_search_base: ou=%d,dc=local
ldap_timeout: 10
ldap_filter: uid=%U
ldap_bind_dn: cn=Manager,dc=local
ldap_password: secret
ldap_deref: never
ldap_restart: yes
ldap_scope: sub
ldap_use_sasl: no
ldap_start_tls: no
ldap_version: 3
ldap_auth_method: bind

Edite o parametro MECH no arquivo /etc/sysconfig/saslauthd para ldap

# Directory in which to place saslauthd's listening socket, pid file, and so
# on. This directory must already exist.
SOCKETDIR=/run/saslauthd

# Mechanism to use when checking passwords. Run "saslauthd -v" to get a list
# of which mechanism your installation was compiled with the ablity to use.
MECH=ldap

# Additional flags to pass to saslauthd on the command line. See saslauthd(8)
# for the list of accepted flags.
FLAGS=

Habilite e inicie o serviço saslauthd

# systemctl enable saslauthd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/saslauthd.service to /usr/lib/systemd/system/saslauthd.service.
# systemctl start saslauthd.service

Agora verifique se o serviço consegue autenticar usuários no AD.

# testsaslauthd -u openldap@LDAP1 -p P@ssw0rd
0: OK "Success."

Se você receber a mensagem 0: OK "Success." parabéns. O SASL pode autenticar utilizando o seu proxy LDAP.

Passo 4

Neste último passo é onde colocamos tudo para funcionar junto. O serviço LDAP irá se comunicar com o serviço saslauthd através de um objeto mutex.

Para configurar criaremos o arquivo /usr/lib64/sasl2/slapd.conf com o seguinte conteúdo

pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux

Veja que o arquivo slapd.conf possui o mesmo nome do arquivo configurado anteriormente mas são para propósitos diferentes.

Agora adicionamos o usuário ldap no grupo sasauthd para que o nosso serviço LDAP possa consultar o serviço.

# usermod -a -G saslauth ldap

Tenha certeza que possui os parâmetros sasl-host e sasl-secprops devidamente configurados no arquivo /etc/openldap/slapd.conf conforme instruções no Passo 1.

Reinicie o serviço do LDAP

# systemctl restart slapd.service

Agora iremos criar um usuário em nossa base de dados LDAP. Mas antes vamos criar uma unidade organizacional LDAP1 (OU) para organizar os usuários que pertencem a este domínio AD.

Crie um arquivo LDAP1.ldif com o seguinte conteúdo

dn: ou=LDAP1,dc=local
objectclass: organizationalUnit
objectclass: top
ou: LDAP1

Agora adicionamos a unidade organizacional utilizando o comando ldapadd

# ldapadd -H ldap://localhost -D cn=Manager,dc=local -w secret -f LDAP1.ldif

adding new entry "ou=LDAP1,dc=local"


A resposta do comando acima indica que a entrada da unidade organizacional foi efetuada com sucesso. Podemos verificar a operação utilizando o comando ldapsearch

# ldapsearch -H ldap://localhost -D cn=Manager,dc=local -w secret -b dc=local -LLL
dn: dc=local
dc: local
objectClass: dcObject
objectClass: organizationalUnit
ou: local

dn: ou=LDAP1,dc=local
objectClass: organizationalUnit
objectClass: top
ou: LDAP1

Criaremos agora um grupo Users com o gid 501 como o grupo padrão para nossos usuários. Crie o arquivo UsersGroup.ldif com o seguinte conteúdo

dn: cn=Users,dc=local
cn: Users
gidnumber: 501
objectclass: posixGroup
objectclass: top

Usamos então o comando ldapadd para adicionar o grupo na base LDAP

# ldapadd -H ldap://localhost -D cn=Manager,dc=local -w secret -f UsersGroup.ldif
adding new entry "cn=Users,dc=local"


Agora criaremos o usuário Angus MacGyver em nossa base LDAP instruindo pelo campo userPassword que este usuário deverá se autenticar via serviço SASL. Crie o arquivo AngusMacGyver.ldif com o seguinte conteúdo

dn: cn=Angus MacGyver,ou=LDAP1,dc=local
cn: Angus MacGyver
gidnumber: 501
givenname: Angus
homedirectory: /home/angus.mcgyver@contoso.com
loginshell: /bin/bash
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: MacGyver
uid: angus.macgyver
uidnumber: 1000
userpassword: {SASL}angus.macgyver@LDAP1

Utilizamos o comando ldapadd para adicionar o usuário em nossa base LDAP

# ldapadd -H ldap://localhost -D cn=Manager,dc=local -w secret -f AngusMacGyver.ldif adding new entry "cn=Angus MacGyver,ou=LDAP1,dc=local"


Agora consultando a base com o comando ldapsearch teremos o seguinte resultado

# ldapsearch -H ldap://localhost -D cn=Manager,dc=local -w secret -b ou=LDAP1,dc=local -LLL
dn: ou=LDAP1,dc=local
objectClass: organizationalUnit
objectClass: top
ou: LDAP1

dn: cn=Angus MacGyver,ou=LDAP1,dc=local
cn: Angus MacGyver
gidNumber: 501
givenName: Angus
homeDirectory: /home/angus.mcgyver@contoso.com
loginShell: /bin/bash
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
sn: MacGyver
uid: angus.macgyver
uidNumber: 1000
userPassword:: e1NBU0x9YW5ndXMubWFjZ3l2ZXJATERBUDE=


Veja que o resultado do comando ldapsearch traz o usuário Angus MacGyver cadastrado na base LDAP. Veja que o campo userPassword está criptografado com base64 mas podemos decodificar esse campo utilizando o comando abaixo para simples verificação do valor armazenado

# echo e1NBU0x9YW5ndXMubWFjZ3l2ZXJATERBUDE= | perl -MMIME::Base64 -ne 'print decode_base64($_) . "\n"'

{SASL}angus.macgyver@LDAP1

Tchan Tchan!!! Esse valor será utilizado para autenticação via SASL

Agora, a partir de um servidor Linux CentOS 7 iremos configurá-lo para se autenticar utilizando a nossa base de dados LDAP.

Na linha de comando utilize o comando authconfig para realizar a configuração

# authconfig --enableldap --enableldapauth --ldapserver=192.168.0.10 --ldapbasedn="dc=local" --enablemkhomedir --update

Agora logue no servidor linux com o usuário angus.macgyver utilizando a senha cadastrada no AD e VIVA!! O seu servidor de Proxy LDAP está devidamente configurado e integrado com o serviço AD.

Você poderá aperfeiçoar essas configurações criando redundância entre mais servidores LDAP replicando a base de metadados e replicando a configuração do Proxy. Deverá também criar um script de inicialização para subir automaticamente o serviço Proxy LDAP toda vez que o servidor for reiniciado. Mais para frente farei mais posts abordando mais um pouco sobre LDAP e apresentando arquivos manifests para o puppet para subir mais servidores proxy para compor a solução.

Por enquanto este post mostra como funciona e como se implanta uma solução com Proxy LDAP que pode ser usada para integrar vários servidores ADs a partir de um único serviço de LDAP.


Até a próxima.

- Rafael Baena


Referencias:

http://ltb-project.org/wiki/documentation/general/sasl_delegation