Aller au contenu
Infrastructure as Code medium

Filtres Jinja2 avancés Ansible : regex_search, flatten, b64encode, password_hash

11 min de lecture

Logo Ansible

Au-delà des filtres essentiels (default, combine, selectattr, dict2items...) déjà couverts dans la sous-section Variables et facts, Ansible expose des filtres avancés pour les cas plus pointus. Cette page liste les filtres avancés que vous rencontrerez dans les templates de production : extraction par regex (regex_search, regex_findall), aplatissement de listes nested (flatten), encodages (b64encode, b64decode), hash de mot de passe (password_hash), parsing/sérialisation de YAML (from_yaml, to_nice_yaml), empreintes (hash).

C'est une page de référence : on revient ici quand on cherche un filtre précis pour un besoin spécifique.

  • regex_search et regex_findall pour extraire par regex
  • flatten pour aplatir une liste de listes
  • b64encode et b64decode pour Base64
  • password_hash('sha512') pour générer un hash compatible /etc/shadow
  • from_yaml, to_nice_yaml pour parser/sérialiser
  • hash('sha256') pour calculer une empreinte hex

regex_search('pattern') retourne la première occurrence (ou None) :

{{ 'web1.lab.example.com' | regex_search('^([a-z]+)') }} ← 'web'
{{ 'IP : 10.10.20.21' | regex_search('\\d+\\.\\d+\\.\\d+\\.\\d+') }} ← '10.10.20.21'
{{ 'rien à matcher' | regex_search('xyz') }} ← '' (chaîne vide)

regex_findall('pattern') retourne toutes les occurrences sous forme de liste :

{{ 'a-1, b-2, c-3' | regex_findall('([a-z])-(\\d)') }}
← [['a', '1'], ['b', '2'], ['c', '3']]

Pour ne capturer qu'un seul groupe :

{{ 'a-1 b-2 c-3' | regex_findall('([a-z])-\\d') }} ← ['a', 'b', 'c']

Cas pratique : extraire toutes les IPs d'un fichier de config :

{% set ips = config_text | regex_findall('\\d+\\.\\d+\\.\\d+\\.\\d+') %}
Adresses détectées : {{ ips | join(', ') }}
{{ [[1, 2], [3, [4, 5]]] | flatten }} ← [1, 2, 3, 4, 5]
{{ [[1, 2], [3, [4, 5]]] | flatten(levels=1) }} ← [1, 2, 3, [4, 5]]

Sans levels, récursif (aplatit tous les niveaux). Avec levels=1, un seul niveau.

Cas pratique : agréger les services de plusieurs groupes :

vars:
webservers_services: [nginx, php-fpm]
dbservers_services: [postgresql, redis]
caches_services: [memcached]
template_var: "{{ [webservers_services, dbservers_services, caches_services] | flatten | unique }}"
{{ 'admin:secret' | b64encode }} ← 'YWRtaW46c2VjcmV0'
{{ 'YWRtaW46c2VjcmV0' | b64decode }} ← 'admin:secret'

Cas pratique : générer un header Authorization: Basic ... :

- name: Appel API avec auth basic
ansible.builtin.uri:
url: https://api.example.com/data
headers:
Authorization: "Basic {{ (api_user + ':' + api_password) | b64encode }}"
{{ 'mySecretPass' | password_hash('sha512') }}
← '$6$xxx$xxxxxxxxxxx...' (hash crypt SHA-512)

Avec un salt explicite (idempotent) :

{{ 'mySecretPass' | password_hash('sha512', 'mysalt2024') }}

Sans salt explicite, Ansible génère un salt aléatoire à chaque appel, vous obtenez un nouveau hash à chaque run, ce qui casse l'idempotence du module user. Toujours poser un salt fixe en production :

- name: Définir le mot de passe d'un user
ansible.builtin.user:
name: alice
password: "{{ 'mySecretPass' | password_hash('sha512', 'salt-alice-2024') }}"

from_yaml parse une string YAML en objet Python :

