Confiner PostgreSQL avec SELinux

22/09/2014, 14:23:47

J'avais déjà expérimenté un peu avec SELinux il y a deux ans sans aller trop loin, parce que j'entendais souvent la phrase "Si on veut de la sécurité, il faut SELinux" et surtout à cause de l'arrivée de l'extension sepgsql dans les modules contrib de PostgreSQL. Ça avait donné une conf pour le Fosdem où finalement, j'ai plus parlé des privilèges classiques que de SELinux.

Suite à une demande au ${BOULOT}, je me suis replongé dedans, et les choses ont peu évolué. Dans la majorité des recherches que j'ai pu faire, SELinux reste tout de même un truc qui se met en travers la route, c'est-à-dire, qu'il y a toujours plus de résultats sur comment le désactiver plutôt que configurer les choses correctement. Ensuite, certains proposent de faire aveuglement confiance à setroubleshoot et audit2allow pour faire taire la bête. Enfin, j'ai dû trouver une page ou deux après en deux semaines à temps plein sur le sujet qui parlent de comment confiner un utilisateur dans le but d'implémenter ce que promet SELinux et que toutes les entreprises demandent : le RBAC, Role Based Access Control, ou comment donner le moins de droits possibles aux sous-traitants qui hébergent les serveurs.

Cette fois ci, je suis allé plus loin. Déjà, je suis parti sur une installation de CentOS 6, la famille de distribution RHEL/CentOS/Fedora semble être la plus en avance par rapport à SELinux : à peu près tous les services/daemons fournis dans l'install sont confinés par SELinux. Les utilisateurs ne le sont pas au login, il n'y a donc aucune configuration de RBAC. On verra peut-être ça plus tard, j'ai pas encore obtenu de résultat satisfaisant sur ce sujet, et il vaut mieux expliquer comment confiner correctement PostgreSQL avant de passer aux roles. Tout simplement, parce qu'il est très simple de casser ce confinement avec la configuration par défaut de RHEL, grâce à pg_ctl. Enfin, l'installation des paquets du PGDG n'est pas confinée par défaut, il manque les file contexts adaptés aux chemins particuliers de ces paquets, prévu pour faire cohabiter plusieurs versions majeures ; ce qui ne correspond pas ce qu'à prévu Red Hat pour PostgreSQL.

Après cette longue introduction, mais avant de commencer, il faut savoir administrer un minumum SELinux : si vous ne savez pas qu'il existe des options -Z, ce que sont les contexts, les types et les domaines, mieux vaut d'abord se documenter, par exemple chez Red Hat.

Voici donc les file contexts à ajouter dans un fichier module.te pour confiner l'installation PostgreSQL du PGDG :

/etc/rc\.d/init\.d/(se)?postgresql(-.*)?    --  gen_context(system_u:object_r:postgresql_initrc_exec_t,s0)
/usr/pgsql-[0-9]+\.[0-9]+/bin/initdb        --  gen_context(system_u:object_r:postgresql_exec_t,s0)
/usr/pgsql-[0-9]+\.[0-9]+/bin/pg_ctl        --  gen_context(system_u:object_r:postgresql_initrc_exec_t,s0)
/usr/pgsql-[0-9]+\.[0-9]+/bin/postgres      --  gen_context(system_u:object_r:postgresql_exec_t,s0)
/usr/pgsql-[0-9]+.[0-9]+/share/locale(/.*)?     gen_context(system_u:object_r:locale_t,s0)
/usr/pgsql-[0-9]+.[0-9]+/share/man(/.*)?        gen_context(system_u:object_r:man_t,s0)

Tout d'abord, pour l'init script et pg_ctl, on utilise le type postgresql_initrc_exec_t, c'est ce qui permet de lancer PostgreSQL dans le domaine confiné postgresql_t au boot, via l'init script, et manuellement. La méthode la plus propre est de toujours utiliser l'init script, idéalement par l'intermédiaire de run_init pour démarrer, arrêter ou redémarrer le postmaster. On évite alors de laisser trainer des choses dans /var/{run,lock}.

Les programmes postgres et initdb doivent avoir le type postgresql_exec_t car ils exécutent le serveur PostgreSQL ; cela doit se faire dans le domaine postgresql_t.

Enfin, on a placé les labels corrects sur les fichiers de traduction et les pages de man, pour faire plus propre. Ce code source de module SELinux alors doit être compilé et chargé.

