Implementazione delle best practice dei ruoli di Postgres


21

gente,

Potrei usare il vostro aiuto per migliorare la progettazione del controllo degli accessi degli utenti Postgres e allinearla alle migliori pratiche. Sto aiutando a implementare un piccolo server Postgres di produzione ma non sono un amministratore DB, quindi so quanto basta per essere pericoloso.

Esiste un server con una installazione di Postgres v9.2. Questa installazione ospita più database, ognuno dei quali serve completamente un "cliente" diverso. In altre parole, customer1 non dovrà, non utilizzare database2 e così via. Durante le normali operazioni, i database sono accessibili ciascuno da un'istanza corrispondente di CakePHP, tutti situati nello stesso server di Postgres. Sebbene possano esserci possibili ottimizzazioni su questa distribuzione, sono principalmente interessato ai ruoli di Psql.

Sulla base di quello che ho letto, sembra che tre tipi di ruoli avrebbero senso:

  • Postgres superutente con password non predefinita
  • Un ruolo di amministratore che non dispone dei privilegi di superutente per la manutenzione ordinaria, la creazione di DB, il backup e il ripristino. Dovrebbe essere in grado di fare qualsiasi cosa con tutti i database dei clienti.
  • Ruoli utente con la sola capacità di CRUD nel rispettivo database. Ulteriori diritti sul proprio DB potrebbero essere tollerati se si ripulisce l'implementazione.

L'implementazione di quel design è dove sono molto meno fiducioso. Proprietà di DB rispetto a tabella e anche di chi dovrebbe ereditare da chi è un po 'confuso. Di seguito sono riportati i miei database e i miei utenti. Sono sufficienti informazioni per valutare l'implementazione?

     Role name |                   Attributes                   |     Member of     
    -----------+------------------------------------------------+-------------------
     admin     | Create role, Create DB                         | {user1, user2}
     postgres  | Superuser, Create role, Create DB              | {}
     user1     |                                                | {}
     user2     |                                                | {}

    postgres=# \l
                                 List of databases
       Name    |  Owner   | Encoding | Collate | Ctype |   Access privileges   
    -----------+----------+----------+---------+-------+-----------------------
     admin     | postgres | UTF8     | en_US   | en_US | =Tc/postgres         +
               |          |          |         |       | postgres=CTc/postgres+
               |          |          |         |       | admin=CTc/postgres
     postgres  | postgres | UTF8     | en_US   | en_US | 
     template0 | postgres | UTF8     | en_US   | en_US | =c/postgres          +
               |          |          |         |       | postgres=CTc/postgres
     template1 | postgres | UTF8     | en_US   | en_US | =c/postgres          +
               |          |          |         |       | postgres=CTc/postgres
     user1     | admin    | UTF8     | en_US   | en_US | =Tc/admin            +
               |          |          |         |       | admin=CTc/admin      +
               |          |          |         |       | user1=CTc/admin
     user2     | admin    | UTF8     | en_US   | en_US | =Tc/admin            +
               |          |          |         |       | admin=CTc/admin      +
               |          |          |         |       | user2=CTc/admin

Per impedire connessioni esterne e password in chiaro, pg_hba.conf è come tale:

local   all             all                                     md5
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5

1
Nella mia esperienza, la migliore separazione che porta anche una grande quantità di altri vantaggi è quella di eseguire cluster PostGreSQL separati (ad es. Servizi) per ciascun cliente. Questo è ciò che attualmente facciamo per un grande ambiente di produzione in questo momento e non lo farei diversamente se il numero di DB non diventasse davvero grande e ognuno di essi fosse davvero piccolo. Naturalmente, l'applicazione deve anche sapere come connettersi a una diversa origine dati per ciascun tenant (cliente).
Florin Asăvoaie,

Accanto a FlorinAsăvoaie la sua osservazione. Ogni database non dovrebbe avere il proprio utente proprietario e l'utente query? Ciò semplificherebbe l'inserimento di determinati utenti in un deposito password per scopi di manutenzione.
hspaans,

Risposte:


5

So che questa è una vecchia domanda, ma cercherò di rispondere anche adesso, mentre devo fare qualche ricerca in merito.

Quello che stai cercando di fare è chiamato multi-tenancy a livello di database. Ciò può essere ottenuto in due modi:

  1. In un singolo cluster di database, un po 'come l'OP ha descritto, tuttavia, la mia scelta personale sarebbe questa:

    • L'utente di postgres utilizza l'autenticazione peer e non è consentita la connessione tramite password. L'autenticazione MD5, secondo me, è una cattiva pratica. In caso di problemi con la coerenza del database o questo tipo di cose, sarà comunque possibile effettuare il login se si consente a Postgres di utilizzare l'autenticazione peer.
    • Ogni cliente dovrebbe ottenere il proprio schema e non il database. Ci sono molte ragioni per questo:
      • Possedere l'intero database garantirebbe molti privilegi.
      • Possedere solo tabelle specifiche comporterebbe problemi per gli sviluppatori e richiederebbe sempre agli amministratori di aggiungere permessi e cose.
      • Pertanto, in una configurazione normale, ognuno di loro otterrebbe l'accesso per creare elementi all'interno del proprio schema, inclusi tabelle, viste, trigger, ecc.
      • Tutti usano la stessa stringa di connessione tranne il nome utente. In postgres, per impostazione predefinita, se hai uno schema con il nome del tuo utente, è automaticamente nel tuo percorso di ricerca.
    • Opterei per non avere un utente amministratore in grado di accedere a ogni schema, come misura di sicurezza. È necessario eseguire i backup scaricando ogni schema con il proprio utente o usando la tecnica PITR di PostgreSQL. Avresti ancora bisogno di usare l'utente postgres per creare nuovi schemi, preferirei una regola sudo e uno script per quello.
    • Molte buone pratiche di sicurezza raccomandano di abbandonare lo schema predefinito, quindi eccoci.
    • Questa soluzione è estremamente adatta se il DB per ogni cliente è piccolo e hai tonnellate di clienti.
    • Se l'applicazione gestisce la multi-tenancy, può utilizzare un singolo pool di connessioni per tutti i clienti. Ovviamente, questo elimina molti dei miglioramenti della sicurezza di cui sopra ma potrebbe avere benefici in termini di prestazioni, specialmente quando hai un gran numero di clienti (se hai 500-1000 origini dati separate e usi il pool di connessioni, sarà abbastanza travolgente).
  2. Ogni cliente ottiene il proprio cluster di database. Questa è la mia soluzione preferita soprattutto perché di solito lavoro con applicazioni che dispongono di grandi database per ciascun cliente.

    • Questo porta un'ottima separazione dei dati. È possibile utilizzare volumi di archiviazione separati per ciascun cliente, allocare limiti CPU e memoria (utilizzando la finestra mobile?).
    • Ottima flessibilità su ciò di cui ogni cliente ha bisogno nella sua istanza. Potrebbero essere simili o avere caratteristiche distinte.
    • Molto facile da scalare in entrambe le direzioni (su e fuori).
    • Uso anche IP virtuali separati in cui ciascun cluster è in attesa di connessioni, rendendo il ridimensionamento non necessario la riconfigurazione dell'origine dati.
    • I backup PITR sono per cliente, quindi sarà più semplice ripristinare un singolo cliente rispetto alla multi-tenancy per schema.
    • In configurazioni complesse, ogni cliente potrebbe aver bisogno di più database, schemi, utenti e ruoli, ecc., Quindi in questi casi è una soluzione decisamente migliore.

È inoltre possibile utilizzare una combinazione di quanto sopra e utilizzare pgBouncer come router.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.