PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Um sistema de segurança para aplicativos, pool de conexões e PostgreSQL - O caso do LDAP


Tradicionalmente, o aplicativo típico consiste nos seguintes componentes:

Neste caso simples, uma configuração básica seria suficiente:
  • o aplicativo usa um mecanismo de autenticação local simples para seus usuários
  • o aplicativo usa um pool de conexões simples
  • há um único usuário definido para acesso ao banco de dados

No entanto, à medida que a organização evolui e aumenta, mais componentes são adicionados:
  • mais aplicativos de locatário ou instâncias do aplicativo acessando o banco de dados
  • mais serviços e sistemas acessando o banco de dados
  • autenticação/autorização centralizada (AA) para todos (ou a maioria) dos serviços
  • separação de componentes para escalonamento futuro mais fácil

No esquema acima, todas as preocupações são separadas em componentes individuais, cada componente serve a um propósito especializado. No entanto, o pool de conexões ainda usa um único usuário de banco de dados dedicado, como na configuração anterior mais simples que vimos acima.

Além dos novos componentes, também chegam novos requisitos:
  • melhor controle refinado do que os usuários podem fazer no nível do banco de dados
  • auditoria
  • melhor registro de sistema mais útil

Sempre podemos implementar todos os três com mais código de aplicativo ou mais camadas no aplicativo, mas isso é apenas complicado e difícil de manter.

Além disso, o PostgreSQL oferece um conjunto tão rico de soluções nas áreas mencionadas (segurança, segurança em nível de linha, auditoria, etc.) que faz todo o sentido mover todos esses serviços para a camada de banco de dados. Para obter esses serviços diretamente do banco de dados, devemos esquecer o usuário único no banco de dados e usar usuários individuais reais.

Isso nos leva a um esquema como o abaixo:

Em nosso caso de uso, descreveremos uma configuração corporativa típica que consiste no esquema acima, onde usamos:
  • Servidor de aplicativos Wildfly (exemplos mostrados para a versão 10)
  • Serviço de autenticação/autorização LDAP
  • pooler de conexões pgbouncer
  • PostgreSQL 10

Parece uma configuração típica, já que o jboss/wildfly tem suportado autenticação e autorização LDAP por muitos anos, o PostgreSQL tem suportado LDAP por muitos anos.

No entanto, o pgbouncer só iniciou o suporte para LDAP (e isso via PAM) desde a versão 1.8 no final de 2017, o que significa que alguém até então não podia usar o pool de conexões PostgreSQL mais quente em uma configuração corporativa (o que não parecia promissor por nenhum ângulo que escolhemos para olhá-lo)!

Neste blog, descreveremos a configuração necessária em cada camada.

Configuração do Wildfly 10


A configuração da fonte de dados terá que ficar assim, estou mostrando as coisas mais importantes:
<xa-datasource jndi-name="java:/pgsql" pool-name="pgsqlDS" enabled="true" mcp="org.jboss.jca.core.connectionmanager.pool.mcp.LeakDumperManagedConnectionPool">
	<xa-datasource-property name="DatabaseName">
		yourdbname
	</xa-datasource-property>
	<xa-datasource-property name="PortNumber">
		6432
	</xa-datasource-property>
	<xa-datasource-property name="ServerName">
		your.pgbouncer.server
	</xa-datasource-property>
	<xa-datasource-property name="PrepareThreshold">
		0
	</xa-datasource-property>
	<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
	<driver>postgresql-9.4.1212.jar</driver>
	<new-connection-sql>
		SET application_name to 'myapp';
	</new-connection-sql>
	<xa-pool>
		<max-pool-size>400</max-pool-size>
		<allow-multiple-users>true</allow-multiple-users>
	</xa-pool>
	<security>
		<security-domain>postgresqluser</security-domain>
	</security>
</xa-datasource>

Coloquei em negrito os parâmetros e valores importantes. Lembre-se de definir o endereço IP (ou hostname), o nome do banco de dados e a porta de acordo com a configuração do seu servidor pgbouncer.

Além disso, em vez do nome de usuário/senha típicos, você precisará ter um domínio de segurança definido, que deve ser especificado na seção de fonte de dados, conforme mostrado acima. Sua definição ficará assim:
<security-domain name="postgresqluser">
	<authentication>
		<login-module code="org.picketbox.datasource.security.CallerIdentityLoginModule" flag="required">
			<module-option name="managedConnectionFactoryName" value="name=pgsql,jboss.jca:service=XATxCM"/>
		</login-module>
	</authentication>
