# Segurança

## Visão Geral de Segurança do GBDS

O GBDS possui um módulo de segurança que usa tokens JWT para realizar autenticação e autorização do usuário. O GBDS pode ser integrado com qualquer diretório de usuários compatível com LDAP para autenticação, e com o Apache Ranger para prover auditoria de autorização e acesso.

### Componentes

Há quatro componentes principais que trabalham juntos para prover segurança às operações do GBDS: Módulo de Segurança do API, Ranger, Solr e o Armazenamento de Credenciais LDAP.

* Módulo de Segurança do API

  > Todas requisições da API primeiro passam pelo módulo de segurança, que impõe autenticação e autorização para recursos protegidos.
* Armazenamento de Credenciais LDAP

  > Uma instância LDAP (como Active Dicertory, OpenLDAP), mantém informação sobre usuários e grupos de usuários, e provê autenticação para o acessar o GBDS API e autorizar as transações da API.
* Ranger

  > Apache Ranger é um framework de segurança que provê um controle de acesso refinado ao GBDS API. Políticas de segurança podem ser criadas para barrar ou permitir acessos aos *endpoints* da API baseado em critérios como grupo de usuário, nome de usuário, recursos requeridos, métodos HTTP usados e endereço de IP.
* Solr

  > O GBDS usa Solr para armazenar logs de acesso para todos pedidos de API, através do painel de controle do Ranger, esses logs podem ser vistos, buscados e exportador.

### Fluxos de Trabalho Habilitados para Segurança

#### Autenticação

Há dois métodos para autenticar com a API. Quando o cliente não possui um token válido, deve ser usada autenticação por credenciais. Nesse caso, o cliente faz um pedido para o endpoint de criação de token, passando um *payload* JSON com as credenciais válidas para um usuário no registrado no LDAP. Em seguida, o Módulo de Segurança cria um vínculo com o diretório LDAP, usando as credenciais do usuário de vinculação (Bind User, veja abaixo), e realiza a autenticação. Então, cria um Sujeito Autenticado: um usuário associado com todos os grupos a que ele pertence. Finalmente, o Módulo de Segurança constrói um token JWT, assina-o digitalmente e o retorna para o cliente. Este token pode ser usado para realizar requisições subsequentes à API do GBDS.

![Authentication Flow](/files/wyapDUKgibF65OxI9T2q)

Quando o cliente já tem um token válido, mas próximo de expirar, é possível usar este token para criar um novo com um tempo de expiração posterior. Primeiro o cliente faz uma requisição para o endpoint de criação de token com o token válido. O Módulo de Segurança validará o token e criará um novo, usando o mesmo Sujeito Autenticado, mas com um novo *expirationTime*. O novo token será enviado ao usuário. Como esse fluxo não exige a consulta ao diretório LDAP, ele é muito mais rápido. Aplicações cliente devem ser projetadas para usar a renovação de token sempre que possível.

![Authentication Flow](/files/OrTIBCv88BLI7pIqmCLn)

#### Realizando uma Requisição de API

Quando um token JWT válido é adquirido, ele é enviado à API do GBDS com toda requisição, seguindo o padrão JWT. A requisição terá um cabeçalho de autorização com o esquema *Bearer*, isso é, `Authorization: Bearer <token>`. Para recursos protegidos, o Módulo de Segurança extrairá o token do cabeçalho e validará sua assinatura usando a Chave de Assinatura original. Se o token for válido, a requisição é autenticada. A seguir, o Módulo de Segurança construirá um *AuthorizationContext* com o nome do sujeito, grupo do sujeito, recursos da requisição, endereço de IP e método HTTP. Este *AuthorizationContext* será enviado ao Ranger para autorizar ou negar a requisição e será gravado pelo Solr, junto de seus resultados: *Allowed* ou *Denied*. Finalmente, se a requisição for autorizada, será encaminhada para a API do GBDS para processamento.

![Making an API Request](/files/5fXJ1wd3RUwhViDgkJ4f)

### Configurações

#### Arquivos

O módulo de segurança usa quatro arquivos de configuração diferentes:

* `/etc/griaule/conf/gbscluster.properties`: Arquivo primário de configuração do GBDS. Quando a segurança está ativa, opções de segurança são configuradas neste arquivo.
* `/etc/griaule/conf/gbsapi/keystore.jks`: *Keystore* protegida por senha contendo o **Ldap Bind User Password** e **JWT Signing Key**. Somente acessível pelo usuário griaule.
* `/etc/griaule/conf/gbsapi/truststore`: *Truststore* protegida por senha contendo o **Ldap Server Certificate** para permitir conexões LDAP. Somente acessível pelo usuário griaule.
* `/etc/griaule/conf/gbsapi/.password`: Arquivo de senhas contendo as senhas de *keystore* e *truststore*. As senhas são armazenadas em texto claro, e só deve ser acessível pelo usuário griaule.

#### Opções de Segurança

O GBDS pode funcionar com ou sem a segurança ativada, e isso é controlado pela chave de configuração booleana: `gbscluster.api.security.enabled`. Quando essa chave é definida como *false*, toda segurança é desabilitada e todas as outras chaves de segurança são ignoradas. Se for definida como *true*, as seguintes chaves de configuração **DEVEM** também ser configuradas:

**Gerais**

* `gbscluster.api.security.keystore`: caminho para o *keystore* gerado a partir do script de geração do *keystore*
* `gbscluster.api.security.truststore`: caminho para o *truststore* que possui o certificado do servidor LDAP. Requerido para usar LDAPs.
* `gbscluster.api.security.passwords`: caminho para o arquivo contendo as senhas do *truststore* e *keystore*. Esse arquivo deve ter acesso restrito ao usuário griaule.

**Autenticação**

* `gbscluster.api.security.ldap.url`: URL de conexão ao servidor de armazenamento de usuário LDAP.
* `gbscluster.api.security.ldap.userSearchBase`: Nome Distinto/Distinguished Name (DN) do repositório de usuários no servidor LDAP. Exemplo: `ou=Users,dc=pd,dc=griaule`
* `gbscluster.api.security.ldap.userSearchAttribute`: Atributo de usuário que será usado como nome de usuário durante a autenticação. Exemplo: `sAMAccountName`, `uid`
* `gbscluster.api.security.ldap.userGroupMembershipAttribute`: Atributo de usuário contendo as informações de associação de grupo. Exemplo: `memberOf`
* `gbscluster.api.security.ldap.bindUserDN` Nome distinto do usuário de vinculação (Bind User). O usuário de vinculação é uma conta de usuário usada pelo GBDS para vincular ao servidor LDAP, autenticar usuários e buscar seus grupos.

**Token**

* `gbscluster.api.security.token.ttlInMilliseconds`: Tempo de vida, em milissegundos, do token JWT. Valores válidos: entre 30 minutos e 3 horas.

**Autorização**

* `gbscluster.api.security.authorization.ranger.configurationDirectory`: Diretório com as configurações específicas do ranger do GBDS.

## Integrando com o Diretório Ativo

### Verificando Resolução de DNS

Antes de iniciar, certifique-se que a resolução de nome para o domínio em que as máquinas de cluster serão integradas está funcionando corretamente. Para o domínio chamado de pd.griaule, use o seguinte comando:

```sh
dig -t SRV _ldap._tcp.pd.griaule
```

{% hint style="info" %}
Certifique-se que a SEÇÃO DE RESPOSTA está presente e contém o hostname e o endereço IP do controlador do domínio.
{% endhint %}

{% hint style="warning" %}
**Resolva qualquer problema na resolução de DNS antes de continuar.**
{% endhint %}

### Instalando os Pacotes Necessários

```sh
sudo yum install realmd sssd oddjob oddjob-mkhomedir adcli sssd-ad sssd-tools
```

### Integrando com o DA

Usar o utilitário *realm* é a forma mais conveniente de integrar SSSD com DA. Execute o seguinte comando para mostrar as informações básicas sobre o domínio:

```sh
realm discover <domain_name>
```

#### Entre no Domínio

Para entrar, você necessitará de uma conta que pertença ao grupo de administradores do domínio.

```sh
sudo realm join -U <username> <domain_name>
```

Depois, habilite NSS e PAM com:

```sh
authconfig --enablesssd --update
```

E, finalmente, verifique se a máquina ingressou no domínio com sucesso consultando um usuário no domínio:

```sh
id <username>@<domain_name>
```

#### Solucionando Erros

Se algum problema surgir, use as seguintes dicas:

* Verifique novamente a resolução de nomes do DNS. Esta é a causa mais frequente de erros.
* Certifique-se que os diretórios `/etc/sssd/` e `/etc/sssd/conf.d` existem e ambos possuem permissão 0600.
* Aumente o debug\_level em `/etc/sssd/sssd.conf` em todas as sessões, isto é, `[sssd]`, `[nss]`, `[pam]`, `[domain]`. Então, reinicie o serviço sssd: `sudo service sssd restart`. Os logs serão gerados na pasta `/var/log/sssd/`
* No caso do erro `Insufficient permission to join the domain ...`: o usuário usado para entrar no domínio não possui permissão. Verifique se o usuário faz parte do `Domain Admins group`

## Integrando com o OpenLdap

Esse guia explica como realizar a instalação **mínima** do OpenLDAP que será compatível com o GBDS para autenticação e autorização.

### Instale o OpenLdap

#### Dependências

Conecte-se ao host LDAP e instale os pacotes necessários:

```sh
sudo yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel
```

#### Inicie Ldap Daemon

Seguindo, inicie o LDAP Daemon e configure para que ele inicialize automaticamente no boot do sistema:

```sh
systemctl start slapd.service

systemctl enable slapd.service
```

#### Gere a senha de root

Execute o comando `ldappasswd` para criar uma senha root do LDAP. Escreva tanto a senha normal como a versão codificada retornada pelo `ldappasswd`.

```sh
sudo slappasswd
```

#### Crie o hdb-database

O *hdb* é uma variante hierárquica do backend de banco de dados bdb. No modelo de configuração abaixo, defina as seguintes variáveis de acordo com seu caso de uso:

* **olcSuffix**: Representa o nome de domínio para qual o o LDAP ira fornecer a informação da conta. Adicionalmente, esse nome distinto irá ser adicionado às *queries* que serão enviadas ao backend.
* **olcRootDN**: é o nome distinto do usuário que irá possuir acesso de administrador ao servidor LDAP.
* **olcRootPW**: Define a senha do usuário administrador. A senha será o resultado codificado do comando `slappasswd`, que foi executado previamente.

Coloque a configuração em um arquivo chamado `db.ldif`.

{% hint style="warning" %}
**CERTIFIQUE-SE DE SUBSTITUIR o olcRootPW, olcRootDN e o olcSuffix.**
{% endhint %}

```default
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=oldap,dc=pd,dc=griaule

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=ldapadm,dc=oldap,dc=pd,dc=griaule

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}theHashedPasswordValueFromSlapPasswd
```

{% hint style="warning" %}
Certifique-se de que não há espaços desnecessários ou linhas vazias, ou problemas poderão ocorrer. Veja: <https://serverfault.com/questions/578710/wrong-attributetype-when-using-ldapadd>
{% endhint %}

