Die Implementierung von Best Practices für Postgres-Rollen

21

Leute,

Ich könnte Ihre Hilfe gebrauchen, um das Design meiner Postgres-Benutzerzugriffskontrolle besser und besser auf die Best Practices abzustimmen. Ich helfe bei der Einführung eines kleinen Postgres-Produktionsservers, bin aber kein DB-Administrator und weiß gerade genug, um gefährlich zu sein.

Es gibt einen Server mit einer Installation von Postgres v9.2. Diese Installation hostet mehrere Datenbanken, von denen jede einen anderen "Kunden" vollständig bedient. Mit anderen Worten, Kunde1 wird nicht Datenbank2 verwenden und so weiter. Während des normalen Betriebs wird auf die Datenbanken jeweils von einer passenden Instanz von CakePHP zugegriffen, die sich alle auf demselben Server wie Postgres befinden. Während es bei dieser Bereitstellung Optimierungsmöglichkeiten gibt, interessieren mich hauptsächlich Psql-Rollen.

Basierend auf dem, was ich gelesen habe, scheinen drei Arten von Rollen sinnvoll zu sein:

  • Superuser-Postgres mit nicht voreingestelltem Passwort
  • Eine Administratorrolle ohne Superuser-Berechtigungen für die routinemäßige Wartung, DB-Erstellung, Sicherung und Wiederherstellung. Sollte in der Lage sein, alles mit allen Kundendatenbanken zu tun.
  • Benutzerrollen mit nur der Möglichkeit, CRUD in ihrer jeweiligen Datenbank auszuführen. Weitere Rechte an der eigenen Datenbank könnten toleriert werden, wenn die Implementierung bereinigt wird.

Bei der Umsetzung dieses Entwurfs bin ich viel weniger zuversichtlich. Besitz von DB versus Tisch und auch wer von wem erben soll ist etwas matschig. Unten sind meine Datenbanken und meine Benutzer. Reichen diese Informationen aus, um die Implementierung zu bewerten?

     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

Um externe Verbindungen und Passwörter im Klartext zu verhindern, lautet pg_hba.conf wie folgt:

local   all             all                                     md5
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5
JP Beaudry
quelle
1
Nach meiner Erfahrung ist die beste Trennung, die auch eine Vielzahl anderer Vorteile mit sich bringt, die Ausführung separater PostGreSQL-Cluster (z. B. Dienste) für jeden Kunden. Dies ist, was wir derzeit für eine große Produktionsumgebung tun, und ich würde es nicht anders machen, es sei denn, die Anzahl der DBs würde wirklich groß und jeder von ihnen wäre wirklich klein. Natürlich muss die Anwendung auch wissen, wie für jeden Mandanten (Kunden) eine Verbindung zu einer anderen Datenquelle hergestellt werden kann.
Florin Asăvoaie
Neben @ FlorinAsăvoaie seine Bemerkung. Sollte nicht jede Datenbank einen eigenen Eigentümer und einen eigenen Abfragebenutzer haben? Dies würde es einfacher machen, bestimmte Benutzer zu Wartungszwecken in einen Kennwort-Tresor zu stecken.
hspaans

Antworten:

5

Ich weiß, dass dies eine alte Frage ist, aber ich werde versuchen, sie auch jetzt noch zu beantworten, da ich diesbezüglich Nachforschungen anstellen muss.

Was Sie versuchen, heißt Mandantenfähigkeit auf Datenbankebene. Dies kann auf zwei Arten erreicht werden:

  1. In einem einzelnen Datenbankcluster, so wie es das OP beschrieben hat, wäre meine persönliche Wahl jedoch:

    • Der Benutzer postgres verwendet die Peer-Authentifizierung und darf keine Kennwortverbindungen herstellen. Die MD5-Authentifizierung ist meiner Meinung nach eine schlechte Praxis. Wenn Sie Probleme mit der Datenbankkonsistenz oder Ähnlichem haben, können Sie sich trotzdem anmelden, wenn Sie postgres die Verwendung von Peer-Authentifizierung erlauben.
    • Jeder Kunde sollte sein eigenes Schema und keine Datenbank erhalten. Dafür gibt es mehrere Gründe:
      • Der Besitz der gesamten Datenbank würde viele Berechtigungen gewähren.
      • Nur bestimmte Tabellen zu besitzen, würde Probleme für Entwickler mit sich bringen und würde immer erfordern, Administratoren zu bitten, Berechtigungen und andere Dinge hinzuzufügen.
      • In einer normalen Konfiguration würde jeder von ihnen Zugriff erhalten, um Elemente in seinem Schema zu erstellen, einschließlich Tabellen, Ansichten, Trigger usw.
      • Alle von ihnen verwenden die gleiche Verbindungszeichenfolge mit Ausnahme des Benutzernamens. Wenn Sie in postgres standardmäßig ein Schema mit dem Namen Ihres Benutzers haben, befindet es sich automatisch in Ihrem Suchpfad.
    • Ich würde mich aus Sicherheitsgründen dafür entscheiden, keinen Administrator zu haben, der auf jedes Schema zugreifen kann. Sie sollten Sicherungen durchführen, indem Sie entweder jedes Schema mit einem eigenen Benutzer sichern oder die PITR-Technik von PostgreSQL verwenden. Sie müssten immer noch den Benutzer postgres verwenden, um neue Schemas zu erstellen. Dafür würde ich eine Sudo-Regel und ein Skript verwenden.
    • In vielen bewährten Sicherheitsmethoden wird empfohlen, das Standardschema zu löschen.
    • Diese Lösung eignet sich hervorragend, wenn die DB für jeden Kunden klein ist und Sie Tonnen von Kunden haben.
    • Wenn Ihre Anwendung mandantenfähig ist, kann sie einen einzigen Verbindungspool für alle Kunden verwenden. Dies beseitigt natürlich viele der oben genannten Sicherheitsverbesserungen, kann jedoch Leistungsvorteile mit sich bringen, insbesondere wenn Sie eine große Anzahl von Kunden haben (wenn Sie 500 bis 1000 separate Datenquellen haben und das Verbindungspooling verwenden, ist dies ziemlich überwältigend).
  2. Jeder Kunde erhält einen eigenen Datenbankcluster. Dies ist meine bevorzugte Lösung, insbesondere weil ich normalerweise mit Anwendungen arbeite, die pro Kunde große Datenbanken haben.

    • Dieser bringt eine sehr gute Datentrennung. Sie können separate Speichervolumes für jeden Kunden verwenden, CPU- und Speicherbeschränkungen zuweisen (Docker verwenden?).
    • Wirklich gute Flexibilität, was jeder Kunde in seiner Instanz braucht. Sie können entweder ähnlich sein oder unterschiedliche Merkmale aufweisen.
    • Sehr einfach in beide Richtungen zu skalieren (auf und ab).
    • Ich verwende auch separate virtuelle IP-Adressen, bei denen jeder Cluster auf Verbindungen wartet, sodass keine Neukonfiguration der Datenquelle erforderlich ist.
    • PITR-Backups werden pro Kunde erstellt, sodass es einfacher ist, einen einzelnen Kunden wiederherzustellen, als dies bei einer Mandantenfähigkeit pro Schema der Fall ist.
    • Bei komplexen Setups benötigt jeder Kunde möglicherweise mehrere Datenbanken, Schemas, Benutzer und Rollen usw., sodass dies in diesen Fällen eine bessere Lösung darstellt.

Sie können auch eine Kombination der oben genannten Optionen verwenden und pgBouncer als Router verwenden.

Florin Asăvoaie
quelle