</security-domain>

Dessa forma, o wildfly delegará o contexto de segurança ao pgbouncer.

OBSERVAÇÃO: neste blog, abordamos o básico, ou seja, não fazemos uso ou menção ao TLS, mas você é fortemente encorajado a usá-lo em sua instalação.

Os usuários do wildfly devem se autenticar em seu servidor LDAP da seguinte forma:
<login-module code="<your login module class>" flag="sufficient">
	<module-option name="java.naming.provider.url" value="ldap://your.ldap.server/"/>
	<module-option name="java.naming.security.authentication" value="simple"/>
	<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
	<module-option name="principalDNPrefix" value="uid="/>
	<module-option name="uidAttributeID" value="memberOf"/>
	<module-option name="roleNameAttributeID" value="cn"/>
	<module-option name="roleAttributeID" value="memberOf"/>
	<module-option name="principalDNSuffix"
	value=",cn=users,cn=accounts,dc=yourorgname,dc=com"/>
	<module-option name="userSrchBase" value="dc=yourorgname,dc=com"/>
	<module-option name="rolesCtxDN"
	value="cn=groups,cn=accounts,dc=yourorgname,dc=com"/>
	<module-option name="matchOnUserDN" value="true"/>
	<module-option name="unauthendicatedIdentity" value="foousr"/>
	<module-option name="com.sun.jndi.ldap.connect.timeout" value="5000"/>
</login-module>

Os arquivos de configuração acima se aplicam ao wildfly 10.0, em qualquer caso, você deve consultar a documentação oficial do seu ambiente.

Configuração do PostgreSQL


Para dizer ao PostgreSQL para autenticar (NOTA: não autorize!) em seu servidor LDAP, você deve fazer as alterações apropriadas em postgresql.conf e pg_hba.conf. As entradas de interesse são as seguintes:

Em postgresql.conf:
listen_addresses = '*'

e em pg_hba.conf:
#TYPE  DATABASE    USER        CIDR-ADDRESS                  METHOD
host    all         all         ip.ofYourPgbouncer.server/32 ldap ldapserver=your.ldap.server ldapprefix="uid=" ldapsuffix=",cn=users,cn=accounts,dc=yourorgname,dc=com"

Certifique-se de que as configurações de LDAP definidas aqui correspondam exatamente às que você definiu na configuração do servidor de aplicativos. Existem dois modos de operação que o PostgreSQL pode ser instruído a contatar o servidor LDAP:
  • ligação simples
  • pesquisar e vincular

O modo de ligação simples requer apenas uma conexão com o servidor LDAP, portanto, é mais rápido, mas requer uma organização de dicionário LDAP de alguma forma mais rigorosa do que o segundo modo. O modo de pesquisa e ligação permite maior flexibilidade. No entanto, para o diretório LDAP médio, o primeiro modo (ligação simples) funcionará bem. Devemos sublinhar alguns pontos sobre a autenticação LDAP do PostgreSQL:
  • Isso tem a ver com autenticação somente (verificando senhas).
  • A associação de funções ainda é feita no PostgreSQL, como de costume.
  • Os usuários devem ser criados no PostgreSQL (via CREATE usuário/função) como de costume.

Existem algumas soluções para ajudar na sincronização entre usuários do LDAP e do PostgreSQL (por exemplo, ldap2pg) ou você pode simplesmente escrever seu próprio wrapper que lidará com o LDAP e o PostgreSQL para adicionar ou excluir usuários.
Baixe o whitepaper hoje PostgreSQL Management &Automation with ClusterControlSaiba o que você precisa saber para implantar, monitorar, gerenciar e dimensionar o PostgreSQLBaixe o whitepaper

Configuração do PgBouncer


Esta é a parte mais difícil de nossa configuração, devido ao fato de que o suporte LDAP nativo ainda está faltando no pgbouncer, e a única opção é autenticar via PAM, o que significa que isso depende da configuração correta do UNIX/Linux PAM local para LDAP.

Assim, o procedimento é dividido em duas etapas.

A primeira etapa é configurar e testar se o pgbouncer funciona com o PAM e a segunda etapa é configurar o PAM para funcionar com o LDAP.

pgbouncer


pgbouncer deve ser compilado com suporte a PAM. Para o fazer terá de:
  • instale libpam0g-dev
  • ./configure --with-pam
  • recompile e instale o pgbouncer