{% set parsed = "key: value\nlist:\n - a\n - b" | from_yaml %}
{{ parsed.key }} ← 'value'
{{ parsed.list | length }} ← 2

to_nice_yaml(indent=2) sérialise un dict/liste en YAML lisible :

{{ my_dict | to_nice_yaml(indent=2) }}

Cas pratique : poser un fichier YAML à partir d'un dict Ansible :

- name: Poser un manifest Kubernetes
ansible.builtin.copy:
dest: /etc/k8s/deployment.yml
content: "{{ k8s_deployment | to_nice_yaml(indent=2) }}"
{{ 'foobar' | hash('sha256') }}
← 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'

Algos supportés : md5, sha1, sha256, sha512. Cas pratique : générer un identifiant déterministe à partir d'une string :

- name: Générer un cache key
ansible.builtin.set_fact:
cache_key: "{{ (env + '-' + version) | hash('sha256') | truncate(16, true, '') }}"

Cas pratique, combinaison de 4 filtres avancés (lab ecrire-code/filtres-jinja-avances)

Section intitulée « Cas pratique, combinaison de 4 filtres avancés (lab ecrire-code/filtres-jinja-avances) »

Voici l'exemple validé sur le lab 27-ecrire-code-filtres-jinja-avances :

vars:
fqdn: "web1.lab.example.com"
secret: "admin:secret"
nested: [[1, 2], [3, [4, 5]]]
to_hash: "foobar"
tasks:
- name: Poser le fichier de résultats
ansible.builtin.copy:
dest: /tmp/filtres-avances.txt
content: |
prefix={{ fqdn | regex_search('^([a-z]+)') }}
b64={{ secret | b64encode }}
flat={{ nested | flatten }}
sha256={{ to_hash | hash('sha256') }}

Sortie :

prefix=web
b64=YWRtaW46c2VjcmV0
flat=[1, 2, 3, 4, 5]
sha256=c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2
FiltreUsage
urlsplit('host')Décompose une URL (https://api.com/foo'api.com')
dict2items / items2dictConversion dict ↔ liste de paires
groupby('attr')Groupe une liste de dicts par valeur d'une clé
subelements('key')Itère sur des sous-éléments d'une liste de dicts
community.general.json_query('expr')JMESPath sur des structures complexes
ipaddr / ipv4 / ipv6Manipulations IP ('10.0.0.0/8' | ipaddr('host'))
random / shuffleAléatoire
truncate(N, end='...')Tronquer une string
wordcount / wordwrap(width)Compter / wrapper des mots
SymptômeCauseFix
regex_search retourne videRegex Python (re module), pas POSIXVérifier la syntaxe regex Python
password_hash change à chaque runPas de salt expliciteAjouter un salt fixe : password_hash('sha512', 'mon_salt')
flatten retourne des éléments imbriquésSans levels, c'est récursif, vérifier que c'est OKflatten(levels=1) pour 1 seul niveau
b64encode plante sur des bytesLe filtre attend une stringCaster d'abord en string
hash('md5') rejeté en mode FIPSMD5 désactivé en FIPSPasser à sha256 ou sha512
  • regex_search = première occurrence ; regex_findall = toutes les occurrences.
  • flatten aplatit récursivement par défaut, ou un seul niveau avec levels=1.
  • b64encode / b64decode pour Base64 (auth headers, transport binaire).
  • password_hash('sha512', 'salt') : toujours un salt explicite pour l'idempotence.
  • from_yaml parse une string YAML, to_nice_yaml sérialise, utile pour les manifests Kubernetes.
  • hash('sha256') = empreinte déterministe de string (cache keys, identifiants).

Cette page a un lab d'accompagnement : labs/ecrire-code/filtres-jinja-avances/ dans stephrobert/ansible-training. Il contient un README.md guidé, et un challenge final auto-évalué : combiner regex_search, b64encode, flatten et hash('sha256') dans un seul fichier marqueur posé sur db1.lab.

Fenêtre de terminal
cd ~/Projets/ansible-training/labs/ecrire-code/filtres-jinja-avances/
cat README.md
pytest -v challenge/tests/

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn