Ajouter SSL à une plateforme OpenStack existante: MariaDB/Galera

Ce post est le second d'une série visant à transformer une déploiement classique d'OpenStack en un déploiement avec support du SSL. Ce post vise à l'ajout du support du SSL à la base de donnée MariaDB/Galera.

Le premier post de la série concerne: RabbitMQ.

Rappel de la plateforme visée

La plateforme de test est composée de 3 ctrls hébergeant l'ensemble des services requis pour une utilisation d'OpenStack. Voir Plateformes expérimentales pour plus de détails.

De plus, un début de PKI est présent dans /etc/pki (cf le post précédent):

  • une autorité racine: CA
  • une autorité intermédiaire pour les systèmes: iCA (export-ca.crt)
  • un certificat partagé entre les ctrls (ctrl.crt et ctrl.key)

Objectifs

Il existe trois types de communication avec une grappe de serveurs MariaDB/Galera:

  • les communications entre un client et les serveurs
  • les communications de mise à jour entres les serveurs
  • les communications de synchronisation initiale entres les serveurs

Ces trois types de communications nécessitent une prise en charge spécifique.

Ajouter SSL à une plateforme OpenStack existante: RabbitMq

L'importance de chiffrer les communications entres les nœuds d'une plateforme afin de masquer les informations d'authentification n'est plus à démontrer. Ce post est le premier d'une série visant à remplacer les échanges en clair par des échanges chiffrés au sein d'une plateforme OpenStack existante.

Rappel de la plateforme visée

La plateforme de test est composée de 3 ctrls hébergeant l'ensemble des services requis pour une utilisation d'OpenStack. Voir Plateformes expérimentales pour plus de détails.

Création des certificats

La majorité des communications étant interne à la plateforme OpenStack, le choix d'un autorité locale de certification paraît naturelle. Par conséquent, nous générons:

  • une autorité racine: CA
  • une autorité intermédiaire pour les systèmes: iCA
  • un certificat partagé entre les ctrls

Il existe de nombreuse manière pour générer ces certificats. Dans la suite de cette section, nous allons utiliser l'outil easy-rsa (diverses documentations existent, par exemple la page d'OpenVPN que nous reprenons ici):

# apt-get install easy-rsa