Seu pgbouncer.ini (ou o nome do seu arquivo de configuração pgbouncer) deve ser configurado para pam. Além disso, deve conter os parâmetros corretos para seu banco de dados e seu aplicativo de acordo com os parâmetros descritos nas seções acima. Coisas que você terá que definir ou mudar:
yourdbname = host=your.pgsql.server dbname=yourdbname pool_size=5
listen_addr = *
auth_type = pam
# set pool_mode for max performance
pool_mode = transaction
# required for JDBC
ignore_startup_parameters = extra_float_digits

Claro, você terá que ler a documentação do pgbouncer e ajustar seu pgbouncer de acordo com suas necessidades. Para testar a configuração acima, tudo o que você precisa fazer é criar um novo usuário UNIX local e tentar autenticar no pgbouncer:
# adduser testuser
<answer to all question, including password>

Para que o pgbouncer funcione com o PAM ao ler os arquivos passwd locais, o executável do pgbouncer deve ser de propriedade do root e com setuid:
# chown root:staff ~pgbouncer/pgbouncer-1.9.0/pgbouncer     
# chmod +s ~pgbouncer/pgbouncer-1.9.0/pgbouncer
# ls -l ~pgbouncer/pgbouncer-1.9.0/pgbouncer           
-rwsrwsr-x 1 root staff 1672184 Dec 21 16:28 /home/pgbouncer/pgbouncer-1.9.0/pgbouncer

Nota:A necessidade de propriedade de root e setuid (o que é verdade para todos os sistemas debian/ubuntu que testei) não está documentada em nenhum lugar, nem nos documentos oficiais do pgbouncer nem em qualquer lugar na rede.

Em seguida, efetuamos login (como superusuário pgsql) no host postgresql (ou psql -h your.pgsql.server) e criamos o novo usuário:
CREATE USER testuser PASSWORD 'same as the UNIX passwd you gave above';

então do host pgbouncer:
psql -h localhost -p 6432 yourdbname -U testuser

Você deve ser capaz de obter um prompt e ver as tabelas como se estivesse conectado diretamente ao seu servidor de banco de dados. Lembre-se de excluir este usuário do sistema e também do banco de dados quando terminar todos os seus testes.

PAM


Para que o PAM faça interface com o servidor LDAP, é necessário um pacote adicional:libpam-ldap . Seu script de pós-instalação executará uma caixa de diálogo em modo de texto que você terá que responder com os parâmetros corretos para seu servidor LDAP. Este pacote fará as atualizações necessárias nos arquivos /etc/pam.d e também criará um arquivo chamado:/etc/pam_ldap.conf. Caso algo mude no futuro, você sempre pode voltar e editar este arquivo. As linhas mais importantes neste arquivo são:
base cn=users,cn=accounts,dc=yourorgname,dc=com
uri ldap://your.ldap.server/
ldap_version 3
pam_password crypt

O nome/endereço do seu servidor LDAP e a base de pesquisa devem ser exatamente os mesmos especificados nos arquivos conf do PostgreSQL pg_hba.conf e do Wildfly standalone.xml explicados acima. pam_login_attribute é padronizado como uid. Você é encorajado a dar uma olhada nos arquivos /etc/pam.d/common-* e ver o que mudou após a instalação do libpam-ldap. Seguindo a documentação, você pode criar um novo arquivo chamado /etc/pam.d/pgbouncer e definir todas as opções do PAM lá, mas os arquivos common-* padrão serão suficientes. Vamos dar uma olhada em /etc/pam.d/common-auth:
auth    [success=2 default=ignore]      pam_unix.so nullok_secure
auth    [success=1 default=ignore]      pam_ldap.so use_first_pass
auth    requisite                       pam_deny.so
auth    required                        pam_permit.so

O Unix passwd será verificado primeiro e, se isso falhar, o LDAP será verificado, portanto, lembre-se de que você terá que apagar todas as senhas locais para os usuários definidos no linux/unix /etc/passwd local e no LDAP . Agora é hora de fazer o teste final. Escolha um usuário que esteja definido em seu servidor LDAP e também criado no PostgreSQL, e tente autenticar a partir do banco de dados (via pgsql -h your.pgsql.server ), depois do pgbouncer (também via psql -h your.pgbouncer.server) e, finalmente, por meio do seu aplicativo. Você acabou de tornar realidade um único sistema de segurança para aplicativo, pool de conexões e PostgreSQL!