Envie as mudanças ao servidor

```sh
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f db.ldif
```

{% hint style="warning" %}
Se você não usar *sudo*, terá problemas de permissão: `ldap_modify: Insufficient access (50)`
{% endhint %}

#### Restrinja o Acesso de Monitoramento ao ldapadm

Coloque as seguintes configurações no arquivo chamado `monitor.ldif` e atualize o `dn.base`, onde está escrito *UPDATE ME*, com o nome distinto do valor definido previamente ao `oclRootDN`.

```default
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" read by dn.base="UPDATE ME" read by * none
```

Envie as mudanças ao servidor

```sh
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f monitor.ldif
```

{% hint style="warning" %}
Se você não usar *sudo*, você terá problemas de permissão: `ldap_modify: Insufficient access (50)`
{% endhint %}

#### Adicione o arquivo de configuração do hdb-backend

Este arquivo define as opções de configurações básicas para o hdb-backend:

```sh
sudo cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
sudo chown ldap:ldap /var/lib/ldap/DB_CONFIG
```

#### Adicione esquemas essenciais do LDAP

```sh
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
```

#### Habilite o módulo memberOf

{% hint style="warning" %}
**É NECESSÁRIO FAZER ISSO ANTES DE QUALQUER GRUPO SER CRIADO. O ATRIBUTO MEMBEROF É UM ATRIBUTO OPERACIONAL E NÃO É CRIADO RETROATIVAMENTE.**
{% endhint %}

Este módulo é necessário para a consulta dos grupos de um usuário. Coloque a seguinte configuração no arquivo chamado `memberof_config.ldif`:

```default
dn: cn=module,cn=config
cn: module
objectclass: olcModuleList
objectclass: top
olcmoduleload: memberof.la
olcmodulepath: /usr/lib64/openldap

dn: olcOverlay={0}memberof,olcDatabase={2}hdb,cn=config
objectClass: olcConfig
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOf
```

Para enviar as mudanças ao servidor, execute o comando:

```sh
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_config.ldif
```

#### Gere o banco de dados para seu domínio

Finalmente, especificamos o banco de dados, que usará as configurações previamente criadas, para fornecer todas requisições ao domínio (valor de `olcSuffix`). Atualize o DN de *Users* e *Groups* para coincidir com as configurações do domínio. Insira as configurações em `db_structure.ldif`.

```default
# Create entry for domain
dn: dc=oldap,dc=pd,dc=griaule
objectClass: domain
objectClass: top
dc: oldap

# Create an OU for Users
dn: ou=Users,dc=oldap,dc=pd,dc=griaule
objectClass: organizationalUnit
ou: Users

# Create an OU for Groups
dn: ou=Groups,dc=oldap,dc=pd,dc=griaule
objectClass: organizationalUnit
ou: Groups
```

Para enviar as mudanças para o servidor, use a conta de administrador configurada (`olcRootDN`) depois do parâmetro `-D`. O utilitário `ldapadd` perguntará pela senha da conta de administrador previamente definida.

```sh
sudo ldapadd -x -D 'cn=ldapadm,dc=oldap,dc=pd,dc=griaule' -W -H ldapi:/// -f db_structure.ldif
```

### Solucionando Erros

Note que as mensagens de erro retornadas pelo OpenLdap podem ser confusas. Se tiver problemas com a instalação, é recomendável habilitar o modo debug. Pare o serviço slapd e então reinicie diretamente o processo com a flag de debug `-d -1`:

```sh
slapd -d -1 -u ldap -h "ldap:/// ldapi:///"
```

Se o TLS estiver habilitado, inclua também a string para o endpoint do ldaps:

```sh
slapd -d -1 -u ldap -h "ldap:/// ldapi:/// ldaps:///"
```

### Criptografando senhas OpenLdap

