Déploiement du Vault
Déploiement HashiCorp Vault avec Podman Rootless
Architecture
- Système : AlmaLinux (RHEL-based)
- Container Engine : Podman (rootless)
- Stockage : Raft (backend intégré HA)
- Sécurité : SELinux activé
- Reverse Proxy : Nginx avec Let's Encrypt
Déploiement - Guide Complet
1. Préparation des volumes
# Créer les volumes nommés (recommandé pour Podman rootless)
podman volume create vault_config
podman volume create vault_data
2. Créer le fichier de configuration Vault
# Monter temporairement le volume config
podman volume mount vault_config
# Créer vault.hcl
cat > $(podman volume mount vault_config)/vault.hcl << 'EOF'
disable_cache = true
disable_mlock = true
ui = true
max_lease_ttl = "2h"
default_lease_ttl = "20m"
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = true
}
storage "raft" {
path = "/vault/file"
node_id = "vault-1"
}
api_addr = "http://127.0.0.1:8200"
cluster_addr = "https://127.0.0.1:8201"
EOF
# Démonter le volume
podman volume unmount vault_config
3. Démarrer le conteneur Vault
podman run -d \
--name vault \
-p 8200:8200 \
-p 8201:8201 \
--cap-add=IPC_LOCK \
-v vault_config:/vault/config \
-v vault_data:/vault/file \
docker.io/hashicorp/vault server
4. Vérifier le démarrage
# Vérifier les logs
podman logs vault
# Vérifier le statut
podman ps
5. Initialiser Vault
# Définir l'adresse Vault
export VAULT_ADDR='http://127.0.0.1:8200'
# Initialiser avec 1 clé (configuration single-admin)
vault operator init -key-shares=1 -key-threshold=1
# ⚠️ IMPORTANT : Sauvegarder immédiatement dans un password manager :
# - Unseal Key (ex: abcd1234efgh5678...)
# - Initial Root Token (ex: s.xyz789abc123...)
6. Unsealer Vault
# À chaque démarrage du conteneur
vault operator unseal <UNSEAL_KEY>
# Vérifier le statut
vault status
7. Configuration de l'authentification AppRole
# Login avec le root token
vault login <ROOT_TOKEN>
# Activer AppRole
vault auth enable approle
# Créer la policy admin
vault policy write admin - << 'EOF'
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOF
# Créer le rôle AppRole
vault write auth/approle/role/admin \
token_policies="admin" \
token_ttl=1h \
token_max_ttl=4h
8. Récupérer les credentials AppRole
# Récupérer le RoleID (permanent)
ROLE_ID=$(vault read -field=role_id auth/approle/role/admin/role-id)
echo "RoleID: $ROLE_ID"
# Générer un SecretID (temporaire, à regénérer)
SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/admin/secret-id)
echo "SecretID: $SECRET_ID"
# Sauvegarder le RoleID
echo "$ROLE_ID" > ~/.vault-role-id
9. Login avec AppRole
# Login et récupération du token
vault write auth/approle/login \
role_id="$ROLE_ID" \
secret_id="$SECRET_ID"
# Ou directement exporter le token
export VAULT_TOKEN=$(vault write -field=token auth/approle/login \
role_id="$ROLE_ID" \
secret_id="$SECRET_ID")
10. Configuration Nginx (Reverse Proxy avec SSL)
# Créer le fichier de configuration Nginx
sudo nano /etc/nginx/conf.d/vault.conf
upstream vault_backend {
server 127.0.0.1:8200;
}
server {
listen 80;
server_name vault.example.com;sanjyasz.pro;
# Redirection HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name vault.example.com;sanjyasz.pro;
# Certificats SSL Let's Encrypt
ssl_certificate /etc/letsencrypt/live/example.com/sanjyasz.pro/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/sanjyasz.pro/privkey.pem;
# Configuration SSL moderne
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Headers de sécurité
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
# Proxy vers Vault
location / {
proxy_pass http://vault_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support (pour l'UI)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Tester la configuration Nginx
sudo nginx -t
# Recharger Nginx
sudo systemctl reload nginx
11. Expansion du certificat Let's Encrypt
# Ajouter le sous-domaine vault au certificat existant
sudo certbot certonly --nginx \
-d example.comsanjyasz.pro \
-d www.example.comsanjyasz.pro \
-d vault.example.comsanjyasz.pro \
--expand
# Vérifier le renouvellement automatique
sudo certbot renew --dry-run
12. Gestion SELinux pour les certificats
# Restaurer le contexte SELinux correct
sudo restorecon -Rv /etc/letsencrypt
# Rendre la configuration permanente
sudo semanage fcontext -a -t httpd_sys_content_t "/etc/letsencrypt(/.*)?"
sudo restorecon -Rv /etc/letsencrypt
13. Service Systemd (optionnel - pour auto-start)
# Générer le fichier systemd
podman generate systemd --new --name vault > ~/.config/systemd/user/vault.service
# Activer au démarrage
systemctl --user enable vault.service
systemctl --user start vault.service
# Activer le linger (conteneur démarre même si user pas connecté)
sudo loginctl enable-linger $USER
14. Script de login rapide
# Créer un script de connexion
cat > ~/vault-login.sh << 'EOF'
#!/bin/bash
export VAULT_ADDR='http://127.0.0.1:8200'
ROLE_ID=$(cat ~/.vault-role-id)
SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/admin/secret-id)
export VAULT_TOKEN=$(vault write -field=token auth/approle/login \
role_id="$ROLE_ID" \
secret_id="$SECRET_ID")
echo "✅ Logged in to Vault"
vault token lookup
EOF
chmod +x ~/vault-login.sh
# Utilisation
source ~/vault-login.sh
Problèmes Rencontrés et Solutions
1. Ordre des arguments dans podman run
Problème : Les options -v placées après l'image étaient interprétées comme arguments du conteneur.
Solution : Placer tous les arguments AVANT le nom de l'image.
# ❌ Incorrect
podman run -d --name vault image -v /path:/path
# ✅ Correct
podman run -d --name vault -v /path:/path image
2. Permissions SELinux avec bind mounts
Problème :
Error: lsetxattr(label=system_u:object_r:container_file_t:s0) /var/lib/vault: operation not permitted
Cause : En Podman rootless, impossible de relabeler des dossiers dans /var/lib/ (appartiennent à root).
Solutions :
Option A - Volumes nommés (recommandé) :
podman volume create vault_data
podman run -v vault_data:/vault/file ...
# SELinux géré automatiquement
Option B - Bind mount avec relabeling manuel :
sudo chown -R $(id -u):$(id -g) /var/lib/vault
sudo chcon -R -t container_file_t /var/lib/vault
sudo semanage fcontext -a -t container_file_t "/var/lib/vault(/.*)?"
podman run -v /var/lib/vault:/vault/file ... # Sans :Z
3. User namespace et UID mapping
Problème : Fichiers créés avec des UIDs étranges (524287, 525287).
Cause : Podman rootless mappe les UIDs du conteneur vers un range d'UIDs sur l'hôte.
Explication :
# Vérifier le mapping
cat /etc/subuid | grep username
# username:524288:65536
# UID conteneur 999 → UID hôte 524288 + 999 = 525287
Solution : Normal et voulu pour l'isolation. Utiliser podman unshare si besoin d'interagir :
podman unshare ls -lah /path/to/volume
4. Vault nécessite cluster_addr avec Raft
Problème :
Error: Cluster address must be set when using raft storage
Solution : Configuration Raft complète obligatoire :
storage "raft" {
path = "/vault/file"
node_id = "vault-1"
}
api_addr = "http://127.0.0.1:8200"
cluster_addr = "https://127.0.0.1:8201" # Port 8201 pour le cluster
Note :
Port 8200 = API/UIPort 8201 = Communication inter-nœuds (même en single-node)
5. HTTPS vs HTTP - Erreur de connexion
Problème :
Error: http: server gave HTTP response to HTTPS client
Cause : VAULT_ADDR par défaut en HTTPS mais Vault configuré en HTTP (tls_disable = true).
Solution :
export VAULT_ADDR='http://127.0.0.1:8200'
# Ou ajouter au .bashrc
echo 'export VAULT_ADDR="http://127.0.0.1:8200"' >> ~/.bashrc
6. Permission denied - Authentification manquante
Problème :
Error reading auth/approle/role/admin/role-id: permission denied
Cause : Tentative de lecture sans être authentifié.
Solution :
# Se connecter d'abord
vault login <ROOT_TOKEN>
# Puis exécuter la commande
vault read auth/approle/role/admin/role-id
7. Confusion entre auth method path et role path
Problème : Création d'une auth method sur auth/admin/ au lieu d'utiliser auth/approle/.
Solution :
# ❌ Incorrect - Création d'une nouvelle auth method
vault auth enable -path=admin approle
# ✅ Correct - Utiliser l'auth method standard
vault auth enable approle
vault write auth/approle/role/admin ...
Path correct : auth/approle/role/<role_name>
8. UI Web - Scroll bloqué
Problème : Impossible de scroller dans l'interface web Vault.
Solutions :
// DevTools Console (F12)
document.body.style.overflow = 'auto';
Ou :
9. AppRole non visible dans l'UI de login
Problème : Seule l'option "Token" apparaît dans l'UI de connexion.
Solution : Activer la visibilité de l'auth method :
vault write sys/auth/approle/tune listing_visibility="unauth"
Alternative : Utiliser le token généré par AppRole via CLI :
TOKEN=$(vault write -field=token auth/approle/login role_id="..." secret_id="...")
# Login UI avec ce token
10. Certificats Let's Encrypt et SELinux
Problème :
cannot load certificate: Permission denied
Cause : Après renouvellement Certbot, les nouveaux fichiers ont le mauvais contexte SELinux.
Solution :
# Quick fix
sudo restorecon -Rv /etc/letsencrypt
# Permanent fix
sudo semanage fcontext -a -t httpd_sys_content_t "/etc/letsencrypt(/.*)?"
sudo restorecon -Rv /etc/letsencrypt
# Tester Nginx
sudo nginx -t
Commandes de Maintenance
Unseal après redémarrage
export VAULT_ADDR='http://127.0.0.1:8200'
vault operator unseal <UNSEAL_KEY>
Vérifier le statut
vault status
podman logs vault
podman ps -a
Backup des données Vault
# Backup du volume
podman volume export vault_data > vault_data_backup.tar
# Ou copie directe
cp -r ~/.local/share/containers/storage/volumes/vault_data/_data /backup/vault/
Rotation du SecretID AppRole
# Générer un nouveau SecretID
vault write -f -field=secret_id auth/approle/role/admin/secret-id
Gestion des logs
# Voir les logs
podman logs vault
# Suivre les logs en temps réel
podman logs -f vault
# Dernières 100 lignes
podman logs --tail 100 vault
Concepts Clés
Raft Storage
Backend de stockage HA intégréAlgorithme de consensus distribuéPermet plusieurs nœuds Vault synchronisésPas besoin de base externe (Consul, MySQL, etc.)Recommandé par HashiCorp
AppRole Authentication
Méthode d'auth pour machines/applicationsRoleID : identifiant permanent du rôleSecretID : credential temporaire/éphémèreIdéal pour automation, CI/CD, scriptsPlus secure que userpass pour l'automation
Unseal/Seal
Vault démarre "sealed" (verrouillé)Données chiffrées, inaccessiblesUnseal = déverrouiller avec la cléNécessaire après chaque redémarrageProtège contre le vol de disque
Podman Rootless
Conteneurs sans privilèges rootUser namespaces pour isolationMeilleure sécurité que Docker classiqueCompatible avec SELinux