PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jeden system bezpieczeństwa dla aplikacji, puli połączeń i PostgreSQL — przypadek LDAP

Tradycyjnie typowa aplikacja składa się z następujących elementów:

W tym prostym przypadku wystarczyłaby podstawowa konfiguracja:

  • aplikacja używa prostego lokalnego mechanizmu uwierzytelniania dla swoich użytkowników
  • aplikacja korzysta z prostej puli połączeń
  • istnieje jeden użytkownik zdefiniowany jako dostęp do bazy danych

Jednak wraz z rozwojem organizacji i rozrostem dodawanych jest więcej komponentów:

  • więcej aplikacji dzierżawy lub instancji aplikacji uzyskujących dostęp do bazy danych
  • więcej usług i systemów uzyskujących dostęp do bazy danych
  • centralne uwierzytelnianie/autoryzacja (AA) dla wszystkich (lub większości) usług
  • oddzielenie komponentów dla łatwiejszego przyszłego skalowania

W powyższym schemacie wszystkie koncerny są rozdzielone na poszczególne komponenty, każdy komponent służy do określonego celu. Jednak nadal pula połączeń korzysta z jednego dedykowanego użytkownika bazy danych, jak w poprzedniej prostszej konfiguracji, którą widzieliśmy powyżej.

Oprócz nowych komponentów pojawiają się również nowe wymagania:

  • lepsza, szczegółowa kontrola nad tym, co użytkownicy mogą robić na poziomie bazy danych
  • audyt
  • lepsze, bardziej przydatne logowanie systemowe

Zawsze możemy zaimplementować wszystkie trzy z większą ilością kodu aplikacji lub większą liczbą warstw w aplikacji, ale jest to po prostu kłopotliwe i trudne w utrzymaniu.

Ponadto PostgreSQL oferuje tak bogaty zestaw rozwiązań w wyżej wymienionych obszarach (bezpieczeństwo, Row Level Security, audyt itp.), że przeniesienie wszystkich tych usług do warstwy bazy danych ma sens. Aby pobrać te usługi bezpośrednio z bazy danych, musimy zapomnieć o pojedynczym użytkowniku w bazie danych i zamiast tego użyć prawdziwych indywidualnych użytkowników.

To prowadzi nas do schematu takiego jak poniżej:

W naszym przypadku użycia opiszemy typową konfigurację przedsiębiorstwa składającą się z powyższego schematu, w którym używamy:

  • Serwer aplikacji Wildfly (przykłady pokazane dla wersji 10)
  • Usługa uwierzytelniania/autoryzacji LDAP
  • pulerze połączeń pgbouncera
  • PostgreSQL 10

Wygląda to na typową konfigurację, ponieważ jboss/wildfly od wielu lat obsługuje uwierzytelnianie i autoryzację LDAP, PostgreSQL wspiera LDAP od wielu lat.

Jednak pgbouncer rozpoczął obsługę LDAP (i to przez PAM) dopiero od wersji 1.8 pod koniec 2017 roku, co oznacza, że ​​ktoś do tego czasu nie mógł używać najgorętszego poolera połączeń PostgreSQL w takiej konfiguracji korporacyjnej (co nie brzmiało obiecująco pod żadnym wybranym przez nas kątem spojrzeć na to)!

W tym blogu opiszemy konfigurację potrzebną w każdej warstwie.

Konfiguracja Wildfly 10

Konfiguracja źródła danych będzie musiała wyglądać tak, pokazuję najważniejsze rzeczy:

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

Pogrubiłem ważne parametry i wartości. Pamiętaj, aby zdefiniować adres IP (lub nazwę hosta), nazwę bazy danych i port zgodnie z konfiguracją serwera pgbouncer.

Ponadto zamiast typowej nazwy użytkownika/hasła będziesz musiał zdefiniować domenę bezpieczeństwa, którą należy określić w sekcji źródła danych, jak pokazano powyżej. Jego definicja będzie wyglądać następująco:

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

W ten sposób wildfly przekaże kontekst bezpieczeństwa do pgbouncer.

UWAGA: na tym blogu omawiamy podstawy, tj. nie używamy ani nie wspominamy o TLS, jednak zdecydowanie zachęcamy do korzystania z niego w swojej instalacji.

Użytkownicy wildfly muszą uwierzytelnić się na serwerze LDAP w następujący sposób:

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

Powyższe pliki konfiguracyjne dotyczą wildfly 10.0, w każdym przypadku radzimy zapoznać się z oficjalną dokumentacją swojego środowiska.

Konfiguracja PostgreSQL

Aby poinformować PostgreSQL o uwierzytelnieniu (UWAGA: nie autoryzuj!) na serwerze LDAP, musisz wprowadzić odpowiednie zmiany w postgresql.conf i pg_hba.conf. Interesujące wpisy są następujące:

W postgresql.conf:

listen_addresses = '*'

oraz w 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"

Upewnij się, że zdefiniowane tutaj ustawienia LDAP odpowiadają dokładnie tym, które zdefiniowałeś w konfiguracji serwera aplikacji. Istnieją dwa tryby działania, w których PostgreSQL może kontaktować się z serwerem LDAP:

  • proste wiązanie
  • wyszukaj, a następnie powiąż

Tryb prostego wiązania wymaga tylko jednego połączenia z serwerem LDAP, dlatego jest szybszy, ale wymaga nieco bardziej rygorystycznej organizacji słownika LDAP niż tryb drugi. Tryb wyszukiwania i wiązania zapewnia większą elastyczność. Jednak w przypadku przeciętnego katalogu LDAP pierwszy tryb (proste wiązanie) będzie działał dobrze. Musimy podkreślić pewne punkty dotyczące uwierzytelniania PostgreSQL LDAP:

  • Ma to związek z tylko uwierzytelnianiem (sprawdzanie haseł).
  • Członkostwo na role jest nadal wykonywane w PostgreSQL, jak zwykle.
  • Użytkownicy muszą być utworzeni w PostgreSQL (poprzez CREATE użytkownika/role) jak zwykle.

Istnieje kilka rozwiązań pomagających w synchronizacji między użytkownikami LDAP i PostgreSQL (np. ldap2pg) lub możesz po prostu napisać własne opakowanie, które będzie obsługiwać zarówno LDAP, jak i PostgreSQL w celu dodawania lub usuwania użytkowników.

Pobierz oficjalny dokument już dziś Zarządzanie i automatyzacja PostgreSQL za pomocą ClusterControlDowiedz się, co musisz wiedzieć, aby wdrażać, monitorować, zarządzać i skalować PostgreSQLPobierz oficjalny dokument

Konfiguracja PgBouncera

Jest to najtrudniejsza część naszej konfiguracji, ponieważ pgbouncer nadal nie obsługuje natywnego LDAP, a jedyną opcją jest uwierzytelnianie przez PAM, co oznacza, że ​​zależy to od poprawnej lokalnej konfiguracji PAM UNIX/Linux dla LDAP.

Tak więc procedura jest podzielona na dwa kroki.

Pierwszym krokiem jest skonfigurowanie i przetestowanie, czy pgbouncer współpracuje z PAM, a drugim krokiem jest skonfigurowanie PAM do współpracy z LDAP.

pgbouncer

pgbouncer musi być skompilowany z obsługą PAM. W tym celu musisz:

  • zainstaluj libpam0g-dev
  • ./configure --with-pam
  • przekompiluj i zainstaluj pgbouncera

Twój pgbouncer.ini (lub nazwa pliku konfiguracyjnego pgbouncer) musi być skonfigurowany dla pam. Musi również zawierać poprawne parametry dla Twojej bazy danych i aplikacji zgodnie z parametrami opisanymi w powyższych sekcjach. Rzeczy, które będziesz musiał zdefiniować lub zmienić:

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