Cette configuration est reprise dans le module SELinux disponible sur github. On peut aussi l'ajouter manuellement avec semanage :

semanage fcontext -a -t postgresql_initrc_exec_t '/etc/rc\.d/init\.d/(se)?postgresql(-.*)?'
semanage fcontext -a -t postgresql_exec_t '/usr/pgsql-[0-9]+\.[0-9]+/bin/initdb'
semanage fcontext -a -t postgresql_initrc_exec_t '/usr/pgsql-[0-9]+\.[0-9]+/bin/pg_ctl'
semanage fcontext -a -t postgresql_exec_t '/usr/pgsql-[0-9]+\.[0-9]+/bin/postgres'
semanage fcontext -a -t locale_t '/usr/pgsql-[0-9]+.[0-9]+/share/locale(/.*)?'
semanage fcontext -a -t man_t '/usr/pgsql-[0-9]+.[0-9]+/share/man(/.*)?'

Il existe un certain nombre de booleans pour la configuration des droits SELinux de PostgreSQL, le plus important concerne rsync, souvent nécessaire pour faire des base backups. Il s'agit de postgresql_can_rsync, pour l'activer :

semanage boolean -m --on postgresql_can_rsync

Si on lance l'instance sur un port TCP différent de 5432, il faut l'autoriser dans la configuration locale de SELinux :

semanage port -a -t postgresql_port_t -p tcp <port>

Enfin, il ne faut pas oublier d'appliquer les contexts aux fichiers soit avec restorecon, un relabel complet au reboot ou chcon.

Les stats de PostgreSQL dans un tmpfs avec Proxmox

29/07/2014, 20:30:14

