25 octobre 2014

pg_hba + SSL



Dans les deux précédentes parties (pg_hba part1 et pg_hba part2) nous avons vu comment accepter les connections à un serveur Postgresql en local sans mot de passe, puis avec mot de passe, puis via le réseau. Le point faible de l’accès via le réseau est qu’il n’était pas obligatoirement crypté. Pourtant dans les environnements où le serveur n’est pas dans un réseau totalement sous contrôle (comme dans les hébergements  cloud) le cryptage s’impose.  C’est donc ce que nous allons faire maintenant : configurer et activer  l’authentification et le cryptage (via SSL) de notre serveur Postgresql  ET de notre client pgAdmin.

1) pg_hba.conf

Il n’y a qu'un seul mot à changer dans le fichier pg_hba.conf !
Il suffit de remplacer « host » par « hostssl » et on obtient une ligne du type :

hostssl     all    all    xx.xx.xx.xx/nn     md5

NOTES:
-    On parle ici de SSL, pas du SSH. Un tunnel  SSH est une autre technique utilisée quand le serveur et/ou le client ne supportent pas le cryptage de manière native.
-    Une ligne avec « host » accepte à la fois les connexions cryptées et non cryptées. Notre but étant de forcer le cryptage on ne doit pas garder de ligne « host » (sauf si elle est associée à des ip dont le chemin entre les clients et le serveur est totalement sous contrôle)


2) postgresql.conf

Là aussi pas grand-chose à faire. Il faut juste avoir la ligne « ssl = on » (et pas de ligne ssl =off !)

NB: Quand tout sera finit il faudra redémarrer le service postgresql.


3) Clés SSL coté serveur

Postgresql a besoin d’au moins 2 fichiers (server.crt et server.key) dans son répertoire data (PGDATA) pour pouvoir accepter les connexions SSL.  Comme le certificat du serveur sera signé par nous-même il n’y a pas besoin d’autres fichiers.
Le fichier server.key contient la clé privée du serveur. Ce fichier est secret et doit appartenir au daemon postgres et n’être lisible que par lui. Sinon ça ne marche pas !
Le fichier server.crt n’est pas secret, il contient le certificat du serveur. Il sera envoyé au client pour prouver l’identité du serveur. Il contient le nom du host où s’exécute Postgresql.

(voir plus bas le script bash genSrvKeyCrt qui génère automatiquement ces deux fichiers)


4) Clés SLL coté client

pgAdmin (ou autre client de Postgresql acceptant SSL) a besoin d’au moins 3 fichiers (root.crt, user-name.key user-name.crt).
Là aussi, le fichier user-name.key est une clé privée qui doit rester secrète et n’être lisible que par le client.
Le fichier user-name.crt est le certificat de l’utilisateur coté Postgresql. Il sera envoyé au serveur pour prouver l’identité de l’utilisateur. Il contient le nom de l’utilisateur coté Postgresql qui n’est pas forcément le même que l’utilisateur Unix ou Windows)
Le fichier root.crt est en fait exactement le même fichier que server.crt que l’on a déjà vu coté serveur.

(voir plus bas le script bash genCliKeyCrt qui génère automatiquement ces deux fichiers)


5) scripts + openssl

(ce qui suit est moins long qu'il ne parait ...)

Les deux fichiers coté serveur (server.crt et server.key) sont à générer en premier, et  une fois pour toute. Le fichier server.crt coté serveur servant de root.crt coté client pour tous les utilisateurs, si on régénère les fichiers coté serveur il faut régénérer tous les certificats des utilisateurs.

Les deux fichiers coté client (user-name.key  et user-name.crt) sont générés à la demande pour chaque utilisateur accepté par le serveur Postgresql. Ces fichiers étant associés à l’utilisateur de Postgresql ils peuvent être partagés par plusieurs utilisateurs Unix accédant à Postgresql de la même manière.

Pour simplifier la création de ces clés et certificats on va utiliser deux scripts shell qui enchaineront les commandes openssl nécessaires pour générer tous ces fichiers.

On suppose que les deux scripts sont quelque part dans le PATH et que l'on travaille dans cette arborescence :

...
  |
  +--> server/
  |     +--> server.key
  |     +--> server.crt
  |
  +-- clients/
       +--> user-name.key
       +--> user-name.crt
       +--> root.crt

En copiant les deux scripts ci-dessous attention à ne pas insérer d'espaces après les \ en fin de ligne.
 

======================
==== genSrvKeyCrt ====
======================
#!/bin/bash

HOST=$(hostname)

# Coté serveur on a besoin de deux fichiers.
#  1) server.key  (clé privée du serveur)
#  2) server.crt  (certificat/identité du serveur)

# 1.1) Création de la clé privé du serveur
openssl genrsa             \
        -des3              \
        -out server.key    \
        -passout pass:1234 \
        1024

# 1.2) Supprime la passphrase (1234) de la clé privé
openssl rsa             \
        -in server.key  \
        -out server.key \
        -passin pass:1234

# 1.3) Vérification
openssl rsa -in server.key -check -noout

# 2.1) Création d'un certificat auto certifié d'une validité de 10 ans
openssl req             \
        -new            \
        -x509           \
        -days 3650      \
        -key server.key \
        -out server.crt \
        -subj "/OU=pgserver/CN=$HOST"

# 2.2) Vérification
openssl verify -CAfile server.crt server.crt

# Afficher le certificat (facultatif)
# openssl x509 -in server.crt -text -noout


### end ###

L’exécution donne ceci :

    > cd /path/to/server
    > GenSrvKeyCrt.sh
    Generating RSA private key, 1024 bit long modulus
    ..................++++++
    ...++++++
    e is 65537 (0x10001)
    writing RSA key
    RSA key ok
    server.crt: OK


Copier server.crt et server.key dans le répertoire PGDATA du serveur Postgresql.
Veiller à ce qu'ils appartiennent à 'postgres' et qu'ils ne soit lisibles que par 'postgres'.

> ls -l /path/to/postgres/data/server.*
-rw------- 1 postgres postgres 769 Oct 24 19:56 /home/postgres/data/server.crt
-rw------- 1 postgres postgres 887 Oct 24 19:56 /home/postgres/data/server.key


REDEMARRER le service postgresql avec : systemctl reload postgresql


======================
==== GenCliKeyCrt ====
======================
#!/bin/bash

if [ "$1" == "" ]; then
  echo
  echo "   Usage: $0 pgUserName"
  echo "Exemples: $0 jean"
  echo "          $0 postgres"
  echo
  exit
fi

PGUSER=$1

echo
echo "Création de la clé et du certificat pour $PGUSER"
echo

# Coté client on a besoin de 3 fichiers
#  1) root.crt   (l’autorité de certification (nous!))
#  2) .key (clé privée de l'utilisateur)
#  3) .crt (certificat/identité de l'utilisateur)


# 1) importer root.crt du répertoire frère 'server'
cp ../server/server.crt root.crt

# 2.1) Création de la clé privée user-name.key pour le client
openssl genrsa             \
        -des3              \
        -out $PGUSER.key   \
        -passout pass:1234 \
        1024

# 2.2) Supprime la passphrase (1234) de la clé privée
openssl rsa                \
        -in  $PGUSER.key   \
        -out $PGUSER.key   \
        -passin pass:1234

# 2.3) Vérification
openssl rsa -in $PGUSER.key -check -noout

 

# 3.1) Création du certificat user-name.crt pour le client
openssl req                \
        -new               \
        -key $PGUSER.key   \
        -out $PGUSER.csr   \
        -subj "/OU=pgclient/CN=$PGUSER"

# 3.2) Signature par le serveur du certificat du client
openssl x509               \
       -req                \
       -CAcreateserial     \
       -in    $PGUSER.csr  \
       -out   $PGUSER.crt  \
       -CA    root.crt     \
       -CAkey ../server/server.key



#fichier maintenant inutile

rm $PGUSER.csr

# 3.3) Vérifications
openssl verify -CAfile root.crt $PGUSER.crt
openssl verify -CAfile root.crt ../server/server.crt

# Affiche le certificat (facultatif)
# openssl x509 -in $PGUSER.crt -text -noout


### end ###

L’exécution donne ceci :

    > cd /path/to/client
    > GenCliKeyCrt.sh  bidule

    Création de la clé et du certificat pour bidule

    Generating RSA private key, 1024 bit long modulus
    ...........................................++++++
    ..++++++
    e is 65537 (0x10001)
    writing RSA key
    RSA key ok
    Signature ok
    subject=/OU=client/CN=bidule
    Getting CA Private Key
    bidule.crt: OK
    ../server/server.crt: OK



Copier les trois fichiers (bidule.csrbidule.keyroot.crt) sur la machine client.
Puis configurer la partie SSL de pgAdmin comme indiqué ci-dessous.


La partie "Properties" est configurée comme d’habitude avec le nom du user (bidule) et son password. Mais maintenant tout sera crypté et le serveur comme le client se seront authentifié car partageant le même root.crt.

Le premier utilisateur pour le quel on fait tout cela est en général 'postgres'  et non 'bidule' ;-)