Autorité racine

  • initialisation de l'environnement: L'environnement nécessaire à easy-rsa est généré dans un répertoire cloud-ca. Cet environnement contient un fichier de configuration vars qui peut être adapté (en particulier, les variables d'environnement KEY_COUNTRY, KEY_PROVINCE, KEY_CITY, KEY_ORG, KEY_EMAIL et KEY_OU).

    $ cd <basedir>
    $ make-cadir cloud-ca
    $ cd cloud-ca
    $ source ./vars
    $ ./clean-all
    
  • création de l'autorité de certification (cloud-ca/keys/ca.crt et cloud-ca/keys/ca.key):

    $ ./build-ca
    

Autorité de certification intermédiaire

  • À partir de cloud-ca, création des clé et certificat de l'autorité intermédiaire (cloud-ca/keys/inter.crt et cloud-ca/keys/inter.key):

    $ ./build-inter
    
  • Création de l'environnement de l'autorité intermédiaire:

    $ cd <basedir>
    $ make-cadir cloud-ica
    $ cd cloud-ica
    $ source ./vars
    $ ./clean-all
    
  • Création de l'autorité de certification intermédiaire (cloud-ica/keys/ca.crt, cloud-ica/keys/ca.key et cloud-ica/keys/export-ca.crt):

    $ ./inherit-inter <basedir>/cloud-ca/keys/ ica
    

Certificat des ctrls

  • À partir de l'autorité intermédiaire, création du certificat des ctrls (cloud-ica/keys/ctrl.crt et cloud-ica/keys/ctrl.key):

    $ cd <basedir>/cloud-ica
    $ source ./vars
    $ ./build-key-server ctrl
    

Installation des certificats

Seul les fichiers relatifs au certificat des ctrls sont déployés:

  • export-ca.crt: la chaine d'autorité de certification
  • ctrl.crt: le certificat publique des ctrls
  • ctrl.key: la clé privée des ctrls

Ces fichiers sont mis en place dans le répertoire /etc/pki (à créer si nécessaire) de chaque ctrl. Penser à vérifier les droits du fichier ctrl.key: 0440.

Configuration de RabbitMQ

L'activation du mode SSL se fait simplement par la définition ou l'ajout dans le fichier de configuration (/etc/rabbitmq/rabbitmq.config):

# cat <<EOF > /etc/rabbitmq/rabbitmq.config
[
    {ssl, [{versions, ['tlsv1.2', 'tlsv1.1']}]},
    {rabbit, [
        {tcp_listeners, []},
        {ssl_listeners, [5671]},
        {ssl_options, [{cacertfile,"/etc/pki/export-ca.pem"},
                       {certfile,  "/etc/pki/ctrl.cert"},
                       {keyfile,   "/etc/pki/ctrl.key"},
                       {versions, ['tlsv1.2', 'tlsv1.1']}
                      ]
        }]
    }
].
EOF

Dans cette configuration, seule les protocoles TLSv1.1 et TLSv1.2 sont autorisés. De plus, l'écoute pour des communications en claires est désactivée (aucun port affecté à tcp_listeners).

L'ensemble est redémarré, et le tour est joué!

# /etc/init.d/rabbitmq-server restart

Une première vérification (hormis les fichiers de log) consiste à vérifier que seul le port 5671 est utilisé (au lieu du port 5672).

# netstat -anvp

Mise à jour de la configuration des services d'OpenStack

Du coté des services d'OpenStack, la prise en compte du SSL se fait simplement par modification de la section [oslo_messaging_rabbit] présente dans les fichiers de configuration (service par service: /etc/keystone/keystone.conf, /etc/nova/nova.conf, etc.). Il s'agit d'ajouter une ligne:

[oslo_messaging_rabbit]
...
rabbit_use_ssl = True
...

KVM in KVM

Objectif

Il s'agit de pouvoir exécuter une machine virtuelle de type KVM, à l'intérieur d'une première machine virtuelle (KVM, elle aussi).

Un des avantages de cette idée est de pouvoir développer et tester des hyperviseurs comme des machines virtuelles classiques.

Problème

Pas vraiment de difficulté, il suffit d'avoir du matériel et un noyau relativement récent.

Environnement de départ

  • une machine physique alpha (avec processeur Intel) - noyau 4.6 (jessie-backports) - libvirt (jessie-backports)

Environnement cible

  • une VM hostkvm (créée depuis l'hyperviseur), avec un environnement libvirt / qemu
  • une VM guestkvm (créée depuis hostkvm)

Étapes

Afin de pouvoir créer une VM KVM depuis une première VM, il suffit simplement de s'assurer que la bonne configuration du paramètre:

  • /sys/module/kvm_intel/parameters/nested
  • /sys/module/kvm_amd/parameters/nested

Donc première chose à faire (à adapter au type de processeur utilisé):

$ cat /sys/modules/kvm_intel/parameters/nested
Y

Si la réponse est N (ou 0), il faudra recharger le module en définissant cette option à 1 (ou Y). Cela peut être fait:

  • soit en paramètre de démarrage du noyau: kvm-intel.nested=1 (suivit d'un redémarrage de la machine)

  • soit en option pour modprobe:

    # rmmod kvm-intel
    # echo "options kvm-intel nested=y" > /etc/modprobe.d/kvm.conf
    # modprobe kvm-intel
    

Si la réponse au test est toujours négative c'est que votre noyau / distribution / plateforme matérielle est trop ancien(ne).

Lorsque l'option est activée, il suffit de créer sa première VM (hostkvm) avec l'option:

<cpu mode="host-passthrough"></cpu>

Ainsi, en employant l'outil de création de VM virt-install et le paramètre --cpu host-passthrough, cela donne:

# hostname
alpha
# virt-install --name hostkvm --cpu host-passthrough --ram 4096 --location http://ftp.fr.debian.org/debian/dists/jessie/main/installer-amd64/ --disk size=5 --os-variant debianwheezy --console "pty,target_type=serial" --extra-args="console=ttyS0,115200n8 serial" --network bridge=virbr0

L'option existe de manière similaire au travers de l'interface graphique virt-manager.

On se connecte à la VM par ssh ou directement sur la console, on configure rapidement un environnement libvirt, et on crée la VM guestkvm:

# hostname
hostkvm
# apt-get install ebtables libvirt-bin virtinst
# virsh net-start default
# virt-install --name guestkvm --ram 512 --location http://ftp.fr.debian.org/debian/dists/jessie/main/installer-amd64/ --disk size=1 --os-variant debianwheezy --console "pty,target_type=serial" --extra-args="console=ttyS0,115200n8 serial" --network bridge=virbr0

La seconde installation se réalise, et l'on peut vérifier à partir des diverses machines qui est contenue par qui:

# hostname
alpha
# virsh list
 Id    Name                           State
----------------------------------------------------
 4     hostkvm                        running
# ps aux | grep kvm
libvirt+ 20564  9.7  1.7 3209864 569788 ?      Sl   22:39   1:29 qemu-system-x86_64 -enable-kvm -name hostkvm -S -machine pc-i440fx-2.1,accel=kvm,usb=off -cpu host -m 4096 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 43642e0a-1022-4136-b8cd-d3b33747ded8 -nographic -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/hostkvm.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=discard -no-hpet -no-shutdown -boot strict=on -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x3.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x3 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x3.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x3.0x2 -drive file=/var/lib/libvirt/images/hostkvm-1.qcow2,if=none,id=drive-virtio-disk0,format=qcow2 -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -netdev tap,fd=24,id=hostnet0,vhost=on,vhostfd=25 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:d2:62:90,bus=pci.0,addr=0x2 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,id=input0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 -msg timestamp=on

Sur la machine alpha, libvirt contrôle une VM d'identifiant 4 et nommée hostkvm. Une recherche parmi les processus d'alpha ne montre la présence que d'un seul processus 20564, nommé hostkvm (avec kvm et 4096Mo de RAM).

# hostname
hostkvm
# virsh list
 Id    Name                           State
----------------------------------------------------
 3     guestkvm                       running
# ps aux | grep kvm
libvirt+  8693 59.0 15.0 951028 76064 ?        Sl   23:08   3:08 qemu-system-x86_64 -enable-kvm -name guestkvm -S -machine pc-i440fx-2.1,accel=kvm,usb=off -cpu Broadwell -m 512 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 7e5df8a8-7764-4dbb-a854-536fe4d6cce6 -nographic -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/guestkvm.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=discard -no-hpet -no-shutdown -boot strict=on -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x3.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x3 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x3.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x3.0x2 -drive file=/var/lib/libvirt/images/guestkvm.qcow2,if=none,id=drive-virtio-disk0,format=qcow2 -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -netdev tap,fd=24,id=hostnet0,vhost=on,vhostfd=25 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:ed:c3:19,bus=pci.0,addr=0x2 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,id=input0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 -msg timestamp=on

Sur la machine hostkvm, libvirt contrôle une VM d'identifiant 3 et nommée guestkvm. Une recherche parmi les processus d'hostkvm ne montre la présence que d'un seul processus 8693, nommé guestkvm (avec kvm et 512Mo de RAM).

Construire un module OpenStack à partir de ses sources

intro sur le fonctionnement des sources/documentations/configurations.

Tox est un outil d'automatisation de déploiement et de test réalisé en Python. Pour l'ensemble des fonctionnalités, détails et mode d'emploie de Tox, veuillez-vous reporter au site de l'outil.

installation de tox

$ sudo pip install tox

installation des dépendances de construction

utilisation de tox

KVM in LXC

Objectif

Exécuter une machine libvirt/KVM dans un container LXC.

Problème

La principale difficulté réside dans la gestion des droits à accorder au container afin que KVM puisse s'exécuter.

Environnement de départ

  • noyau 4.6 (jessie-backports)
  • lxc: (jessie-backports)
  • bridge br0 (192.168.0.254/24 qui servira de passerelle au container)

Environnement cible

  • un container LXC
    • une IP 192.168.0.10/24, passerelle 192.168.0.254
    • une IP interne 192.168.1.254 pour un réseau interne au container: 192.168.1.0/24 pour les machines virtuelles KVM
  • une VM KVM

Étapes

  • Vérifications initiales:

    • autorisation de /dev/kvm (pour l'accélation de Qemu)

      S'assurer de la présence de la ligne suivante dans /usr/share/lxc/config/debian.common.conf

      lxc.cgroup.devices.allow = c 10:232 rwm
      
    • autorisation de /dev/net/tun (pour la création d'interfaces virtuelles par libvirt)

      S'assurer de la présence de la ligne suivante dans /usr/share/lxc/config/debian.common.conf

      lxc.cgroup.devices.allow = c 10:200 rwm
      
  • création d'un nouveau container (nommé lxchost):

    • Création de l'arborescence lxchost (dans le répertoire courant) à partir du template Debian

      # cd /var/lib/lxc
      # lxc-create -t debian lxchost
      
    • Autoriser l'accès (depuis le container) à l'ensemble de sysfs (en rw)

      • Dans le fichier ./lxchost/config, ajout de

        lxc.mount.auto = sys:rw
        
      • Cette manipulation donne beaucoup de droits au container (y compris sur le système hôte)

    • Mise en place d'un hook pour la création des devices /dev/kvm et /dev/net/tun au démarrage du container:

      • dans le fichier ./lxchost/config, ajout de la ligne:

        lxc.hook.autodev = /var/lib/lxc/lxchost/hooks/autodev.sh
        
      • création du script correspondant au hook (à l'emplacement indiqué, en créant éventuellement le répertoire hooks)

        #!/bin/sh
        cd ${LXC_ROOTFS_MOUNT}/dev
        mknod kvm c 10 232
        mkdir net
        mknod net/tun c 10 200
        
    • mise en place d'une clé ssh pour se connecter

  • démarrage du container

    • en mode daemon:

      # lxc-start -n lxchost
      
    • en mode console:

      # lxc-start -F -n lxchost
      
  • configuration de l'environnement cible

    # apt-get install libvirt-bin virtinst
    
  • création de la VM (en mode console)

    # virt-install --name kvmguest --ram 512 --location http://ftp.fr.debian.org/debian/dists/jessie/main/installer-amd64/ --disk size=2 --os-variant debianwheezy --console "pty,target_type=serial" --extra-args="console=ttyS0,115200n8 serial"
    

    dans cet exemple, l'installateur est téléchargé depuis un mirroir debian; l'unité de stockage est automatiquement créée sous la forme d'un fichier qcow de 2GB; l'affichage se fait uniquement en mode texte sur la console.

La VM est créée et fonctionnelle dans un container LXC. Bien entendu, les paramètres de création de celle-ci sont libres et doivent être adaptés à votre besoin.

Comme toujours, la lecture de la page [https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html man] est très profitable pour affiner cette configuration.

/!En mode console, après l'installation, ne pas oublier pour le premier démarrage d'éditer la ligne de commande GRUB pour ajouter dans les paramètres du noyau: console=ttyS0,115200n8 serial. Sinon, aucun affichage ne sera visible (bien que la VM soit pleinement opérationnelle, ainsi qu'une connexion par SSH l'attestera).