Au ${BOULOT}, on utilise Proxmox pour virtualiser, et surtout des containers OpenVZ (pour les hypeux qui ne jurent que par lxc, c'était et c'est pas encore si sec que ça lxc, faut beaucoup enrober, et on n'a pas le temps). Les machines PostgreSQL se trouvent donc être des containers OpenVZ.

Pour soulager les disques de certains I/O, des fois ça aide de placer le répertoire de travail du stats collector, par défaut $PGDATA/pg_stat_tmp et configurable par le GUC stats_temp_directory sur un ramdisk.

Sauf que dans un container, le guest ne peut pas manipuler ses filesystems, on doit passer par l'hyperviseur. Dans le cas d'OpenVZ, on peut ajouter un programme sous le nom CTID.mount qui permet de monter, justement, un tmpfs. Ce fichier est à placer à coté du fichier de conf, dans /etc/vz/conf.

On decide alors de placer nos stats dans /var/lib/postgresql/tmpfs, un tmpfs en mémoire. On ajoute ces répertoires pour garder la hiérarchie classique des instances PostgreSQL sur Debian : 9.3/main/pg_stat_tmp.

On écrit donc le script shell suivant dans /etc/vz/conf/CTID.mount, ou CTID est le numéro du container :

#!/bin/sh
# Script de montage d'un tmpfs pour les stats de PostgreSQL

# If one of these files does not exist then something
# is really broken
[ -f /etc/vz/vz.conf ] || exit 1
[ -f $VE_CONFFILE ] || exit 1
# Source both files. Note the order is important.
. /etc/vz/vz.conf
. $VE_CONFFILE

mountpoint=/var/lib/postgresql/tmpfs
subdir=9.3/main/pg_stat_tmp
postgres_uid=104
postgres_gid=108
size=104857600 # 100 Mo

mkdir -p ${VE_ROOT}${mountpoint}
mount -t tmpfs -o size=${size},uid=${postgres_uid},gid=${postgres_gid},mode=0700 tmpfs ${VE_ROOT}${mountpoint}
mkdir -p ${VE_ROOT}${mountpoint}/${subdir}
chown -R ${postgres_uid}.${postgres_gid} ${VE_ROOT}${mountpoint}

Dans le script tout ce fait dans le context de l'hyperviseur, c'est pourquoi on utilise les uid/gid numériques de postgres dans le container pour que les permissions soient correctes dès le boot.

Enfin, il ne reste qu'à modifier le fichier postgresql.conf pour configurer stats_temp_directory :

stats_temp_directory = '/var/lib/postgresql/tmpfs/9.3/main/pg_stat_tmp'

On peut alors redémarrer le container sur l'hyperviseur :

# vzctl restart CTID

Et voir depuis le container le nouveau FS :

# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/simfs      100G   28G   73G  28% /
tmpfs           100M   12K  100M   1% /var/lib/postgresql/tmpfs
tmpfs           410M   32K  410M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           820M     0  820M   0% /run/shm

pgbench et .pgpass

16/06/2014, 10:51:44

En faisant quelques tests sur le Foreign Data Wrapper, j'ai (re)fait un peu de pgbench. Pour ceux qui ne savent pas pgbench permet de simuler un benchmark TPC-B, en gros des lectures, des écritures par un certain nombre de sessions concurrentes.

Même si on peut le considérer simpliste par rapport à un Tsung, il est fourni dans les contribs de PostgreSQL et permet de facilement tester un aspect qu'on néglige souvent : les effets de la concurrence sur une base.

J'ai donc monté mon petit environnement de test avec un rôle pour pgbench et sa base dédiée. Pour aller plus vite, j'en ai profité pour configurer un fichier .pgpass, sauf que pgbench n'en voulait pas :

postgres@fdw:~$ cat .pgpass 
localhost:5432:*:bench:Clair!

postgres@fdw:~$ pgbench -h localhost -n -c 10 -j 10 -U bench bench
Password: 
Connection to database "bench" failed:
fe_sendauth: no password supplied

Poutant, la ligne pour l'utilisateur bench est correcte. Si on lui fournit explicitement le port 5432, il tient compte de l'entrée dans le .pgpass :

postgres@fdw:~$ pgbench -h localhost -n -c 10 -j 10 -U bench -p 5432 bench
transaction type: TPC-B (sort of)
scaling factor: 500
query mode: simple
number of clients: 10
number of threads: 10
number of transactions per client: 10
number of transactions actually processed: 100/100
tps = 77.993447 (including connections establishing)
tps = 88.977249 (excluding connections establishing)

La lecture de ce thread, qui se conclut sur ce patch, nous éclaire sur ce comportement.

Selon le message de commit, la modification change le comportement de la libpq. Elle n'a pas été backportée sur les autres branches et ne sera donc disponible que pour la libpq de la version 9.4 (ou Debian/Ubuntu qui prend toujours la dernière version de la libpq).

Migration du blog sur github

28/05/2014, 18:29:31

Finalement le temps ne me permettant plus d'administrer mon serveur dédié comme il faut, j'ai décidé de l'abondonner et transférer mes services ailleurs. Pour le blog et le wiki, j'ai choisi de faire un site/blog github avec jekyll, vu que c'est tout prémaché.

Sur github, l'hébergement c'est du fichier html, donc statique, on a plusieurs possibilités pour créer un site :

L'avantage de pelican est dans sa capacité à importer le contenu d'un blog dotclear, et transformer la syntaxe en markdown. Le markdown semble avoir la cote, beaucoup de générateurs de site l'utilisent, d'ailleurs je m'y suis mis.

Comme j'avais déjà fait le site de pitrery avec jekyll sur github, la migration fut plus facile, une fois le dotclear migré grâce à pelican.

Au final, j'ai maintenant un truc tout simple avec un thème bootstrap, et le jekyll de base de github est largement suffisant.

La bonne découverte fut pandoc, un super convertisseur de format de document texte, qui va me servir pour la migration du dokuwiki à base de :

pandoc -f html -t markdown http://wiki.orgrim.net/page?do=export_html

Le mot de la fin, ça demande un peu de boulot de nettoyage manuel, mais vu le nombre impressionant de posts que j'ai pu produire en quatre ans, c'était pas trop méchant.

modular-xorg, radeon et pas de KMS

23/08/2013, 19:10:00

Il y avait un moment que je n'avais pas touché à NetBSD et donc mis à jour mon lappy avec du pkg frais. Entre temps, la version de X.org modular, donc issue de pkgsrc, est revenue en 2012, avec son lot de drivers mis à jour. Le drivers xf86-video-ati, est passé en version 7.1.0, sauf qu'il fonctionne uniquement en KMS (Kernel Mode Setting), chose qu'on n'a pas encore dans notre kernel.

Il faut donc la dernière version de la branche 6 du driver, qui contient encore le support UMS, disponible dans le paquet x11/xf86-video-ati6, qui porte le même nom de package, bizarrement. Tout ça est suivi dans le PR 47935.

Pour que le serveur X trouve le device avec ce driver, j'ai du virer la ligne BusID dans la section Device du xorg.conf.