PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Un unico sistema di sicurezza per applicazioni, pool di connessioni e PostgreSQL:il caso per LDAP

Tradizionalmente, l'applicazione tipica è costituita dai seguenti componenti:

In questo semplice caso, sarebbe sufficiente una configurazione di base:

  • l'applicazione utilizza un semplice meccanismo di autenticazione locale per i suoi utenti
  • l'applicazione utilizza un semplice pool di connessioni
  • c'è un singolo utente definito per l'accesso al database

Tuttavia, man mano che l'organizzazione si evolve e diventa più grande, vengono aggiunti più componenti:

  • più app tenant o istanze dell'app che accedono al database
  • più servizi e sistemi che accedono al database
  • Autenticazione/autorizzazione centralizzata (AA) per tutti (o la maggior parte) dei servizi
  • separazione dei componenti per un ridimensionamento futuro più semplice

Nello schema di cui sopra, tutte le preoccupazioni sono separate in singole componenti, ciascuna componente ha uno scopo specifico. Tuttavia, il pool di connessioni utilizza ancora un singolo utente di database dedicato come nella precedente configurazione più semplice che abbiamo visto sopra.

Oltre ai nuovi componenti, arrivano anche nuovi requisiti:

  • migliore controllo granulare di ciò che gli utenti possono fare a livello di database
  • revisione
  • Registrazione del sistema migliore e più utile

Possiamo sempre implementarli tutti e tre con più codice dell'applicazione o più livelli nell'applicazione, ma questo è solo ingombrante e difficile da mantenere.

Inoltre, PostgreSQL offre un insieme così ricco di soluzioni nelle aree sopra menzionate (sicurezza, sicurezza a livello di riga, auditing, ecc.) che ha perfettamente senso spostare tutti quei servizi a livello di database. Per prendere quei servizi direttamente dal database, dobbiamo dimenticare il singolo utente nel database e utilizzare invece i singoli utenti reali.

Questo ci porta a uno schema come il seguente:

Nel nostro caso d'uso descriveremo una tipica configurazione aziendale costituita dallo schema sopra in cui utilizziamo:

  • Server dell'app Wildfly (esempi mostrati per la versione 10)
  • Servizio di autenticazione/autorizzazione LDAP
  • pooler di connessione pgbouncer
  • PostgreSQL 10

Sembra una configurazione tipica, dal momento che jboss/wildfly supporta l'autenticazione e l'autorizzazione LDAP da molti anni, PostgreSQL supporta LDAP da molti anni.

Tuttavia pgbouncer ha avviato il supporto per LDAP (e questo tramite PAM) solo dalla versione 1.8 alla fine del 2017, il che significa che qualcuno fino ad allora non poteva utilizzare il pooler di connessioni PostgreSQL più caldo in una tale configurazione aziendale (che non sembrava promettente da nessuna angolazione scegliamo a guardarlo)!

In questo blog descriveremo la configurazione necessaria in ogni livello.

Configurazione di Wildfly 10

La configurazione dell'origine dati dovrà essere simile a questa, sto mostrando le cose più importanti:

<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>

Ho messo in grassetto i parametri ei valori importanti. Ricordati di definire l'indirizzo IP (o hostname), il nome del database e la porta in base alla configurazione del tuo server pgbouncer.

Inoltre, al posto del tipico nome utente/password, dovrai avere un dominio di sicurezza definito, che deve essere specificato nella sezione dell'origine dati come mostrato sopra. La sua definizione sarà simile a:

<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>

In questo modo wildfly delegherà il contesto di sicurezza a pgbouncer.

NOTA: in questo blog trattiamo le nozioni di base, ovvero non facciamo uso o menzione di TLS, tuttavia ti consigliamo vivamente di utilizzarlo nella tua installazione.

Gli utenti wildfly devono autenticarsi sul tuo server LDAP come segue:

<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>

I file di configurazione sopra riportati si applicano a wildfly 10.0, ti consigliamo comunque di consultare la documentazione ufficiale del tuo ambiente.

Configurazione PostgreSQL

Per dire a PostgreSQL di autenticarsi (NOTA: non autorizzare!) sul tuo server LDAP devi apportare le modifiche appropriate a postgresql.conf e pg_hba.conf. Le voci di interesse sono le seguenti:

In postgresql.conf:

listen_addresses = '*'

e in 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"

Assicurati che le impostazioni LDAP definite qui corrispondano esattamente a quelle che hai definito nella configurazione del tuo server dell'app. Esistono due modalità operative per le quali PostgreSQL può essere istruito per contattare il server LDAP:

  • legatura semplice
  • cerca e quindi collega

La modalità di collegamento semplice richiede solo una connessione al server LDAP, quindi è più veloce ma richiede un'organizzazione del dizionario LDAP in qualche modo più rigorosa rispetto alla seconda modalità. La modalità di ricerca e collegamento consente una maggiore flessibilità. Tuttavia, per la directory LDAP media, la prima modalità (associazione semplice) funzionerà perfettamente. Dobbiamo sottolineare alcuni punti sull'autenticazione LDAP di PostgreSQL:

  • Questo ha a che fare con solo autenticazione (controllo delle password).
  • L'appartenenza ai ruoli viene ancora eseguita in PostgreSQL, come al solito.
  • Gli utenti devono essere creati in PostgreSQL (tramite CREATE utente/ruolo) come al solito.

