Mise en œuvre des meilleures pratiques des rôles Postgres

21

Gens,

Je pourrais utiliser votre aide pour améliorer la conception de mon contrôle d'accès utilisateur Postgres et l'aligner sur les meilleures pratiques. J'aide à déployer un petit serveur Postgres de production mais je ne suis pas administrateur de base de données, donc j'en sais juste assez pour être dangereux.

Il y a un serveur avec une installation de Postgres v9.2. Cette installation héberge plusieurs bases de données, chacune servant pleinement un "client" différent. En d'autres termes, customer1 n'utilisera pas, ne devrait pas utiliser database2, etc. Pendant les opérations normales, chacune des bases de données est accessible par une instance correspondante de CakePHP, tous co-localisés sur le même serveur que Postgres. Bien qu'il puisse y avoir des optimisations possibles sur ce déploiement, je suis principalement intéressé par les rôles Psql.

D'après ce que j'ai lu, il semble que trois types de rôles auraient du sens:

  • Postgres de superutilisateur avec mot de passe non par défaut
  • Un rôle d'administrateur qui n'a pas de privilèges de superutilisateur pour la maintenance de routine, la création de bases de données, la sauvegarde, la restauration. Devrait être capable de tout faire avec toutes les bases de données clients.
  • Rôles d'utilisateur avec juste la possibilité de CRUD dans leur base de données respective. Plus de droits sur leur propre base de données pourraient être tolérés s'il nettoie l'implémentation.

La mise en œuvre de cette conception est l'endroit où je suis beaucoup moins confiant. Propriété de DB par rapport à table et qui devrait hériter de qui est un peu boueux. Voici mes bases de données et mes utilisateurs. Est-ce assez d'informations pour évaluer la mise en œuvre?

     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

Pour empêcher les connexions externes et les mots de passe en clair, pg_hba.conf est comme tel:

local   all             all                                     md5
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5
JP Beaudry
la source
1
D'après mon expérience, la meilleure séparation qui apporte également une énorme quantité d'autres avantages est d'exécuter des clusters PostGreSQL distincts (par exemple des services) pour chaque client. C'est ce que nous faisons actuellement pour un grand environnement de production en ce moment et je ne le ferais pas différemment à moins que le nombre de DB ne devienne vraiment grand et que chacune d'entre elles soit vraiment petite. Bien sûr, l'application doit également savoir comment se connecter à une source de données différente pour chaque locataire (client).
Florin Asăvoaie
A côté de @ FlorinAsăvoaie sa remarque. Chaque base de données ne devrait-elle pas avoir son propre utilisateur propriétaire et utilisateur de requête? Cela faciliterait la mise de certains utilisateurs dans un coffre de mots de passe à des fins de maintenance.
hspaans

Réponses:

5

Je sais que c'est une vieille question, mais j'essaierai d'y répondre même maintenant, car je dois faire des recherches à ce sujet.

Ce que vous essayez de faire est appelé multi-location au niveau de la base de données. Cela peut être réalisé de deux manières:

  1. Dans un cluster de base de données unique, un peu comme décrit l'OP, cependant, mon choix personnel serait le suivant:

    • L'utilisateur postgres utilise l'authentification par les pairs et n'est pas autorisé à se connecter par mot de passe. L'authentification MD5, à mon avis, est une mauvaise pratique. Si vous rencontrez des problèmes avec la cohérence de la base de données ou ce genre de choses, vous pourrez toujours vous connecter si vous permettez à postgres d'utiliser l'authentification par les pairs.
    • Chaque client doit obtenir son propre schéma et non sa base de données. Il y a plusieurs raisons à cela:
      • La possession de la base de données entière accorderait beaucoup de privilèges.
      • Posséder uniquement des tables spécifiques poserait des problèmes aux développeurs et nécessiterait toujours de demander aux administrateurs d'ajouter des autorisations et d'autres éléments.
      • En tant que tel, dans une configuration normale, chacun d'entre eux aurait accès à créer des choses à l'intérieur de son schéma, y ​​compris des tables, des vues, des déclencheurs, etc.
      • Tous utilisent la même chaîne de connexion à l'exception du nom d'utilisateur. Dans postgres, par défaut, si vous avez un schéma avec le nom de votre utilisateur, il est automatiquement dans votre chemin de recherche.
    • J'opterais pour ne pas avoir un utilisateur administrateur capable d'accéder à chaque schéma, par mesure de sécurité. Vous devez effectuer des sauvegardes en vidant chaque schéma avec leur propre utilisateur ou en utilisant la technique PITR de PostgreSQL. Vous auriez encore besoin d'utiliser l'utilisateur postgres pour créer de nouveaux schémas, j'opterais pour une règle sudo et un script pour cela.
    • De nombreuses bonnes pratiques en matière de sécurité recommandent de supprimer le schéma par défaut - c'est parti.
    • Cette solution est extrêmement appropriée si la base de données de chaque client est petite et que vous avez des tonnes de clients.
    • Si votre application gère l'hébergement multiclient, elle peut utiliser un pool de connexions unique pour tous les clients. Bien sûr, cela élimine bon nombre des améliorations de sécurité ci-dessus mais pourrait avoir des avantages en termes de performances, en particulier lorsque vous avez un grand nombre de clients (si vous avez comme 500-1000 sources de données distinctes et que vous utilisez le pool de connexions, ce sera assez écrasant).
  2. Chaque client obtient son propre cluster de base de données. C'est ma solution préférée, surtout parce que je travaille généralement avec des applications qui ont de grandes bases de données pour chaque client.

    • Celui-ci apporte une très bonne séparation des données. Vous pouvez utiliser des volumes de stockage distincts pour chaque client, allouer des limitations de CPU et de mémoire (à l'aide de Docker?).
    • Très bonne flexibilité sur les besoins de chaque client dans son instance. Ils peuvent être similaires ou avoir des caractéristiques distinctes.
    • Très facile à mettre à l'échelle dans les deux sens (vers le haut et vers l'extérieur).
    • J'utilise également des adresses IP virtuelles distinctes où chaque cluster écoute les connexions, ce qui évite d'avoir à reconfigurer la source de données.
    • Les sauvegardes PITR sont effectuées par client, il sera donc plus facile de restaurer un seul client par rapport à l'hébergement multiclient par schéma.
    • Dans les configurations complexes, chaque client peut avoir besoin de plusieurs bases de données, schémas, utilisateurs et rôles, etc., c'est donc une bien meilleure solution dans ces cas.

Vous pouvez également utiliser une combinaison des éléments ci-dessus et utiliser pgBouncer comme routeur.

Florin Asăvoaie
la source