1. Vue d’ensemble

Les secrets (credentials, tokens, passwords) du projet sever-admin sont centralisés, chiffrés et générés dynamiquement via Ansible Vault. Cette approche garantit une single source of truth : les secrets ne sont jamais en clair dans le repository.

1.1. Architecture : Single Source of Truth

┌─────────────────────────────────────────┐
│  Ansible Vault (vault.yml)              │
│  ├─ vault_dev_*   (développement)       │
│  └─ vault_prod_*  (production)          │
└─────────────────────────────────────────┘
         ↓ [Détection environnement]
┌─────────────────────────────────────────┐
│  Ansible Templates (.env.*.j2)          │
│  Injecte dynamiquement dev ou prod      │
└─────────────────────────────────────────┘
         ↓ [Génération au runtime]
┌─────────────────────────────────────────┐
│  .env (généré)                          │
│  ⚠️  Jamais commité                     │
│  ⚠️  Utilisé par docker-compose         │
└─────────────────────────────────────────┘
         ↓
    Containers Docker
    (variables d'environnement)

1.2. Avantages

  • Centralisé : Un seul fichier source pour tous les secrets

  • Chiffré : vault.yml est chiffré avec Ansible Vault

  • Dynamique : Pas de .env statique commité

  • Env-aware : Distinction automatique dev/prod

  • Auditabilité : Historique Git complet (chiffré)

  • Pas de désynchronisation : Les variables Vault sont toujours injectées

2. Structure du Vault

Le fichier ansible/inventory/group_vars/all/vault.yml est organisé par environnement.

Chaque secret existe en deux variantes : - vault_dev_* pour le développement local (ENV=local) - vault_prod_* pour la production (ENV=remote)

2.1. Exemple de Structure

# ─────── DEVELOPMENT (local, ENV=local) ───────

# Clarajob DDL (PostgreSQL)
vault_dev_clarajob_ddl_db_name: "clarajobdb"
vault_dev_clarajob_ddl_db_user: "dev"
vault_dev_clarajob_ddl_db_pass: "dev"

# Clarajob MongoDB
vault_dev_clarajob_mongo_db_name: "clarajob_mongodb"
vault_dev_clarajob_mongo_db_user: "dev"
vault_dev_clarajob_mongo_db_pass: "dev"

# Marketisia DDL (PostgreSQL PredictX)
vault_dev_marketisia_ddl_db_name: "marketisiadb"
vault_dev_marketisia_ddl_db_user: "dev"
vault_dev_marketisia_ddl_db_pass: "dev"

# Auth Server DB (PostgreSQL Keycloak)
vault_dev_auth_server_db_name: "auth_server_db"
vault_dev_auth_server_db_user: "dev"
vault_dev_auth_server_db_pass: "dev"

# Keycloak Admin
vault_dev_keycloak_admin: "clarajobcontact@gmail.com"
vault_dev_keycloak_admin_password: "admin_pass"

# GitLab Registry
vault_dev_gitlab_registry_token: "gldt-1SeGhN7-WQ4c3oyerAjW"

# ─────── PRODUCTION (remote, ENV=remote) ───────

# Clarajob DDL (PostgreSQL)
vault_prod_clarajob_ddl_db_name: "clarajobdb"
vault_prod_clarajob_ddl_db_user: "clarajob_admin"
vault_prod_clarajob_ddl_db_pass: "PROD_PASSWORD_SECURE"

# Clarajob MongoDB
vault_prod_clarajob_mongo_db_name: "clarajob_mongodb"
vault_prod_clarajob_mongo_db_user: "clarajob_admin"
vault_prod_clarajob_mongo_db_pass: "PROD_PASSWORD_SECURE"

# Marketisia DDL (PostgreSQL PredictX)
vault_prod_marketisia_ddl_db_name: "marketisiadb"
vault_prod_marketisia_ddl_db_user: "marketisia_admin"
vault_prod_marketisia_ddl_db_pass: "PROD_PASSWORD_SECURE"

# Auth Server DB (PostgreSQL Keycloak)
vault_prod_auth_server_db_name: "auth_server_db"
vault_prod_auth_server_db_user: "auth_server_db_admin"
vault_prod_auth_server_db_pass: "zfN2z[j@X%-"

# Keycloak Admin
vault_prod_keycloak_admin: "clarajobcontact@gmail.com"
vault_prod_keycloak_admin_password: "PROD_KEYCLOAK_PASSWORD"

# GitLab Registry
vault_prod_gitlab_registry_token: "gldt-1SeGhN7-WQ4c3oyerAjW"

3. Comment Ça Marche

3.1. Lors d’un Déploiement

Exemple : make deploy APP=auth_server_db

1. Ansible détecte l'environnement
   └─ ENV=remote (production) ou ENV=local (développement)

2. Pre-deploy task génère le .env
   ├─ Si production  → injecte vault_prod_* dans .env
   └─ Si local       → injecte vault_dev_* dans .env

3. Docker Compose lit le .env généré
   └─ Les containers reçoivent les bonnes variables d'env

4. Le .env est généré au runtime, jamais commité
   └─ Chaque déploiement = nouveau .env généré depuis Vault

3.2. Exemple Concret

Production (serveur distant)

$ make deploy APP=auth_server_db
# → Détecte ENV=remote (production)
# → Injecte vault_prod_auth_server_db_pass = "zfN2z[j@X%-"
# → Génère .env avec AUTH_SERVER_DB_PASSWORD=zfN2z[j@X%-
# → Docker démarre avec les vrais credentials
# → .env est supprimé ou non commité

Développement (machine locale)

$ ENV=local make deploy APP=auth_server_db
# → Détecte ENV=local (développement)
# → Injecte vault_dev_auth_server_db_pass = "dev"
# → Génère .env avec AUTH_SERVER_DB_PASSWORD=dev
# → Docker démarre avec credentials dev

4. Gestion des Secrets

4.1. Mot de Passe Vault

Le mot de passe qui chiffre vault.yml est stocké en dehors du repo :

~/.vault_sever_admin
chmod 600 ~/.vault_sever_admin

Ce fichier n’est jamais commité. Il est utilisé par Ansible pour déchiffrer vault.yml à la volée.

4.2. Voir les Secrets (Déchiffrement Temporaire)

ansible-vault view ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

4.3. Modifier les Secrets

Méthode 1 : Déchiffrer → Éditer → Rechiffrer (CLI)

# Déchiffrer
ansible-vault decrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

# Éditer avec votre éditeur préféré
vim ansible/inventory/group_vars/all/vault.yml

# Rechiffrer
ansible-vault encrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

Méthode 2 : Ansible Vault Editor (interactif)

# Note: Ne fonctionne que si ~/.vault_sever_admin est accessible
# Cette méthode n'est pas recommandée en CI/CD
# ansible-vault edit ansible/inventory/group_vars/all/vault.yml \
#   --vault-password-file ~/.vault_sever_admin

4.4. Changer le Mot de Passe Vault

ansible-vault rekey ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin
# Vous serez demandé pour le nouveau mot de passe deux fois

5. Cas d’Usage : Ajouter un Nouveau Secret

Supposons que tu veux ajouter un credential pour une nouvelle base de données Redis.

5.1. Étape 1 : Ajouter au Vault

ansible-vault decrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

Ajouter dans le fichier :

# Redis - Développement
vault_dev_redis_host: "redis"
vault_dev_redis_port: "6379"
vault_dev_redis_password: ""

# Redis - Production
vault_prod_redis_host: "redis.internal"
vault_prod_redis_port: "6379"
vault_prod_redis_password: "PROD_REDIS_PASSWORD"

Puis rechiffrer :

ansible-vault encrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

5.2. Étape 2 : Utiliser dans les Templates Ansible

Ajouter dans ansible/templates/.env.databases.j2 :

# Redis
REDIS_HOST={{ vault_redis_host }}
REDIS_PORT={{ vault_redis_port }}
REDIS_PASSWORD={{ vault_redis_password }}

5.3. Étape 3 : Mettre à Jour le Playbook Deploy

Dans ansible/playbooks/deploy.yml, ajouter une pré-task (ou augmenter la pré-task existante) :

- name: "Générer .env.databases depuis les secrets du vault"
  template:
    src: "{{ playbook_dir }}/../templates/.env.databases.j2"
    dest: "{{ mon_projet_dir }}/.env"
    owner: admin
    group: admin
    mode: '0600'
  vars:
    vault_redis_host: "{{ vault_prod_redis_host if ansible_environment_type == 'production' else vault_dev_redis_host }}"
    vault_redis_port: "{{ vault_prod_redis_port if ansible_environment_type == 'production' else vault_dev_redis_port }}"
    vault_redis_password: "{{ vault_prod_redis_password if ansible_environment_type == 'production' else vault_dev_redis_password }}"
  no_log: true

5.4. Étape 4 : Utiliser dans docker-compose.yml

services:
  redis:
    image: redis:7-alpine
    ports:
      - "${REDIS_PORT}:6379"
    environment:
      REDIS_PASSWORD: ${REDIS_PASSWORD}
    command: redis-server --requirepass ${REDIS_PASSWORD}

5.5. Étape 5 : Tester

# Développement
ENV=local make deploy APP=mon-app
# → REDIS_PASSWORD='' (vide)

# Production
make deploy APP=mon-app
# → REDIS_PASSWORD=PROD_REDIS_PASSWORD

6. Secrets Externalisés (Repo security/env)

En plus du Vault chiffré, les secrets en clair sont stockés dans un repo séparé pour faciliter la collaboration :

/media/multi2/projects/app/security/env/
├── local/server-admin/
│   ├── .env.auth-server.local
│   ├── .env.databases.local
│   └── .env.infra-and-ansible.local
└── prod/server-admin/
    ├── .env.auth-server.prod
    ├── .env.databases.prod
    └── .env.infra-and-ansible.prod

Purpose : Ce repo security est séparé et sécurisé, il ne contient que les secrets (pas le code applicatif).

Note

Le repo security/env n’est jamais utilisé directement par les playbooks Ansible. Les .env dans security/env servent de référence documentaire et de backup des secrets. La source de vérité reste le Vault chiffré (vault.yml).

7. Règles de Sécurité

Important
  1. Jamais commiter .env

    • .env est dans .gitignore — généré au runtime

    • Chaque déploiement génère un nouveau .env

  2. Jamais commiter vault.yml en clair

    • Toujours chiffrer : ansible-vault encrypt

    • Si clair, changer IMMÉDIATEMENT tous les passwords

  3. Protéger ~/.vault_sever_admin

    • chmod 600 — seul l’utilisateur peut lire

    • Ne pas copier sur des machines non sécurisées

  4. Utiliser des variantes dev/prod

    • Toujours créer vault_dev_* ET vault_prod_*

    • Évite les accidents (dev password en prod)

  5. Documenter les nouveaux secrets

    • Ajouter un commentaire dans vault.yml (ex: "# Docker Registry deploy token")

    • Facilite la maintenance

  6. Rotationner les passwords compromis

    • Changer sur le serveur

    • Mettre à jour le Vault

    • Redeployer

8. Audit Trail & Historique

Le Vault est versionné dans Git (chiffré) — tu peux tracer les modifications :

# Voir l'historique des modifications du vault
git log ansible/inventory/group_vars/all/vault.yml

# Voir ce qui a changé (reste chiffré)
git diff HEAD~1 ansible/inventory/group_vars/all/vault.yml

# Identifier qui a modifié quoi
git log -p --author=ulrich ansible/inventory/group_vars/all/vault.yml

Même chiffré, tu peux identifier : - Qui a changé - Quand - Le message du commit

8.1. Rotation de Password Exemple

Scénario : auth_server_db_pass est compromis

# 1. Changer le password sur le serveur
ssh -i ~/.ssh/serverAdminSSHKeypair.pem admin@18.158.207.98 \
  "docker exec auth_server_db psql -U admin -d auth_server_db \
   -c \"ALTER ROLE auth_server_db_admin WITH PASSWORD 'new_secure_password';\""

# 2. Mettre à jour le vault
ansible-vault decrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

# Éditer:
#   vault_prod_auth_server_db_pass: "new_secure_password"

ansible-vault encrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

# 3. Commiter
git add ansible/inventory/group_vars/all/vault.yml
git commit -m "security: rotate auth_server_db_admin password (CVE-2026-xxxxx)"

# 4. Déployer
make deploy APP=auth_server_db

9. Troubleshooting

9.1. "Decryption failed"

# Vérifier le password file
cat ~/.vault_sever_admin

# Doit contenir le password exact, sans espace ni retour à la ligne
# Sinon, réinitialiser :
echo "CORRECT_PASSWORD" > ~/.vault_sever_admin
chmod 600 ~/.vault_sever_admin

9.2. "vault_prod_* variables not found"

# Vérifier que vault.yml est chiffré
file ansible/inventory/group_vars/all/vault.yml
# Doit afficher: "ASCII text" si bien chiffré

# Si c'est du texte brut, rechiffrer :
ansible-vault encrypt ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin

9.3. "Template generation failed"

# Vérifier que les templates existent
ls -la ansible/templates/.env.*.j2

# Vérifier que le playbook utilise les bonnes variables
ansible-vault view ansible/inventory/group_vars/all/vault.yml \
  --vault-password-file ~/.vault_sever_admin | grep -E "vault_(dev|prod)_"

10. Templates Ansible Fournis

Le projet inclut 3 templates par défaut :

Template Rôle Variables

.env.auth-server.j2

Auth Server + Keycloak

vault_*auth_server_db*, vault_*keycloak*

.env.databases.j2

Toutes les BDs

vault_*clarajob*, vault_*marketisia*, vault_*auth_server*

.env.infrastructure.j2

Infrastructure

vault_*_gitlab_registry_token, Semaphore, Rundeck

Chaque template injecte dynamiquement les secrets via les variables vault_dev_* ou vault_prod_* selon l’environnement.

11. Intégration CI/CD

11.1. Jenkins

Le credential Jenkins VAULT_PASSWORD_FILE (type: Secret file) contient le mot de passe vault.

// Dans le Jenkinsfile
withCredentials([file(credentialsId: 'VAULT_PASSWORD_FILE', variable: 'VAULT_PASS')]) {
    sh '''
        cp $VAULT_PASS ~/.vault_sever_admin
        chmod 600 ~/.vault_sever_admin
        make deploy APP=clarajob-sa
    '''
}

11.2. Semaphore / Rundeck

Ces outils n’ont besoin que de l’adresse du Vault password file — Ansible gère le reste.

12. Bonnes Pratiques Résumées

Pratique Détail Fréquence

Rotation de secrets

Changer les passwords tous les 90 jours

Trimestriel

Audit des accès

Qui a consulté/modifié les secrets

Après chaque changement

Backup du vault password

Sauvegarder ~/.vault_sever_admin securely

Une fois, jamais modifier

Documentation

Ajouter un commentaire pour chaque nouveau secret

À chaque ajout

Test dev/prod

Tester le déploiement en dev avant prod

À chaque changement de secret

13. Ressources Supplémentaires


Dernière mise à jour : 2026-08-13 Auteur : DevOps Team