Attention, cet article a plus d'une année d'ancienneté. Il est possible que les informations présentées ne soient plus à jour, spécialement dans le cadre d'un article technique.
Bonjour à tous,
Aujourd’hui, on va faire le tour de ma manière de gérer les mises à jour de mon infra perso. Elle a évolué, j’ai pas mal de choses plus ou moins compliquées à tenir à jour, du Debian, du BitWarden, du Windows, du OpnSense (FreeBSD) en plus de nginx compilés à la main et de mes certificats Let’s Encrypt. Il fallait donc que je centralise tout ça.
En plus de la centralisation, je voulais automatiser les mises à jour afin de plus m’occuper de mon bordel.
Tout ce qui sera mis ici dans l’article est disponible sur GitHub : https://github.com/stylersnico/own-ansible-update-tools
Cela vous évitera les erreurs d’indentation dans les copier/coller et vous pourrez mieux vous situer les fichiers de configuration.
Description de l’infra
- 2 ESX avec 15 vms en tout
- Un Vps hetzner
- Du windows, avec entre autres mon AD et mon Exchange
- Toujours du Windows pour Veeam et mes contrôleurs Unifi Wifi et Video
- Du bitwarden sur VM
- Nextcloud, un reverse proxy
- Un OpnSense virtualisé pour le firewall
- Et d’autres choses …
Les hôtes et les variables de connexion
Dans mon fichier d’hôte, j’ai bien séparé les hôtes par catégorie.
- [ansible] : L’hôte ansible
- [apt] : Mes serveurs Debian
- [ngx-custom] : Mes serveurs ou je build NGINX à la pate
- [letsencrypt] : Les serveurs NGINX ou il y’a des certificats Let’s Encrypt que je renouvelle
- [bitwarden] : Le serveur Bitwarden, pour mettre à jour les images docker
- [omv] : Le serveur OpenMediaVault ou j’ai mon Transmission que je coupe avant les mises à jour
- [windows-no-ad] : Les serveurs Windows sans Active Directory
- [windows-ad] : Les serveurs Windows dans l’Active Directory
- [freebsd] : Le firewall OpnSense
Voici le détail :
[ansible] localhost ansible_connection=local [apt] localhost ansible_connection=local omv.nsh.ovh:22 ansible_connection=ssh ansible_user=root webhost.nicolas-simond.com:22 ansible_connection=ssh ansible_user=root 192.168.1.7:22 ansible_connection=ssh ansible_user=nsw-ansible 192.168.1.11:22 ansible_connection=ssh ansible_user=nsw-ansible 192.168.1.12:22 ansible_connection=ssh ansible_user=nsw-ansible cloud.yaute.ninja:22 ansible_connection=ssh ansible_user=root 192.168.1.38 ansible_connection=ssh ansible_user=root 192.168.1.39 ansible_connection=ssh ansible_user=root 192.168.1.40 ansible_connection=ssh ansible_user=root [ngx-custom] 192.168.1.7:22 ansible_connection=ssh ansible_user=nsw-ansible webhost.nicolas-simond.com:22 ansible_connection=ssh ansible_user=root [letsencrypt] 192.168.1.7:22 ansible_connection=ssh ansible_user=nsw-ansible webhost.nicolas-simond.com:22 ansible_connection=ssh ansible_user=root [bitwarden] 192.168.1.38 ansible_connection=ssh ansible_user=root [omv] omv.nsh.ovh:22 ansible_connection=ssh ansible_user=root [windows-no-ad] veeambackup.mail.ch Ubiquiti-C.mail.ch [windows-ad] ex-dc02.mail.ch ex-ms02.mail.ch [freebsd] 192.168.1.254 ansible_connection=ssh ansible_user=root [freebsd:vars] ansible_python_interpreter="/usr/local/bin/python2.7"
Dans le détail, pour les Windows je suis obligé de faire deux fichiers de configuration séparés dans le dossier « group_vars »
Pour le FreeBSD j’indique directement le chemin du python à la fin.
Dans le fichier « /etc/ansible/group_vars/windows-no-ad.yml » je fait une connexion basique via WinRm avec l’administrateur local
ansible_become: false ansible_user: Administrateur ansible_password: XXX ansible_port: 5986 ansible_connection: winrm # The following is necessary for Python 2.7.9+ when using default WinRM self-signed certificates: ansible_winrm_server_cert_validation: ignore
Dans le fichier « /etc/ansible/group_vars/windows-ad.yml » il y’a une subtilité. N’ayant pas réussi à faire parler du Debian 9 et du Serveur 2019 en kerberos je passe par une authentification NTLM classique.
ansible_become: false ansible_user: Administrateur@mail.ch ansible_password: XXX ansible_port: 5986 ansible_connection: winrm ansible_winrm_transport: ntlm # The following is necessary for Python 2.7.9+ when using default WinRM self-signed certificates: ansible_winrm_server_cert_validation: ignore
Vous noterez que je laisse les mots de passe en clair dans mes fichiers de config et que je ne les chiffre pas. C’est en local chez moi et je veux y automatiser par la suite pour que tout ce mette à jour tout seul par la suite.
Vous allez sans doute préférer chiffre tout ça avec les vault ansible de votre côté.
J’en avais parlé dans mon article sur la gestion des Windows avec Ansible : https://www.abyssproject.net/2016/09/gerer-serveurs-windows-ansible/
Principes de découpage
Au début de chaque playbook, j’efface le fichier des logs et je coupe le démon transmission avant de lancer une activité internet avec les lignes suivantes :
- hosts: ansible become: yes become_method: sudo tasks: - name: Truncate logs shell: echo "" > /etc/ansible/ansible.log - hosts: omv become: yes become_method: sudo tasks: - name: Stop transmission on OMV systemd: name: transmission-daemon state: stopped
A la fin de chaque playbook je relance transmission et m’envoie le log Ansible par email pour savoir ce qu’il s’est passé, car, je vous rappelle que je ne lance pas les playbook à la main :
- hosts: omv become: yes become_method: sudo tasks: - name: Start transmission on OMV systemd: name: transmission-daemon state: started - hosts: ansible become: yes become_method: sudo tasks: - name: Sending ansible.log by email mail: host: outbound-eu1.ppe-hosted.com port: 25 from: ansible@mail.ch to: me@mail.ch subject: Linux Servers update log body: "{{ lookup('file', '/etc/ansible/ansible.log') }}"
Mise à jour des serveurs Debian, de NGINX et de BitWarden
On lance simplement les mises à jour sur les serveurs et on vérifie si tout redémarre bien en attendant en async que Ansible arrive à se reconnecter pour éviter des erreurs dans le playbook.
J’utilise Kexec pour un redémarrage plus rapide pour les serveurs où c’est installé.
- hosts: apt become: yes become_method: sudo tasks: - name: updates a server apt: update_cache=yes - name: upgrade a server apt: upgrade=dist dpkg_options='force-confold,force-confdef' - name: Check if a reboot is required register: reboot stat: path=/var/run/reboot-required get_md5=no - name: Check if kexec is used register: kexec stat: path=/usr/bin/kexec-reboot get_md5=no - name: Reboot the services shell: needrestart -ra -l when: reboot.stat.exists == false - name: Reboot the server using reboot command: /sbin/reboot async: 1 poll: 0 when: reboot.stat.exists == true and kexec.stat.exists == false - name: Wait for systems to become reachable wait_for_connection: - name: Reboot the server using kexec shell: kexec-reboot -lr async: 1 poll: 0 when: reboot.stat.exists == true and kexec.stat.exists == true - name: Wait for systems to become reachable wait_for_connection:
Pour les serveurs Nginx, je lance simplement mon script de build depuis le serveur Ansible et attends le retour du build :
Le script est disponible sur GitHub : https://github.com/stylersnico/nginx-openssl-chacha-naxsi/blob/master/build.sh
Vous remarquerez que je crée une notification a la fin du script pour que Ansible se charge de redémarrer Nginx en cas de réussite du script.
- hosts: ngx-custom become: yes become_method: sudo tasks: - name: Build latest Nginx Release script: /etc/ansible/ressources/scripts/build-ngx.sh notify: - restart nginx handlers: - name: restart nginx service: name=nginx state=restarted
Pour BitWarden, j’utilise le script fourni par les créateurs et passe des commandes shell directement à l’hôte à travers Ansible :
- hosts: bitwarden become: yes become_method: sudo tasks: - name: Self update on bitwarden shell: /root/bitwarden.sh updateself - name: Update bitwarden core and web shell: /root/bitwarden.sh update
Mise à jour des serveurs Windows
Ici c’est nettement plus simple que pour les Debian.
J’installe simplement les mises à jour critiques et les mises à jour de sécurité et attends le redémarrage des serveurs :
- hosts: windows-no-ad tasks: - name: install all critical and security updates win_updates: category_names: - CriticalUpdates - SecurityUpdates state: installed register: update_result - name: reboot if required win_reboot: reboot_timeout_sec: 180 when: update_result.reboot_required - hosts: windows-ad tasks: - name: install all critical and security updates win_updates: category_names: - CriticalUpdates - SecurityUpdates state: installed register: update_result - name: reboot if required win_reboot: reboot_timeout_sec: 180 when: update_result.reboot_required
Mise à jour du firewall OpnSense
Ici pour OpnSense je ne passe pas par le système de mise à jour BSD mais par l’utilitaire OpnSense, je suis bien obligé.
J’invoque donc le shell local comme pour BitWarden (la connexion root de OpnSense doit se faire sur /bin/sh et non pas le choix par défaut) :
- hosts: freebsd become: yes become_method: sudo tasks: - name: Update OPNSense shell: opnsense-update
Renouvellement des certificats Let’s Encrypt
ici je ne réinvente pas la roue, j’utilise simplement mon script bash que j’utilise depuis des années.
Un exemple est disponible ici : https://github.com/stylersnico/my-webserver/blob/master/root/renew-certs.sh
On va encore une fois invoquer le shell depuis Ansible et ensuite redémarrer les services NGINX sur les serveurs :
- hosts: letsencrypt become: yes become_method: sudo tasks: - name: Update certificats shell: /root/renew-certs.sh - name: restart nginx service: name=nginx state=restarted
Concaténation
Si vous voulez tout lancer en une fois, faites donc un fichier global et importez vos playbook dedans :
nano /etc/ansible/playbook/update-all-servers.yml
- import_playbook: include/update-apt-servers.yml - import_playbook: include/update-windows-servers.yml - import_playbook: include/update-opnsense-servers.yml
Automatisation
Comme déjà expliqué, les mises à jour se font dans mon dos et ça me va bien.
Oui Ansible Tower / Semaphore gnagnagna. Si vous voulez faire simple, balancez un crontab depuis votre utilisateur ansible :
crontab -e
Personnellement je programme les mises à jour chaque jour à 7h et le renouvellement des certificats SSL chaque premier du mois comme ceci :
0 7 * * * /usr/bin/ansible-playbook /etc/ansible/playbooks/update-all-servers.yml 0 7 1 * * /usr/bin/ansible-playbook /etc/ansible/playbooks/include/letsencrypt.yml
Fin
Merci pour cet article clair…. Je précise que pour des serveurs CentOS, il faut modifier quelques lignes : Les droits sur le fichiers : chmod 600 /home/ansible/.ssh/authorized_keys Sans cela, impossible de se connecter sans mot passe. Pour supprimer le mot de passe de l’utilisateur ansible : passwd -l ansible Dans le playbook, la tâche apt doit être remplacée par celle çi : tasks: – name: upgrade all packages dnf: name: « * » state: latest Attention à bien décaler les 2 dernières lignes, sinon il y aura une erreur. Par ailleurs, j’utilise PFSense, et je souhaite utiliser sudo. J’arrive à tout faire,… Voir plus »