Gérer vos secrets avec Vault

Linux Pratique n° 100 | mars 2017 | Denis Mortreux
Creative Commons
  • Actuellement 0 sur 5 étoiles
0
Merci d'avoir participé !
Vous avez déjà noté cette page, vous ne pouvez la noter qu'une fois !
Votre note a été changée, merci de votre participation !
De plus en plus menacée, la sécurité informatique est devenue un enjeu majeur pour les entreprises désireuses de consolider leurs anciennes architectures et moderniser leurs nouvelles. Des méthodes et des outils existent pour renforcer la sécurité des données : Vault apporte une réponse technique pour le stockage, et l’accès à vos secrets. Découvrez comment l’installer et l’exploiter !

Outil utilisé : Vault/hashicorp v0.6.1

Site du projet : https://www.vaultproject.io/

Note

Qu’est-ce que Vault?

Vault permet de stocker des secrets de manière sécurisée, tels que vos mots de passe, vos clés privées, vos identifiants de connexion... Il permet d’en contrôler l’accès, mais aussi de renforcer l’authentification à des ressources (génération de mots de base d’accès tournant pour vos bases de données, ssh avec OTP...)
C’est un produit sous licence publique Mozilla écrit en Go qui offre ses services via un interfaçage RESTs. Mais Vault est-il sécurisé ? La gestion de la mémoire en Go et la libre consultation du code source sont des points positifs d’autant plus qu’il a été audité par le groupe iSEC/NCC (auditeur de TrueCrypt et OpenSSL)[ISEC]

1. Installation

L’objectif est de renforcer l’usage des secrets dans une architecture trois tiers existante (projetA), composée de trois machines : un apache avec SSL, une application et une base de données MySQL.

Actuellement, il n’existe aucun paquet officiel Vault. Vous pouvez donc faire votre propre paquet ou l’installer manuellement avec cette procédure.

1.1 Préparer le système à recevoir Vault

1. Créez un utilisateur « vault » dédié. Téléchargez et installez le binaire pour votre plateforme et créez les répertoires pour la configuration et les données.

% adduser --no-create-home --disabled-login vault

% wget -O - https://releases.hashicorp.com/vault/0.6.1/vault_0.6.1_linux_amd64.zip | funzip > /usr/bin/vault && chmod +x /usr/bin/vault

% mkdir /etc/vault; mkdir /var/lib/vault ; chown vault /var/lib/vault ; chmod 700 /var/lib/vault

2. Ajoutez au binaire la capacité de verrouiller une zone mémoire pour éviter que le système vide des pages mémoire dans la swap et expose vos secrets.

% setcap cap_ipc_lock=+ep /usr/bin/vault

3. Facilitez la gestion de votre service avec systemd.

# /lib/systemd/system/vault.service
[Unit]

Description=Vault daemon

After=network.target

[Service]

ExecStart=/usr/bin/vault server -config=/etc/vault/vault.conf

ExecStop=

User=vault

Group=vault

[Install]

WantedBy=multi-user.target

Avant de démarrer Vault, il faut créer les certificats serveurs pour bénéficier du TLS.

1.2 Créer votre infrastructure de certificats

Si vous ne pouvez pas acheter un certificat signé par une autorité de certification(AC) connue, il faudra suivre cette procédure.

Créons une AC qui permettra de signer notre certificat serveur et de la distribuer aux clients. Pour faciliter l’administration en local, l’ajout de l’extension (subjectAltName) avec l’IP 127.0.0.1 sera pratique.

1. Ajoutez à votre configuration openssl une extension (localisation variant suivant les distributions, sous Debian /etc/ssl/openssl.cnf) :

[SANVAULT]

subjectAltName=IP:127.0.0.1

2. Lancez la création de l’AC et du certificat serveur. Choisissez un mot de passe robuste pour votre clé privée d’AC pour assurer la sécurité des certificats et garantir le transport des secrets !

# Génération d’une autorité de certificat(AC) pour 10 ans

% openssl req -new -sha256 -x509 -extensions v3_ca -keyout ca.key -out ca_vault.crt -days 3650
# renforcer la protection de la clé privée de votre AC
% chown root:root ca.key && chmod 400 ca.key
# Création d’une clé privée sans mot de passe pour vault avec un csr (CN=nom de machine)
% openssl req -out vault.csr -new -newkey rsa:2048 -nodes -keyout vault.key -reqexts SANVAULT -config /etc/ssl/openssl.cnf
# Signature de votre certificat avec votre autorité de certificat
% openssl x509 -req -days 3650 -in vault.csr -out vault.pem -CA ca_vault.crt -CAkey ca.key -CAcreateserial -extfile /etc/ssl/openssl.cnf -extensions SANVAULT