Oczywiście będziesz musiał przeczytać dokumentację pgbouncera i dostroić swojego pgbouncera do swoich potrzeb. Aby przetestować powyższą konfigurację, wszystko, co musisz zrobić, to utworzyć nowego lokalnego użytkownika UNIX i spróbować uwierzytelnić się w pgbouncer:

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

Aby pgbouncer działał z PAM podczas odczytu z lokalnych plików passwd, plik wykonywalny pgbouncer musi być własnością roota i mieć 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

Uwaga:Konieczność posiadania roota i setuid (co jest prawdziwe dla każdego testowanego przeze mnie systemu debian/ubuntu) nie jest nigdzie udokumentowana, ani w oficjalnej dokumentacji pgbouncera, ani nigdzie w sieci.

Następnie logujemy się (jako superużytkownik pgsql) do hosta postgresql (lub psql -h twój.pgsql.server) i tworzymy nowego użytkownika:

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

następnie z hosta pgbouncer:

psql -h localhost -p 6432 yourdbname -U testuser

Powinieneś otrzymać monit i zobaczyć tabele tak, jakbyś był połączony bezpośrednio z serwerem bazy danych. Pamiętaj, aby usunąć tego użytkownika z systemu, a także usunąć go z bazy danych po zakończeniu wszystkich testów.

PAM

Aby PAM mógł współpracować z serwerem LDAP, potrzebny jest dodatkowy pakiet:libpam-ldap . Jego skrypt poinstalacyjny uruchomi okno dialogowe trybu tekstowego, na które należy odpowiedzieć, podając prawidłowe parametry dla serwera LDAP. Ten pakiet dokona niezbędnych aktualizacji w plikach /etc/pam.d, a także utworzy plik o nazwie:/etc/pam_ldap.conf. Jeśli coś zmieni się w przyszłości, zawsze możesz wrócić i edytować ten plik. Najważniejsze wiersze w tym pliku to:

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

Nazwa/adres serwera LDAP i bazy wyszukiwania muszą być dokładnie takie same, jak te określone w plikach PostgreSQL pg_hba.conf i Wildfly standalone.xml conf, które wyjaśniono powyżej. pam_login_attribute domyślnie to uid. Zachęcamy do przejrzenia plików /etc/pam.d/common-* i zobaczenia, co zmieniło się po instalacji libpam-ldap. Postępując zgodnie z dokumentacją, możesz utworzyć nowy plik o nazwie /etc/pam.d/pgbouncer i zdefiniować tam wszystkie opcje PAM, ale wystarczą domyślne pliki common-*. Zajrzyjmy do /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

Unix passwd zostanie sprawdzone jako pierwsze, a jeśli to się nie powiedzie, zostanie sprawdzony LDAP, więc pamiętaj, że będziesz musiał usunąć wszelkie lokalne hasła dla tych użytkowników, którzy są zdefiniowani zarówno w lokalnym linux/unix /etc/passwd, jak i w LDAP . Teraz nadszedł czas na ostatni test. Wybierz użytkownika, który jest zdefiniowany na twoim serwerze LDAP, a także utworzony w PostgreSQL i spróbuj uwierzytelnić się z bazy danych (poprzez pgsql -h twój.pgsql.server ), a następnie z pgbouncer (również przez psql -h twój.pgbouncer.server) , a na koniec za pośrednictwem Twojej aplikacji. Właśnie urzeczywistniłeś jeden system bezpieczeństwa dla aplikacji, puli połączeń i PostgreSQL!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. django.db.utils.ProgrammingError:relacja app_user nie istnieje podczas testu manage.py

  2. Komentować znak/znaki w postgres / postgresql / psql?

  3. Powrót XFS na Linuksie

  4. Oblicz wiek w latach w PostgreSQL

  5. Znajdź nazwę hosta i port za pomocą poleceń PSQL