Esistono alcune soluzioni per aiutare con la sincronizzazione tra utenti LDAP e PostgreSQL (ad es. ldap2pg) oppure puoi semplicemente scrivere il tuo wrapper che gestirà sia LDAP che PostgreSQL per aggiungere o eliminare utenti.

Scarica il whitepaper oggi Gestione e automazione di PostgreSQL con ClusterControlScopri cosa devi sapere per distribuire, monitorare, gestire e ridimensionare PostgreSQLScarica il whitepaper

Configurazione PgBouncer

Questa è la parte più difficile della nostra configurazione, a causa del fatto che il supporto LDAP nativo manca ancora da pgbouncer e l'unica opzione è l'autenticazione tramite PAM, il che significa che ciò dipende dalla corretta configurazione locale di UNIX/Linux PAM per LDAP.

Quindi la procedura è suddivisa in due passaggi.

Il primo passaggio consiste nel configurare e verificare che pgbouncer funzioni con PAM e il secondo passaggio consiste nel configurare PAM per funzionare con LDAP.

pgbouncer

pgbouncer deve essere compilato con il supporto PAM. Per farlo dovrai:

  • installa libpam0g-dev
  • ./configure --with-pam
  • ricompilare e installare pgbouncer

Il tuo pgbouncer.ini (o il nome del tuo file di configurazione pgbouncer) deve essere configurato per pam. Inoltre, deve contenere i parametri corretti per il database e l'applicazione in conformità con i parametri descritti nelle sezioni precedenti. Cose che dovrai definire o modificare:

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

Ovviamente, dovrai leggere i documenti di pgbouncer e ottimizzare il tuo pgbouncer in base alle tue esigenze. Per testare la configurazione di cui sopra tutto ciò che devi fare è creare un nuovo utente UNIX locale e provare ad autenticarti su pgbouncer:

# adduser testuser
<answer to all question, including password>

Affinché pgbouncer funzioni con PAM durante la lettura dai file passwd locali, l'eseguibile pgbouncer deve essere di proprietà di root e con 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:La necessità della proprietà di root e di setuid (che è vero per ogni sistema debian/ubuntu che ho testato) non è documentata da nessuna parte, né sui documenti ufficiali di pgbouncer né da nessuna parte in rete.

Quindi accediamo (come superutente pgsql) all'host postgresql (o psql -h your.pgsql.server) e creiamo il nuovo utente:

CREATE USER testuser PASSWORD 'same as the UNIX passwd you gave above';

quindi dall'host pgbouncer:

psql -h localhost -p 6432 yourdbname -U testuser

Dovresti essere in grado di ricevere un prompt e vedere le tabelle come se fossi connesso direttamente al server del database. Ricordati di eliminare questo utente dal sistema e di eliminarlo anche dal database quando hai finito con tutti i tuoi test.

PAM

Affinché PAM possa interfacciarsi con il server LDAP, è necessario un pacchetto aggiuntivo:libpam-ldap . Il suo script di post installazione eseguirà una finestra di dialogo in modalità testo a cui dovrai rispondere con i parametri corretti per il tuo server LDAP. Questo pacchetto effettuerà gli aggiornamenti necessari nei file /etc/pam.d e creerà anche un file chiamato:/etc/pam_ldap.conf. Nel caso qualcosa cambi in futuro puoi sempre tornare indietro e modificare questo file. Le righe più importanti in questo file sono:

base cn=users,cn=accounts,dc=yourorgname,dc=com
uri ldap://your.ldap.server/
ldap_version 3
pam_password crypt

Il nome/indirizzo del tuo server LDAP e la base di ricerca devono essere esattamente gli stessi di quelli specificati nei file PostgreSQL pg_hba.conf e Wildfly standalone.xml conf spiegati sopra. pam_login_attribute di default è uid. Si consiglia di dare un'occhiata ai file /etc/pam.d/common-* e vedere cosa è cambiato dopo l'installazione di libpam-ldap. Seguendo i documenti, puoi creare un nuovo file chiamato /etc/pam.d/pgbouncer e definire lì tutte le opzioni PAM, ma i file common-* predefiniti saranno sufficienti. Diamo un'occhiata in /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

Verrà prima verificato Unix passwd e, se fallisce, verrà controllato LDAP, quindi tieni presente che dovrai cancellare tutte le password locali per quegli utenti che sono definiti sia nel locale linux/unix /etc/passwd che in LDAP . Ora è il momento di fare il test finale. Scegli un utente che è definito nel tuo server LDAP e creato anche in PostgreSQL, e prova ad autenticarti dal DB (tramite pgsql -h your.pgsql.server ), quindi da pgbouncer (anche tramite psql -h your.pgbouncer.server) e infine tramite la tua app. Hai appena reso realtà un unico sistema di sicurezza per app, pool di connessioni e PostgreSQL!