Aller au contenu principal

Rudder vous aide à durcir vos VM Linux

· 10 minutes de lecture
Stéphane ROBERT

logo rudder

Suite à l'introduction de la semaine passée de rudder, un outil de gestion de configuration, je vous propose cette semaine de vous montrer comment l'utiliser pour faire du hardening de VM

Introduction

Il y a quelques semaines, je vous ai expliqué comment j'utilisais openscap, un outil destiné aux administrateurs systèmes et aux personnes en charge de la sécurité, pour réaliser des audits de sécurité. L'objectif étant de renforcer la sécurité des assets. Pour cela, je me servais d'OpenScap pendant le développement de rôles Ansible pour contrôler si je respectais un certain nombre de règles de sécurité. On va reprendre le même principe, mais cette fois, ce sera rudder à la manœuvre. Vous allez voir que ce que rudder propose simplifie pas mal le travail.

Rudder n'utilise pas pour le moment la commande openscap-ssh pour lancer des audits à distance. On est donc obligé d'installer OpenScap et le framework de test de compliance sur tous les nœuds.

Pour en simplifier l'installation, je vais utiliser, mon rôle ansible-rôle-openscap qui se charge de réaliser ces installations. Je vais en profiter pour vous montrer comment utiliser rudder comme source d'inventaire dynamique Ansible.

Utilisation de rudder comme source d'inventaire dynamique ansible

Avant toute chose, je vais modifier mon vagrantfile pour utiliser une règle de nommage des nodes. Cette règle de nommage simplifié var permettre de définir l'environnement, le rôle, et un numéro d'index. Cela va permettre de simplifier la création des groupes rudder et donc ceux d'ansible.

Ma règle de nommage (simplifiée) :

  • Première lettre pour l'environnement : P pour prod, D pour développement, R pour cette recette, Q pour qualification, ...
  • Deux lettres pour définir le rôle du serveur : Par exemple SW pour Serveur WEB, BD pour base de données, ou FC pour serveur de fichiers.
  • Trois autres lettres pour définir le projet utilisant la ressource : MUT pour de la mutualisation par exemple.
  • Deux lettres pour la localisation physique du serveur : LIL pour Lille, PAR pour Paris, LOC pour local.
  • Trois lettres pour le provider : LOC pour local, AZU pour Azure, GCP pour GCP
  • Deux chiffres comme index.

Ce qui donne par exemple : pswmutloc01 pour le premier serveur web de mutualisé de production.

Provisionnement des nouveaux nœuds

Si les nodes node1, node2 et node3 sont encore présents, il faut les détruire avant de modifier votre Vagrantfile !

vagrant destroy node1 node2 node3

Le nouveau Vagrantfile :

# -*- mode: ruby -*-
# vi: set ft=ruby :

#####################################################################################
# Copyright 2016 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################
ENV['VAGRANT_NO_PARALLEL'] = 'yes'

nodes = [
{
"name" => "pswmutloc01"
},
{
"name" => "pbdtotloc01"
},
{
"name" => "dswmutloc01"
}
]

Vagrant.configure("2") do |config|
config.vm.synced_folder '.', '/vagrant', disabled: true
config.hostmanager.enabled = true
config.hostmanager.manage_host = true

config.vm.define "server" do |server|
server.vm.box = "generic/ubuntu2204"
server.vm.provider :libvirt do |lv|
lv.memory = 2048
lv.cpus = 2
lv.management_network_name = 'my_network'
lv.management_network_address = '192.168.3.0/24'
end
server.vm.provision :shell, :path => "https://repository.rudder.io/tools/rudder-setup",
:args => ["setup-server", "latest"],
:env => {"ADMIN_USER" => "admin", "ADMIN_PASSWORD" => "admin"}
server.vm.hostname = "server.rudder.local"
server.vm.network :forwarded_port, guest: 443, host: 8081
end
nodes.each do |node|
config.hostmanager.manage_host = true
config.vm.define node["name"] do |machine|
machine.vm.box = "generic/ubuntu2204"
machine.vm.provision :shell, :path => "https://repository.rudder.io/tools/rudder-setup",
:args => ["setup-agent", "latest", "server.rudder.local"]
machine.vm.hostname = "#{node["name"]}.rudder.local"
machine.vm.provider "libvirt" do |lv|
lv.memory = 1024
lv.management_network_name = 'my_network'
lv.management_network_address = '192.168.3.0/24'
end
end
end
end

On peut lancer la création des nouveaux nœuds.

vagrant up

Il faudra effacer les nœuds, et accepter les nouveaux dans l'interface de rudder. N'oubliez pas aussi de remplacer dans votre fichier de config ssh, les nœuds par ceux retourner par la commande vagrant ssh-config.

Host *
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null

Host server.rudder.local
HostName 192.168.3.173
User vagrant
Port 22
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/vagrant/Projets/personal/rudder/installation-server/.vagrant/machines/server/libvirt/private_key
IdentitiesOnly yes
LogLevel FATAL

Host pswmutloc01.rudder.local
HostName 192.168.3.25
User vagrant
Port 22
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/vagrant/Projets/personal/rudder/installation-server/.vagrant/machines/pswmutloc01/libvirt/private_key
IdentitiesOnly yes
LogLevel FATAL

...

Je devrais chercher un plugin Vagrant se chargeant de cette tâche !

Création des groupes rudder

Nous allons créer des groupes, pour cela, nous allons utiliser des expressions régulières sur les noms de machines pour les répartir dans les groupes.

  • Pour les serveurs WEB : ^[a-z]sw.*$.
  • Pour les serveurs de BDD : ^[a-z]bd.*$.
  • Pour les serveurs de Production : ^p.*$.
  • Pour les serveurs de Développement : ^d.*$.

rudder group

Utilisation de rudder comme inventaire Ansible

Tout est documenté ici. Il faut récupérer deux fichiers : rudder.py et rudder.ini et modifier la configuration ansible.

Mon fichier rudder.ini :

[rudder]

# Your Rudder server API URL, typically:
# https://rudder.local/rudder/api
uri = https://localhost:8081/rudder/api/

# By default, Rudder uses a self-signed certificate. Set this to True
# to disable certificate validation.
disable_ssl_certificate_validation = True

# Your Rudder API token, created in the Web interface.
token = zoJAplBPVQYc0KbbTfq5tNnzKvONro8V

# Rudder API version to use, use "latest" for latest available
# version.
version = latest

# Property to use as group name in the output.
# Can generally be "id" or "displayName".
group_name = displayName

# Fail if there are two groups with the same name or two hosts with the
# same hostname in the output.
fail_if_name_collision = True

# We cache the results of Rudder API in a local file
cache_path = /tmp/ansible-rudder.cache

# The number of seconds a cache file is considered valid. After this many
# seconds, a new API call will be made, and the cache file will be updated.
# Set to 0 to disable cache.
cache_max_age = 500

Il faut générer un token dans l'interface avec juste les droits de lecture. Pour cela il faut se rendre dans Administration/API Accounts :

rudder group

Pour le fichier ansible.cfg, il faut juste définir à script où l'ajouter à la liste existante :

[inventory]
enable_plugins = host_list, script, auto, yaml, ini, toml

Pour vérifier que cela fonctionne, nous allons utiliser la commande suivante :

ansible-inventory  -i rudder.py --list
{
"All_Linux_Nodes": {
"hosts": [
"dswmutloc01.rudder.local",
"pbdtotloc01.rudder.local",
"pswmutloc01.rudder.local",
"server.rudder.local"
]
},

....

"all": {
"children": [
"All_Linux_Nodes",
"All_Linux_Nodes_managed_by_root_policy_server",
"BD",
"Dev",
"Prod",
"SW",
"Ubuntu_22_04",
"ungrouped"
]
}
}

Nous retrouvons bien tous nos groupes. Testons un module Ansible :

ansible -i rudder.py Ubuntu_22_04 -m ping

dswmutloc01.rudder.local | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
pswmutloc01.rudder.local | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
pbdtotloc01.rudder.local | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}

Pour ceux qui ont des problèmes avec la connexion au serveur Rudder, j'ai proposé une correction utilisant une librairie Ansible à la place d'httplib2 pour se connecter au serveur.

Installation d'OpenScap sur tous les serveurs

Comme dit plus haut, je vais utiliser mon rôle personnel pour installer OpenScap sur toutes les machines.

ansible-galaxy install stephrobert.openscap
- downloading rôle 'openscap', owned by stephrobert
- downloading rôle from https://github.com/stephrobert/ansible-role-openscap/archive/1.0.4.tar.gz
- extracting stephrobert.openscap to /home/vagrant/.ansible/roles/stephrobert.openscap
- stephrobert.openscap (1.0.4) was installed successfully

Mon playbook :

---
- name: Install Openscap on Client
hosts: Ubuntu_22_04
pre_tasks:
- name: Install packages
ansible.builtin.package:
name:
- libopenscap8
- python3-openscap
state: present
become: true
roles:
- role: stephrobert.openscap
vars:
- oscap_version: "1.3.6"
- install_content: true
- install_oscap: true
- scan: true

J'utilise les dernières versions des projets Openscap et ComplianceAsCode/content.

Si vous êtes attentif, vous avez certainement remarqué que j'utilise le groupe Ubuntu_22_04 comme cible. On peut lancer l'installation d'OpenScap.

On lance l'installation :

ansible-playbook -i rudder.py openscap.yml

PLAY [Install Openscap on Client] ************

TASK [Gathering Facts] ***********************
ok: [pswmutloc01.rudder.local]
ok: [dswmutloc01.rudder.local]
ok: [pbdtotloc01.rudder.local]

...

Tout est installé, passons à l'installation du plugin OpenScap sur rudder.

Installation du plugin Rudder OpenScap

Connectez-vous au serveur rudder :

vagrant ssh server
Last login: Thu Feb 16 08:44:19 2023 from 192.168.3.1
-bash: warning: setlocale: LC_ALL: cannot change locale (fr_FR.UTF-8)
vagrant@server:~$

Il faut passer root :

sudo -i
apt install python3-requests rudder-api-client
wget http://repository.rudder.io/plugins/7.2/openscap/release/rudder-plugin-openscap-7.2.4-2.1.rpkg
rudder package install-file rudder-plugin-openscap-7.2.4-2.1.rpkg

Création des directives

Nous allons définir une directive permettant de lancer le scan OpenScap sur les nœuds du groupe Ubuntu 22.04.

Création de la directive

Pour cette directive, nous allons utiliser la technique Plugin OpenScap Policies et lui définir les deux variables profile et scap_file comme dans la capture d'écran suivante. Nous allons l'ajouter aussi directement à la Rule Ubuntu 22.04 OpenScap.

rudder directive openscap

  • profile : xccdf_org.ssgproject.content_profile_cis_level2_server.
  • scap_file : /opt/openscap-content/ssg-ubuntu2204-ds.xml.

Terminer par [Create]

Lancement du scan

Par défaut les scans sont lancés de nuit. Pour les forcer, sur un des nœuds avec le compte root, lancez la commande suivante :

vagrant ssh dswmutloc01
sudo -i
rudder agent run -D schedule_simple_openscap_repaired -ui

Dans la section OpenScap de la page du noeud dswmutloc01, vous devriez voir apparaître le rapport.

rudder rapport openscap

Nous voyons que nous avons pas mal de choses à corriger. Nous allons utiliser rudder.

Durcissement d'une VM avec Rudder

Nous allons nous intéresser à la partie SSH. Dans le rapport nous voyons ceci.

rudder openscap ssh

Création de la directive SSH

Nous allons donc créer une nouvelle directive que nous allons ajouter à notre rule Ubuntu 22.04. Dans la section directives, recherchez SSH dans les techniques. Dans les paramètres, je mets :

  • Allow password authentication à No
  • Allow TCP forwarding à No
  • Allow X11 forwarding à No
  • Print motd à Yes

Je la rattache à la rule Ubuntu 22.04.

rudder openscap ssh

On relance la génération du rapport OpenScap.

rudder openscap ssh

Conclusion

En quelques clics, on a renforcé la configuration SSH de nos trois nœuds, alors qu'il y a une semaine, je ne savais pas utiliser ce produit. Rudder montre tout son potentiel dans ce domaine. En vous aidant des explications du rapport OpenScap, on peut arriver à rapidement durcir la configuration d'une VM.

Plutôt que d'opposer des outils, Utilisons les tous à bon escient, et on arrivera à configurer une infrastructure rapidement et de manière sécurisé.

On voit bien ici, que rudder peut aussi vous aider à construire un inventaire dynamique Ansible. En ajoutant des propiétées sur tous les nœuds, on peut l'enrichir encore plus.

Dans cet exemple, j'utilise vagrant pour provisionner des VM, mais on peut facilement transposer cet exemple pour provisionner des VM sur les clouds AWS, GCP, Azure, ... avec du Terraform.

Plus loin

Rudder, est donc un très bon outil de gestion de configuration et d'audit de sécurité. Lors du cfgmgmtcamp 2023, j'ai pu échanger avec les développeurs de cet outil. Dans leur roadmap, il y a des choses très intéressantes à venir.

Rudder dispose aussi de toute une série de plugins permettant de faire bien d'autres choses. Donc, je vais continuer à l'explorer.