Note

Vault est intransigeant avec la conformité des certificats utilisés. Sans certificat serveur avec une AC associée et enregistrée sur votre système, vous devrez rajouter des paramètres supplémentaires aux clients (-tls-skip-verify) qui affaibliraient la sécurité. Utiliser Vault en production, sans chiffrer le transport est absurde.

3. Distribuez votre certificat d’autorité (ca_vault.crt) à vos clients et à votre serveur, puis mettez à jour la base des certificats de confiance.

# (suivant distribution) ajout de notre autorité de certificat et mise à jour des CA de confiance
cp ca_vault.crt /usr/local/share/ca-certificates/ && update-ca-certificate

1.3 Le fichier de configuration

1. Écrivez un fichier de configuration avec le module de stockage de secret « File ». Il existe d’autres modules notamment pour les bases de données et ainsi que ceux qui supportent la haute disponibilité, comme consul, zookeeper ou etcd.

# /etc/vault/vault.conf
# Écoute sur le port TCP 8200 sur toutes les IPs en TLS

listener "tcp" {

 address       = "0.0.0.0:8200"

 tls_cert_file = "/etc/vault/vault.pem"
  tls_key_file = "/etc/vault/vault.key"

}
# module de stockage
backend "file" {

 path = "/var/lib/vault"
}

Note

Vault stocke ses secrets et son arborescence sous cette forme : les branches sont des répertoires et les feuilles sont des fichiers contenant les secrets. Donc aucun secret ne doit être stocké dans le chemin. De plus, avec le module « File », la lecture/écriture d’un secret passe par l’ouverture/fermeture systématique des fichiers. Il est donc mal adapté aux fortes charges.

2. Activez au redémarrage et démarrez Vault :

% systemctl enable vault.service
% systemctl start vault.service

1.4 Initialisation de la clé de chiffrement

Lors du 1er démarrage, Vault va créer une clé de chiffrement qui permettra de chiffrer les secrets. Elle est protégée par le mécanisme du partage de clé de Shamir, qui permet de diviser le secret en plusieurs parties nécessitant un minimum de participants pour la révéler (cérémonie des clés).

1. Initialisez-le (ici avec 5 clés dont 3 suffisent pour le desceller) :

% vault init -key-shares=5 -key-threshold=3
Unseal Key 1 (hex)   : 330d9e8c517aa493ca37ef7ba4f73abf3c1ef6b0e1011be6eaf56640823e559f01

Initial Root Token: 1bfde3d3-e1c2-1e2a-3c57-1fb92890361d

2. Distribuez judicieusement les « Unseal key » aux différentes personnes de votre organisation pour garantir une bonne ségrégation des droits.

Le « root token » donnera les pleins pouvoirs pour configurer les futurs droits d’accès.

3. Descellez la clé de chiffrement. Trois participants minimums devront entrer leur clé (hex ou base64) :

% vault unseal Mw2ejFF6pJPKN+97pPc6vzwe9rDhARvm6vVmQII+VZ8B

% vault unseal 738ceaaef7b8dd133e00d33d31c533634e372e294591a5f89779a092cfc67ef603

% vault unseal 7f3rxTLTmij/Z+gMrfYYgJ45LsJ/3Qw9R5nNHwLhcWAF

Vault a maintenant déchiffré et chargé en mémoire la clé de chiffrement. Désormais, vous pouvez vous authentifier et créer vos premiers secrets !

2. Stocker des secrets

1.  Authentifiez-vous avec le root token.

% vault auth 1bfde3d3-e1c2-1e2a-3c57-1fb92890361d

Pour l’organisation, la génération et la classification de secrets (« stockage logique »), Vault utilise un système d’arborescence, comme un système de fichiers, où les chemins racines se montent et se démontent.

% vault mounts

Path        Type       Default TTL  Max TTL  Description

cubbyhole/  cubbyhole  n/a          n/a      per-token private secret storage

secret/     generic    system       system   generic secret storage

sys/        system     n/a          n/a      system endpoints used for control, policy and debugging

Le chemin détermine l’URL REST d’accès à l’information et sa classification. Chaque type de module possède les propriétés présentées dans la partie description avec leur durée de vie respective.

Vous pouvez ajouter des points de montage personnalisés, par exemple avec le module « generic » :

% vault mount -path=mypassword -max-lease-ttl=87600h generic

Successfully mounted 'generic' at 'mypassword'!

Note

Contrairement à un système de fichiers Linux, le démontage d’un chemin entraîne la destruction de tous ses secrets.

2.1 Stockage de la clé de déchiffrement SSL de notre certificat apache

1. Stockez votre mot de passe de déchiffrement de votre clé privée SSL relatif au projetA et lisez-le :

vault write secret/projetA/web apache_priv_key=secret

Success! Data written to: secret/projetA/web
% vault read secret/projetA/web

Key                     Value

---                     -----

refresh_interval        720h0m0s

apache_priv_key         secret

Le refresh_interval informe le client de la durée de rafraîchissement du secret, grâce au module « generic », c’est indicatif. Il a un grand intérêt lorsque l’on utilise un système de rotation des secrets (MySQL, OTP...), pour la récupération du nouveau mot de passe valide.

2. Modifiez votre configuration apache pour lire le mot de passe de chiffrement de clé privée SSL à partir d’un script (paramètre SSLPassPhraseDialog) :

# configuration apache ssl ...

...
SSLPassPhraseDialog exec:/path/get_passwd_from_vault.sh
...

3. Écrivez le script correspondant :

#!/usr/bin/env bash
export VAULT_TOKEN="un_token_dédié"
vault read -field=apache_priv_key secret/projetA/web

Ne mettez pas votre « root-token » dans le script, car il a accès à tous les secrets. Nous verrons par la suite comment créer des tokens avec des accès restreints.

2.2 Générer des comptes MySQL tournants

2.2.1 Configuration du module

L’objectif du module est de fournir à Vault un utilisateur MySQL avec les droits nécessaires pour générer/détruire à la volée des identifiants/mots de passe pour un type de profil donné (lecture, écriture…), souhaité pour notre application.

1. Créez un utilisateur « vault_gen » sur votre MySQL avec les droits nécessaires pour ajouter/supprimer des utilisateurs et leur attribuer des droits sur la base de données «projetA» :

mysql> CREATE USER 'vault_gen'@'localhost' IDENTIFIED BY 'secret';
mysql> GRANT ALL PRIVILEGES ON projetA.* TO 'vault_gen'@'localhost' WITH GRANT OPTION;
mysql> GRANT CREATE USER ON *.* TO 'vault_gen'@'localhost';

2. Montez le module MySQL sur le point de montage « mysql.projetA ». Il sera dédié à notre instance MySQL, et les identifiants seront à renouveler toutes les 10 minutes :

% vault mount -path=projetA.mysql -description="mysql projet A" -default-lease-ttl=10m mysql

3. Configurez le module avec votre utilisateur MySQL « vault_gen ».

% vault write projetA.mysql/config/connection  

connection_url="vault_gen:secret@tcp(127.0.0.1:3306)/projetA"

4. Créez les profils de compte désirés comme « lecture, écriture et dba ». Observez ci-dessous un exemple pour la lecture seule à adapter pour vos autres comptes (droit après le « GRANT »).

# remplacer % par localhost si l’application est sur la même machine que le MySQL
% vault write projetA.mysql/roles/lecture sql="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';

GRANT SELECT ON projetA.* TO '{{name}}'@'%';"

La création des rôles est entièrement personnalisable grâce aux modèles et aux variables « {{name}} »/« {{password}} », ainsi que les requêtes SQL. Il est tout à fait possible de rajouter d’autres instructions SQL dans la chaîne.

Pour supprimer un rôle, il suffit de détruire la branche correspondante :

% vault delete projetA.mysql/roles/lecture

Note

La suppression d’un rôle et le démontage du module ne coupent pas les connexions MySQL existantes (pas de « kill »).

2.2.2 Générer des identifiants de connexion

1. Récupérez les identifiants générés par Vault dans le MySQL :

% vault read projetA.mysql/creds/lecture

password        5b65ee31-14f1-3488-ad7c-fe0d51096830

username        lect-root-1435be

2. Connectez-vous au MySQL pour tester le couple username/password :

% mysql -ulect-root-1435be -p5b65ee31-14f1-3488-ad7c-fe0d51096830 -B -N -e"show grants"

GRANT USAGE ON *.* TO 'lect-root-1435be'@'localhost' IDENTIFIED BY PASSWORD <secret>

GRANT SELECT ON `projetA`.* TO 'lect-root-1435be'@'localhost'                       

Pour utiliser ces identifiants tournants, des modifications dans votre application seront nécessaires : en faisant une requête REST directement (exemple ci-dessous avec curl) ou en utilisant une bibliothèque dédiée au langage (hvac pour python, Spring Cloud Vault pour java, etc.) :

% curl -s -H "X-Vault-Token: TOKEN" "https://127.0.0.1:8200/v1/projetA.mysql/creds/ecriture" | python -m json.tool

       "password": "1a2bd102-2af4-a284-601f-893deac80ef4",

       "username": "ecri-root-760038"

Si d’autres modules à explorer existent, il n'est pas possible de tous les traiter ici. Lorsque l’on centralise les secrets, le plus important est d’en contrôler strictement les accès, regardons la procédure à suivre.

3. Contrôler l’accès à vos secrets

Il y a deux techniques essentielles pour contrôler l'accès aux secrets : les tokens avec leurs modules d'authentification et les politiques de droit.

3.1 Comprendre les tokens

Les mécanismes d’authentification reposent sur le composant « token ». Il est représenté par un uuid, créé aléatoirement. Il est rattaché à une ou plusieurs politiques de droits, une structure de données qui permettent de les représenter sous la forme d’arbre ainsi que d’autres propriétés (durée de vie, nombre d’utilisation...). Il est plus pratique et flexible d’utiliser un module d’authentification que de créer des tokens manuellement, car il le fera pour vous. Néanmoins, il est important d’en comprendre le fonctionnement, car ils sont toujours manipulés.

La première manipulation de token est l’authentification que nous avons utilisée pour administrer Vault :

% vault auth TOKEN_ROOT

Une fois authentifié(e), on peut consulter les propriétés de son token :

% vault token-lookup

id                      2dfb381f-3bd1-9ff1-2753-37c6d1c3356a   << le token

policies                [default]                              << liste des droits pour le token

ttl                     35988                                  << durée restante avant expiration

Enfin, si on souhaite les créer, les renouveler et les détruire, découvrez cinq manipulations courantes.

3.1.1. 5 manipulations courantes de tokens

1. Comment créer un token « root » ? Ce type de token n’expire jamais. Il doit être créé pour un nombre restreint de personnes et ne jamais être mis dans une application.

% vault token-create -display-name="Bob admin" -policy="root"

2. Comment créer une hiérarchie de token ? En créant initialement la racine avec un token orphelin. Par défaut, le token est renouvelable. Il a une durée de vie fixée à « default_lease_ttl ».

% vault token-create -display-name="AdminClient1" -policy="default" -orphan

3. Comment créer un token avec une durée de vie limitée à 10 heures, renouvelable jusqu’à « default_lease_ttl »?

% vault token-create -display-name="adminClient2" -policy="default" -ttl=10h

4. Comment renouveler un token ? Vous devez le renouveler avant son expiration.

% vault token-renew -increment 10h

token_duration 10h0m0s

5. Comment révoquer un token ? Soit avec sa valeur, soit via son accesseur afin de révoquer des droits sans les avoir.

% vault token-create -orphan -renewable=true -display-name="AdminClient1" -policy="default" -ttl=10h


token           9c93ee42-aa6b-d62f-6bb4-a0ed5ff65eb2

token_accessor  a46d5538-1a9b-94c0-9e41-2bcd90d662fc
 
# les 2 commandes ci-dessous révoquent le même token
% vault token-revoke 9c93ee42-aa6b-d62f-6bb4-a0ed5ff65eb2
% vault token-revoke -accessor a46d5538-1a9b-94c0-9e41-2bcd90d662fc

Tous les tokens possèdent une ou plusieurs « policy » qui déterminent les politiques d’accès aux données. Créons en maintenant pour nos besoins.

3.2 Politique d’accès

Ils déterminent les permissions sur les secrets ou l’administration : lecture et écriture des différentes branches. Une permission se configure à l’aide de la syntaxe HCL ou json.

On décrit le chemin d’accès, avec éventuellement des jokers, puis leurs politiques et/ou leurs capacités. Une politique est un ensemble de capacités. Par défaut, il existe deux politiques de droits, lisibles ainsi :

# pour les lister
% vault policies

default

root
# pour consulter la politique « default »
% vault policies default
path "auth/token/lookup-self" {

Par défaut rien n’est autorisé. C’est la politique « default » qui permet de manipuler son propre token et son cagibi personnel (cubbyhole) : elle est automatiquement appliquée sauf à root qui a tous les droits.

3.2.1 Les droits pour votre script apache SSL

1. Définissez une politique pour que votre script apache ait accès en lecture au mot de passe SSL et appliquez-la avec la commande policy-write :

# fichier lecture_web.hcl

path "secret/projetA/web" { policy = "read" }

% vault policy-write lecture_web lecture_web.hcl

Policy 'lecture_web' written.

2. Ajoutez une politique pour administrer ces secrets :

# admin_projeta.hcl
path "secret/projetA/*" { policy = "write" }

On peut faire des politiques plus complexes comme supprimer n’importe quel token, verrouiller les secrets en cas d’intrusion et contrôler les politiques de sécurité :

# admin_securite
path "/auth/token/revoke*" { policy = "write" }
path "/sys/seal*" { policy = "sudo" }
path "/sys/policy*" { policy = "read" }

Ici, l’utilisation du droit sudo pour le scellement est nécessaire, car il est réservé à « root ».

3.2.2 Les droits pour votre MySQL

1. Donnez les droits de configuration sur le module MySQL à vos administrateurs.

# dba_projeta
path "/projetA.mysql/*" { policy = "write" }

2. N’oubliez pas de protéger tous les accès au compte MySQL créé (écriture, lecture...).

# app_db_projeta
path "/projetA.mysql/auth/creds/ecriture" { policy = "read" }

Note

Les politiques de droits sont dynamiques. Elles sont lues à chaque requête : inutile de recréer un token. De plus, on peut donner des droits sur des chemins qui n’existent pas encore.

Nous l’avons vu, manipuler les tokens est une tâche fastidieuse. Pour y palier, des modules existants  génèrent, gèrent et appliquent les politiques de droit aux tokens.

3.3 Les modules d’authentification

Ils sont nombreux, du GitHub au LDAP d’entreprise. Présentons le module « userpass » pour authentifier des personnes et le module « approle », orienté machines/applications.

3.3.1 Authentifiez des personnes

1. Activez le module une première fois et créez des utilisateurs adaptés à vos précédentes politiques de droits (un échantillon ci-dessous).

# activation du module (à faire qu’une fois)
% vault auth-enable userpass
% vault write auth/userpass/users/denis password='robustless' policies=admin_projeta
% vault write auth/userpass/users/theary password='secret' policies=admin_securite
% vault write auth/userpass/users/teddy password='bear' policies=dba_projeta,admin_projeta

2. Authentifiez-vous à l’aide de la commande auth et vos couples utilisateurs/mots de passe pour recevoir votre token.

% vault auth -method=userpass username=theary

L'authentification des personnes réussie, il s'agit de faire de même avec les applications/machines.

3.3.2 Authentifier des machines et des applications

Le module « approle » permet de créer des rôles pour vos machines et vos applications : on l’utilisera pour authentifier notre script pour apache.

1. Activez le module une seule fois :

% vault auth-enable approle

2. Créez le rôle « web_projeta » sur lequel on associe notre politique de droits « lecture_web » et on y affecte une restriction d’IP pour renforcer la sécurité.

% vault write auth/approle/role/web_projeta secret_id_ttl=0 token_ttl=24h bound_cidr_list="172.17.0.0/24" policies="lecture_web"

3. Récupérez l’identifiant de votre rôle :

% vault read auth/approle/role/web_projeta/role-id

Key     Value

---     -----

role_id 046edfd1-edbf-9310-4c80-270cb7fd1282

4. Récupérez votre « secret-id » qui est une sécurité supplémentaire. Elle associe à un rôle, un uuid confidentiel. Cela empêche la fuite de secret, lorsque l’on connaît juste le nom de l’application.

% vault write -f auth/approle/role/applicationA/secret-id
Key                     Value
---                     -----
secret_id               915a1259-d26e-e832-bd30-8ba088e701cf
secret_id_accessor      f5d6cfd4-4067-21c6-bbc7-de9e7cacbbf0

5. Modifiez le script apache ainsi :

export VAULT_TOKEN=`vault write -field=token auth/approle/login role_id=046edfd1-edbf-9310-4c80-270cb7fd1282 secret_id=915a1259-d26e-e832-bd30-8ba088e701cf`

Vous pouvez utiliser le même principe pour vos applications. Maintenant pour faire face à un incident de sécurité, on doit auditer notre gestionnaire de secret.

4. Gardez le contrôle

Pour détecter toutes activités anormales, il faut l’interconnecter avec un produit de surveillance qui est facilité par le format json des logs (Elasticsearch/watch) :

# dans un fichier
% vault audit-enable file path=/var/log/vault.log
# via syslog
% vault audit-enable syslog

Rassurez-vous, toutes les actions sont loggées avec des tokens et les secrets hachés en SHA256.

Conclusion

Vault est un outil complet et moderne adapté à tout type d’architecture moyennant quelques modifications logicielles. La mise à disposition du code source et les audits réalisés par des professionnels sont rassurants.
C’est un logiciel récent qui évolue, il est donc à installer avec un suivi régulier des mises à jour. De plus, on pourrait lui reprocher un manque de fonctionnalités pour les entreprises (HSM et interface d’administration) absentes dans la version communautaire. Néanmoins, il offre de nombreuses fonctionnalités puissantes adaptées à tous.