Por padrão, OpenLdap armazena as senhas em texto claro. Para mudar este comportamento, é necessário: [Definir um algoritmo global de hash](#configurando-o-algoritmo-hash) de senhas e [habilitar a política de senhas](#criando-uma-politica-de-senha-padrao) para automaticamente criptografar qualquer senha em texto claro.

#### Configurando o Algoritmo Hash

Usaremos o algoritmo SHA-512 com 50000 rodadas e sal de 16 bytes. Crie um arquivo chamado `hash_algorithm.ldif`

```default
dn: cn=config
replace: olcPasswordHash
olcPasswordHash: {CRYPT}

dn: cn=config
replace: olcPasswordCryptSaltFormat
olcPasswordCryptSaltFormat: $6$rounds=50000$%.16s
```

Para enviar as configurações ao servidor:

```sh
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f hash_algorithm.ldif
```

#### Importar o Esquema de Política de Senha

```sh
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/ppolicy.ldif
```

#### Carregar o módulo de Política de Senha

Crie um arquivo chamado `password_policy_config.ldif` contendo:

```default
# load password policy module
dn: cn=module,cn=config
cn: module
objectClass: top
objectClass: olcModuleList
olcModuleLoad: ppolicy.la
olcModulePath: /usr/lib64/openldap

# apply the password policy overlay our database
dn: olcOverlay={1}ppolicy,olcDatabase={2}hdb,cn=config
objectClass: olcPPolicyConfig
objectClass: olcOverlayConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=Password Policy,ou=Policies,dc=oldap,dc=pd,dc=griaule
olcPPolicyForwardUpdates: FALSE
olcPPolicyHashCleartext: TRUE
olcPPolicyUseLockout: FALSE
```

Então envie as mudanças com:

```sh
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f password_policy_config.ldif
```

Se você encontrar um erro indicando que o pwdAttribute não existe, isto significa que o esquema de política de senha não foi importado.

#### Criando uma Política de Senha Padrão

Crie um arquivo chamado `password_policy.ldif` contendo:

```default
# create default password policy
dn: cn=Password Policy,ou=Policies,dc=oldap,dc=pd,dc=griaule
objectClass: top
objectClass: device
objectClass: pwdPolicy
cn: Password Policy
```

Então envie as mudanças com o comando abaixo, substituindo o `olcRootDN`:

```sh
sudo ldapadd -x -D '<olcRootDN>' -W -H ldapi:/// -f db_structure.ldif
```

### Melhorando a Segurança

#### Desativando Vinculação Anônima

Crie um arquivo `disable_anon_binding.ldif` contendo:

```default
dn: olcDatabase={-1}frontend,cn=config
add: olcRequires
olcRequires: authc

dn: olcDatabase={2}hdb,cn=config
add: olcRequires
olcRequires: authc
```

Então envie as mudanças:

```sh
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f disable_anon_binding.ldif
```

Para testar se as mudanças funcionaram, execute a seguinte busca anônima:

```sh
# without TLS
ldapsearch -x -LLL -H ldapi:/// "(cn=*)"
# Or with TLS
ldapsearch -x -LLL -H ldaps:/// "(cn=*)"
```

#### Desativando Permissão de Leitura para Senhas de Usuário

Finalmente, qualquer usuário pode obter a senha de outro usuário. Mesmo que as senhas estejam criptografadas, isso deve ser evitado. Ainda mais se for decidido manter as senhas em texto claro. Então, crie um arquivo chamado `disabled_password_read.ldif`.

{% hint style="warning" %}
**CERTIFIQUE-SE QUE NÃO HÁ QUEBRA DE LINHA PARA olcAccess**
{% endhint %}

```default
dn: olcDatabase={2}hdb,cn=config
add: olcAccess
olcAccess: to attrs=userPassword by dn="<olcRootDN>" write by self write by * auth
-
add: olcAccess
olcAccess: to * by dn="<olcRootDN>" write by users read by self write by * auth
```

Envie as mudanças:

```sh
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f disabled_password_read.ldif
```

Se você executar uma busca vinculada com qualquer usuário que não for o olcRootDN, a única senha retornada será a do próprio usuário.

```sh
ldapsearch -x -D '<non_root>' -LLL -H ldapi:/// "(cn=*)"
```

### Habilitando LDAPs

Antes de continuar, certifique-se que sua instância do OpenLdap está funcionando e que ela possui duas unidades organizacionais: uma para os usuários e uma para os grupos. Você pode fazer isso usando o Apache Directory Studio para conectar ao servidor usando a URL de conexão ldap, por exemplo: <ldap://192.168.0.100:389>, e com sua conta de administrador configurada (**olcRootDN**).

Para habilitar LDAPS, será necessário um certificado válido assinado por uma autoridade confiável (trusted authority). Alternativamente, nós provemos um guia de como configurar seu próprio certificado de autoridade e como usar isso para assinar certificados do seu servidor.

#### Crie seu CA

Se você já tem um certificado válido, você pode pular esse passo.

No CentOS, você encontrará o arquivo `openssl.cnf`, que contém a configuração principal para seu CA, no diretório `/etc/pki/tls`. Todavia, o nosso CA será colocado em `/etc/pki/CA`.

Primeiro, crie o arquivo `index.txt` e os arquivos seriais, que conterão informações dos certificados assinados e número serial certificado a ser usado, respectivamente.

```sh
touch /etc/pki/CA/index.txt
echo '01' > /etc/pki/CA/serial
```

Seguindo, adicione as seguintes políticas para `/etc/pki/tls/openssl.cnf`:

```properties
# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ signing_policy ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ signing_req ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
```

Agora, mude para o diretório do CA:

```sh
cd /etc/pki/CA
```

Nós geraremos o certificado CA, válido por 10 anos, com o comando a seguir. O utilitário pedirá que você defina a senha da chave privada e informações sobre o sujeito do certificado (o CA, nesse caso). Anote esta senha, ela será exigida para assinar certificados.

```sh
openssl req -config /etc/pki/tls/openssl.cnf -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 3650
```

Em seguida, limite os direitos de acesso à chave privada do CA:

```sh
chmod 0400 private/cakey.pem
```

#### Crie um Certificado do Servidor LDAP

Primeiro, criamos uma requisição de assinatura do certificado para o servidor LDAP:

```sh
openssl req -config /etc/pki/tls/openssl.cnf -newkey rsa:2048 -nodes -sha256 -out ldap_cert.csr -outform PEM -keyout ldap_key.pem
```

Depois, assinamos o `server.csr` usando a chave privada do CA:

```sh
openssl ca -config /etc/pki/tls/openssl.cnf -policy signing_policy -extensions signing_req -out ldap_cert.pem -infiles ldap_cert.csr
```

Agora, o `ldap_cert.pem` é o certificado para seu servidor e sua chave privada está no arquivo `ldap_key.pem`.

{% hint style="info" %}
a chave privada para o servidor não está criptografada (`-nodes` parameter). Isto é menos seguro, mas o **OpenLdap não tem suporte para chaves criptogradas**. Então, é indispensável restringir todo acesso a esse arquivo, como será feito nos próximos passos.
{% endhint %}

#### Configurando o OpenLdap para usar o certificado e a chave

Primeiro, copie o certificado CA para `/etc/openldap/cacerts`. Isto fará o OpenLdap confiar no certificado assinado pelo seu CA.

```sh
mkdir /etc/openldap/cacerts
cp /etc/pki/CA/cacert.pem  /etc/openldap/cacerts
chown -R ldap:ldap /etc/openldap/cacerts/
```

Em seguida, instale o certificado do seu servidor ldap em `/etc/openldap/certs`:

```sh
mv /etc/pki/CA/ldap_cert.pem /etc/openldap/certs
chown ldap:ldap /etc/openldap/certs/ldap_cert.pem

mv /etc/pki/CA/ldap_key.pem /etc/openldap/certs
chown ldap:ldap /etc/openldap/certs/ldap_key.pem
chmod 400 /etc/openldap/certs/ldap_key.pem
```

Definir a permissão 400 para a chave privada do servidor é **INDISPENSÁVEL**.

Crie um arquivo chamado `enable_ldaps.ldif` com as seguintes configurações:

```default
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/openldap/cacerts/cacert.pem
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/ldap_cert.pem
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/ldap_key.pem
```

Então, envie as mudanças para o servidor e teste os arquivos de configuração:

```sh
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f enable_ldaps.ldif
```

#### Habilite o Endpoint TLS

No arquivo `/etc/sysconfig/slapd`, adicione `ldaps:///` na linha que começa com `SLAPD_URLS=`. Depois disso, a linha deve ser similar a:

```properties
SLAPD_URLS="ldapi:/// ldap:/// ldaps:///"
```

#### Forçar o TLS

Crie um arquivo chamado `force_tls.ldif` com o seguinte conteúdo:

```default
dn: olcDatabase={2}hdb,cn=config
changetype:  modify
add: olcSecurity
olcSecurity: tls=1
```

Então, envie as mudanças para o servidor:

```sh
sudo ldapmodify -v -Y EXTERNAL -H ldapi:/// -f force_tls.ldif
```

Agora teste o requerimento TLS rodando a seguinte busca. Ela deve ser negada devido ao requerimento do TLS:

```sh
ldapsearch -H ldap://<host> -D "cn=ldapadm,dc=oldap,dc=pd,dc=griaule" -W '(uid=ldapadm)'
```

{% hint style="warning" %}
A PARTIR DE AGORA, QUALQUER CHAMADA DO `ldapi:///` QUE NECESSITE DO *olcRootDN* (i.e. aquelas que criam entidades na árvore do diretório) NECESSITA SER REALIZADA NO `ldaps:///`. CHAMADAS QUE PODEM USAR `-Y EXTERNAL` (i.e., que modifica `cn=config`) PODEM AINDA USAR `ldapi:///`.
{% endhint %}

#### Configuração do TLS do lado do cliente

Para permitir que utilitários como `ldapsearch` se conectem via TLS, adicione `TLS_REQCERT allow` para `/etc/openldap/ldap.conf`:

```sh
echo "TLS_REQCERT allow" >> /etc/openldap/ldap.conf
```

### Crie um Usuário Vinculado para o Ranger do GBDS

O GBDS e o Ranger exigirão que o usuário vincule-se ao servidor LDAP para executar queries e autenticações. O único privilégio que este usuário necessita é ler a árvore de diretórios.

{% hint style="warning" %}
Não use o olcRootDN como o usuário de vínculo.
{% endhint %}

Crie um arquivo chamado `bind_user.ldif` com o seguinte conteúdo. **Substitua** o `dn:` por um que coincida com sua instalação. Adicionalmente, defina a senha do usuário de vinculação. Se você habilitar a criptografia de senha, escreva a senha em texto claro. Senão, use o slappasswd para produzir um hash para a senha e escreva o hash no arquivo `.ldif` (Similar a como foi criado a senha do **olcRootDN**).

```default
dn: cn=gbds_bind,ou=Users,dc=oldap,dc=pd,dc=griaule
objectClass: top
objectClass: person
objectClass: inetOrgPerson
cn: gbds_bind
uid: gbds.bind
sn: Bind User
userPassword: <password>
```

Envia as mudanças com:

```sh
# for tls enabled
ldapadd -D "<olcRootDN>" -W -H ldaps:/// -f bind_user.ldif
# without tls
ldapadd -D "<olcRootDN>" -W -H ldapi:/// -f bind_user.ldif
```

Para testar se o usuário foi criado corretamente, execute a seguinte busca autenticando com o usuário vinculado `credentials:his`

```sh
ldapsearch -D "<bind_user_dn>" -W -H ldaps:/// "(cn=gbds_bind)"
```

### API do LDAP

A API LDAP é uma API fornecida pela Griaule para auxiliar o gerenciamento de usuários e grupos. Você pode autenticar, criar, excluir ou modificar dados de usuários e listar dados de usuários e dados de grupos por meio da API.

{% hint style="info" %}
Se os arquivos da API não foram fornecidos, entre em contato com a Equipe de Suporte da Griaule.
{% endhint %}

A API completa pode ser acessada em [Api do LDAP](/apis/ldap.md).

{% hint style="warning" %}
A API funciona com segurança SSL e é necessário uma truststore e keystore. Para mais informações sobre a criação dessas, veja a seção [Configurando a Segurança do GBDS](#configurando-a-segurança-do-gbds).
{% endhint %}

#### Configurando a API

Para instalar e configurar corretamente a API, siga as etapas:

1. Extraia o pacote fornecido.
2. Em `/etc/griaule` crie o diretório `ldap`.
3. Mova o diretório `conf` do pacote fornecido para o diretório `/etc/griaule/ldap`.
4. Mova o `config.properties` para o diretório `/etc/griaule/ldap`.
5. Abra o arquivo `config.properties` e ajuste os parâmetros de configuração de acordo com seu ambiente.
6. Em `/var/lib/griaule` crie o diretório `ldap`.
7. Mova o arquivo `bs-ldap-api.jar` e o script `kill-api.sh` e `start-api.sh` para o novo diretório.
8. Execute o script de início (start).

#### Criando Novos Usuários e Grupos

Para criar um novo usuário, chame [Create User](https://gitbook.griaule.com/apis/ldap/create#post-ldap-user). A API criará o usuário, a senha e os grupos aos quais o usuário pertence.

Se forem necessárias modificações em um usuário existente, chame [Modify User Data](https://gitbook.griaule.com/apis/ldap/user#put-ldap-user-user).

Para recuperar dados do usuário, chame [Get User Data](https://gitbook.griaule.com/apis/ldap/user#get-ldap-user-user).

Para adicionar, modificar ou excluir grupos, acesse `/etc/griaule/ldap/conf/group-list.json` e modifique o arquivo de acordo com o desejado. Você também pode ver todos os grupos chamando [List Groups](https://gitbook.griaule.com/apis/ldap/list#get-ldap-user-groups).

## Instalando o Ranger

Depois que o OpenLdap ou o Active Directory estiverem configurados, pode-se proceder para instalação do Ranger.

### Pré-requisitos

#### Instalando o ambari-infra

Vá para o ambari e instale o serviço Ambari-infra. Isso proverá uma instância do Solr para armazenar data auditada para o Ranger.

#### Instale e Configure a Instância MySQL

1. Instale uma instância do MySQL
2. Crie o usuário rangerdba e conceda os privilégios necessário

   ```sql
   CREATE USER 'rangerdba'@'localhost' IDENTIFIED BY 'Rangerdba$1';

   GRANT ALL PRIVILEGES ON *.* TO 'rangerdba'@'localhost' IDENTIFIED BY 'Rangerdba$1' WITH GRANT OPTION;

   CREATE USER 'rangerdba'@'%' IDENTIFIED BY 'Rangerdba$1';

   GRANT ALL PRIVILEGES ON *.* TO 'rangerdba'@'%';

   GRANT ALL PRIVILEGES ON *.* TO 'rangerdba'@'%' IDENTIFIED BY 'Rangerdba$1' WITH GRANT OPTION;

   FLUSH PRIVILEGES;
   ```

   > Note que Rangerdba$1 é a senha para o usuário rangerba. Substitua pela senha desejada.
3. Teste se o usuário rangerdba foi criado com sucesso: `mysql -u rangerdba -p`
4. Instale o conector MySQL: `yum install mysql-connector-java*`
5. Registre o conector com o ambari, executando os seguintes comandos no host com o servidor ambari instalado: `ambari-server setup --jdbc-db=mysql --jdbc-driver=/usr/share/java/mysql-connector-java.jar`

### Instalando o Serviço do Ranger

Vá para o ambari e adicione o serviço do Ranger. Visite cada uma das seguintes abas de configuração antes de finalizar a instalação.

#### Ranger Admin

1. Deixe o nome de usuário do Ranger DB como `rangeradmin`. Coloque a senha que você quiser, mas salve-a para depois.
2. Certifique-se que as opções `Setup Database` e `Database User` estão marcadas como `Yes`
3. Para o nome de usuário DBA, use a conta de usuário criada nos passos anteriores.

#### Informações de Usuários do Ranger

Esse serviço importará usuários e grupos no banco de dados do ranger.

{% hint style="info" %}
Abaixo, nos damos **SUGESTÕES** para valores em várias opções de configurações requeridas. Você deve se certificar de que correspondem à sua implantação LDAP.
{% endhint %}

1. Mude o *Sync Source* para o `Ldap/AD`
2. Na aba *Common Config*:
   1. **LDAP/AD URL**: Se a URL configurada aqui for para o LDAPS, o certificado do LDAPS necessitará ser importada no usersync truststore como se for descrito na seção [Importar o Certificado Ldaps](#importar-o-certificado-ldaps)
   2. **Bind User**: Preencha o usuário DN vinculado e a senha. O usuário só precisa ter privilégio de leitura para o repositório de Usuários e Grupos.
3. Na aba *User Configs*:
   1. **Username Attribute**: atributos que armazenam o userName para login. Para AD, **usualmente** `sAMAccountName` e para o OpenLdap, `uid`.
   2. **User Search Base**: DN para o nó que contém o usuário que necessita ser sincronizado (Usuário AD).
4. Na aba *Group Configs*:
   1. **Group member Attribute**: Atributo da entidade de Grupos que armazena qual usuário pertence a qual grupo, além de informação sobre a associação usuário-grupo. É **usualmente** `member`
   2. **Group Name Attribute**: Atributo do grupo que contém o nome do grupo. **Usualmente** `cn`
   3. **Group Object Class**: Classe da entidade de grupo. Para AD, é **usualmente** `group`, para o OpenLdap é **usualmente** `groupOfNames`
   4. **Group Search Base**: com o nó que contém os grupos que precisam ser sincronizados

#### Ranger Audit

1. Marque a opção `Audit to Solr`
2. Marque a opção `Solr Cloud`

### Checagem da Instalação

#### Sincronização de Usuário

Vá para o website do ranger em `http://<host>:6080`, faça o login e vá para *Settings*, e então, *Users/Groups*. Todos os usuários e grupos da *User/Group Search Base* devem estar presentes. Se não for o caso, ocorreu um problema com a sincronização de usuário. Verifique o log em `/var/log/ranger/usersync/usersync.log` para identificar o erro.

#### Solr Audit

Vá ao ambari-infra UI e verifique a existência da coleção `ranger_audits`

### Habilitando a Integração do Ldap com TLS

Para habilitar o Ranger a usar o LDAPS em vez do LDAP, duas mudanças precisam ser feitas. Primeiro, precisamos atualizar a URL de conexão do ldap para a URL protegida pelo TLS. Segundo, precisamos importar o certificado LDAPS.

#### Mudando a URL de Conexão do Ldap

Vá, para o Ambari, *Ranger*, *Configs*, *Ranger User Info*, *Common Configs*. Mude o LDAP/AD URL para `ldaps://<hostname>:636`

#### Importar o Certificado Ldaps

Se seu repositório Ldap está usando TLS, você precisa importar seu certificado no *UserSync truststore* do ranger.

Para obter a localização do *truststore*, vá para o Ambari, *Ranger*, *Configs*, *Advanced*, *Advanced ranger-ugsync-site*, `ranger.usersync.truststore.file`. Então, use o keytool do Java para importar o certificado do Ldaps na *truststore*. Se a *truststore* já existir, haverá necessidade de uma senha. Se não, anote a senha usada. Você precisará dela depois.

```sh
sudo keytool -import -trustcacerts -alias $ALIAS -file $PATH_TO_YOUR_LDAPS_CERT -keystore /usr/hdp/current/ranger-usersync/conf/mytruststore.jks
```

Seguindo, corrija a permissão e o proprietário da *truststore*.

```sh
sudo chmod 640 /usr/hdp/current/ranger-usersync/conf/mytruststore.jks
sudo chown ranger:ranger /usr/hdp/current/ranger-usersync/conf/mytruststore.jks
```

Se a *truststore* for nova, vá para o Ambari, *Ranger*, *Configs*, *Advanced*, *Advanced ranger-ugsync-site* e defina as propriedades:

1. **ranger.usersync.truststore.file**: com o caminho absoluto para a *truststore*
2. **ranger.usersync.truststore.password**: senha para a *truststore*

#### Solucionando Erros

Se não é possível criar o SSLContext para comunicação com o gerenciador de políticas, há um problema com as credenciais e as chaves do usersync. O único modo de resolver esse problema é deletar a *truststore* `/usr/hdp/current/ranger-usersync/conf/mytrustore.jks`, recriá-la com o certificado do Ldaps e atualizar a configuração de senha no Ambari, *Ranger*, *Configs*, *Advanced ranger-usersync-site*

## Configurando a Segurança do GBDS

Uma vez que o Ranger, o Solr e o servidor Ldap estiverem instalados e configurados, podemos seguir para as configurações do GBDS.

### Criando o Keystore do GBDS

O keystore será usado para salvar as senhas dos usuários vinculados e chaves de assinatura para os tokens JWT gerados pela API.

Execute o script `/var/lib/griaule/gbsapi/scripts/create_keystore.py` passando o caminho para o novo banco de chaves e o caminho para criar o arquivo de senhas. O script perguntará pela senha do usuário vinculado a ser salva. Depois, o script criará o keystore com a senha do usuário vinculado e uma chave de assinatura aleatória. O keystore será protegido por uma senha gerada aleatoriamente, a qual será salva no arquivo de senha especificado. Por fim, o arquivo do keystore e de senhas terá as permissões alteradas para somente leitura.

```sh
python /var/lib/griaule/gbsapi/scripts/create_keystore.py --store_path /etc/griaule/conf/gbsapi/keystore.jks --password_file /etc/griaule/conf/gbsapi/.passwords
```

{% hint style="info" %}
O arquivo de senhas contém as senhas em texto plano. Portanto, é indispensável que isso seja mantido em uma localização segura de acesso permitido somente ao usuário *griaule*.
{% endhint %}

### Criando *trustore* para o LDAPS

Se você pretende conectar ao seu servidor LDAP usando SSL, precisa importar o certificado do servidor para uma *truststore* e configurar o GBDS para usá-lo.

Assumindo que o certificado do servidor chama-se `server_cert.pem`, execute o seguinte comando e use uma senha forte para o *truststore*:

```sh
sudo keytool -import -trustcacerts -alias ldap_server -file <certificate_file> -keystore /etc/griaule/conf/gbsapi/truststore
chown griaule:griaule /etc/griaule/conf/gbsapi/truststore
chmod 400 /etc/griaule/conf/gbsapi/truststore
```

Além de criar a *truststore*, esse comando restringirá o acesso ao usuário griaule. Depois, salve a senha da *truststore* no arquivo de senhas.

```sh
sudo -u griaule chmod u+w /etc/griaule/conf/gbsapi/.passwords && sudo -u griaule echo "truststore=<YOUR_PASSWORD>" >> /etc/griaule/conf/gbsapi/.passwords && sudo -u griaule chmod 400 /etc/griaule/conf/gbsapi/.passwords
```

### Atualizando o Arquivo de Configuração

Edite o arquivo `/etc/griaule/conf/gbscluster.properties` e modifique as seguintes propriedades:

1. **gbscluster.api.security.enabled**: defina como *true* para habilitar a segurança.
2. **gbscluster.api.security.keystore**: caminho para o keystore que você criou (`/etc/griaule/conf/gbsapi/keystore.jks`)
3. **gbscluster.api.security.truststore**: caminho para a *truststore* que você criou (`/etc/griaule/conf/gbsapi/truststore`)
4. **gbscluster.api.security.passwords**: caminho para o arquivo de senhas (`etc/griaule/conf/gbsapi/.passwords`)
5. **gbscluster.api.security.ldap.url**: URL do servidor Ldap, exemplo: `ldap://<host>:389`. Se você habilitou Ldaps, isso deve ser `ldaps://<host>:636`
6. **gbscluster.api.security.ldap.userSearchBase**: O DN do nodo da árvore que guarda os usuários que estarão habilitados para autenticação no GBDS. No seu guia de instalação do OpenLdap, o DN deveria ser: `ou=Users,dc=oldap,dc=pd,dc=griaule`

   > **É NECESSÁRIO QUE SEJA O MESMO DN CONFIGURADO NO RANGER**
7. **gbscluster.api.security.ldap.userSearchAttribute**: Atributo da entidade Usuário que contém o `userName`, que será usado durante a autenticação.

   > **É NECESSÁRIO QUE SEJA O MESMO CONFIGURADO NO RANGER**
8. **gbscluster.api.security.ldap.userGroupMembershipAttribute**: Atributo da entidade Usuário que contém o DN dos grupos que pertence. Usualmente memberOf.

   > **É NECESSÁRIO QUE SEJA O MESMO CONFIGURADO NO RANGER**
9. **gbscluster.api.security.ldap.bindUserDN**: DN do usuário vinculado. Use o mesmo configurado para o Ranger.
10. **gbscluster.api.security.token.ttlInMilliseconds**: Tempo de vida, em milissegundos, para o token JWT gerado pela API. Os valores válidos são entre 30 minutos e 3 horas. Recomendamos 1 hora.

## Instalando o Serviço de Autorização do Ranger

Para instalar e executar o serviço de autorização do Ranger, é necessário ter criado um usuário GBDS e um usuário ADMIN.

Para criar o usuário administrador, abra o arquivo `administrator_group.ldif` na pasta `/etc/openldap` e adicione o seguinte ao arquivo:

```default
dn: cn=administrator,ou=Groups,dc=oldap,dc=pd,dc=griaule
objectclass: groupofnames
cn: administrator
description: IT Security Group
# Add the group members all of which are assumed to exist under people
member: cn=gbds_bind,ou=Users,dc=oldap,dc=pd,dc=griaule
```

Em seguida, no arquivo `gbds_user.ldif`, crie o usuário GBDS.

```default
dn: cn=gbds_user,ou=Groups,dc=oldap,dc=pd,dc=griaule
objectclass: groupofnames
cn: gbds_user
description: IT Security Group
# Add the group members all of which are assumed to exist under people
member: cn=gbds_bind,ou=Users,dc=oldap,dc=pd,dc=griaule
```

Aplique as alterações reiniciando o Ranger por meio da GUI do Ambar.

```sh
sudo ldapadd -D "cn=ldapadm,dc=oldap,dc=pd,dc=griaule" -W -H ldapi:/// -f /etc/openldap/administrator_group.ldif
sudo ldapadd -D "cn=ldapadm,dc=oldap,dc=pd,dc=griaule" -W -H ldapi:/// -f /etc/openldap/gbds_user.ldif
```

{% hint style="info" %}
Se o TLS estiver ativo, lembre-se de alterar `ldapi:///` por `ldaps:///`.
{% endhint %}

Quando as alterações forem aplicadas, execute a Política de autorização do Ranger.

```sh
java -jar /root/ranger-authorization-service-installer-1.0-SNAPSHOT-jar-with-dependencies.jar -admin_password 'Griaule.123' -admin_username admin -ranger_url http://127.0.0.1:6080
```

Para finalizar o processo, atualize os Arquivos XML do Ranger. Vá para `/etc/griaule/conf/gbsapi/` e no arquivo `ranger-gbds-audit.xml`, modifique de acordo:

```xml
<name>xasecure.audit.jpa.javax.persistence.jdbc.url</name>
<value>jdbc:mysql://127.0.0.1:3306/ranger_audit</value>

<name>xasecure.audit.kafka.broker_list</name>
<value>localhost:9092</value>

<name>xasecure.audit.solr.solr_url</name>
<value>http://localhost:6083/solr/ranger_audits</value>

<name>xasecure.audit.destination.solr.urls</name>
<value>http://localhost:8886/solr/ranger_audits</value>
```

Faça o mesmo para `ranger-gbds-security.xml`

```xml
<name>ranger.plugin.gbds.policy.rest.url</name>
<value>http://localhost:6080</value>
```

## Configurando o PHP LDAP Admin

PHP LDAP Admin é uma ferramenta para gerenciar OPENLDAP via GUI, é uma alternativa ao uso de CLI. O usuário pode adicionar/modificar/excluir usuários, grupos, funções, etc. via GUI. Observe que isso não é necessário para que o LDAP funcione.

Primeiro, installe as dependências do PHPLDAPAdmin.

Em `/etc/httpd/conf.d`, atualize o arquivo `phpldapadmin.conf` com

```properties
# Require local
Require all granted
```

E também atualize o arquivo `config.php` na pasta `/etc/phpldapadmin` com

```php
servers->setValue('server','name','Local LDAP Server');
servers->setValue('server','host','127.0.0.1');
servers->setValue('server','port',389);
servers->setValue('server','base',array('dc=oldap,dc=pd,dc=griaule'));
servers->setValue('login','attr','dn');
```

Execute o seguinte comando para iniciar e habilitar os serviços HTTPD

```sh
$ systemctl enable httpd.service && systemctl start httpd.service && systemctl status httpd.service
```

Após habilitar o HTTPD, é necessário especificar as possíveis atualizações. Se o firewall estiver ativado, execute

```sh
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --reload
```

E se o SELinux estiver habilitado, execute

```sh
setsebool -P httpd_can_connect_ldap on
```

Valide o PHP LDAP Admin GUI abrindo a GUI em <http://localhost/ldapadmin> com o usuário (DN, por exemplo, cn=ldapadm,dc=oldap,dc=pd,dc=griaule) e senha. Em seguida, clique nos botões suspensos e confirme se todos os usuários e grupos estão disponíveis.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.griaule.com/instalacao-do-gbds/security.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
