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 tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn