Dans les bonnes pratiques de sécurité, toute information d’identification (clef API, user/mot de passe, token) ne doit être stockée :
- ni dans un repo git,
- ni dans le bloc note d’un devops (oui oui),
- ni en dur dans un fichier de configuration présent au sein d’un OS.
Mieux encore, le développeur ou le sysadmin ne doit pas avoir connaissance de ces informations d’identification.
Le script, le logiciel ou le fichier de configuration doivent eux-mêmes être en mesure de récupérer ces informations dans un coffre-fort.
Nous avons sélectionné un outil très pertinent : VAULT, développé et maintenu par la société HashiCorp.
Ce coffre-fort qui permet de stocker des secrets (il a d’autres fonctionnalités, qui ne seront pas abordées ici).
Nous verrons ici :
- Le déploiement d’un vault,
- Activation d’un « path » kv et kv v2,
- La création d’un token avec une policy pour accéder aux paths.
Pré-requis et environnement
Nous déployons sur l’environnement suivant :
- OS : Ubuntu 22.x
- Version VAULT : 1.15.4
- Domaine : https://vault.tld
Le déploiement se fait via le paquet vault officiel, il peut très bien se faire via docker.
Les pré-requis :
- Le système doit avoir accès à : apt.releases.hashicorp.com sur le port 443 en sortie,
- Vous devez avoir accès sur le port 443 à vault.tld (qui sera le domaine utilisé pour l’exemple).
Déploiement
Via l’utilisateur root (ou utilisez sudo), on installe le paquet :
# Téléchargement de la clef GPG + ajout du repo hashicorp
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
apt update ; apt install vault -y
Puis on vérifie que vault est bien installé :
vault --version
Vault v1.15.4 (9b61934559ba31150860e618cf18e816cbddc630), built 2023-12-04T17:45:28Z
On s’assure que le service sera démarré lors du démarrage de l’OS :
systemctl enable vault ; systemctl start vault
# On exporte dans une variable l'adresse, pour l'utilisation du CLI ou de l'API
echo "export VAULT_ADDR='https://vault.tld:8200'" >> ~/.bashrc
source ~/.bashrc
On modifie la configuration par défaut (/etc/vault.d/vault.hcl) pour obtenir :
ui = true
storage "file" {
path = "/opt/vault/data"
}
# HTTPS listener
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/opt/vault/tls/vault.tld.crt"
tls_key_file = "/opt/vault/tls/vault.tld.key"
}
Attention : un certificat SSL doit être fourni au VAULT, dès son initialisation, il existe plusieurs options :
- Vous avez déjà un SSL, vous pouvez passer cette étape,
- Vous n’avez pas de SSL, alors nous allons le générer localement, il faudra ultérieurement utiliser un SSL généré via une PKI (soit celle de vault, soit une autre).
Ici, nous n’avons pas de certificat SSL, il faut donc le générer, il sera nécessaire :
mkdir ~/certs
cd ~/certs
openssl genrsa -des3 -out myCA.key 2048 # Entrez une passphrase
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.pem # Vous pouvez laisser les valeurs par défaut
apt-get install -y ca-certificates
cp ~/certs/myCA.pem /etc/ssl/certs/
update-ca-certificates
awk -v cmd='openssl x509 -noout -subject' '/BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt | grep vault
openssl genrsa -out vault.tld.key 2048
openssl req -new -key vault.tld.key -out vault.tld.csr # Vous pouvez laisser les valeurs par défaut
cat > ~/certs/vault.tld.ext << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = vault.tld
IP.1 = 10.0.0.20
EOF
openssl x509 -req -in vault.tld.csr -CA myCA.pem -CAkey myCA.key \
-CAcreateserial -out vault.tld.crt -days 825 -sha256 -extfile vault.tld.ext
cp ~/certs/vault.tld.crt /opt/vault/tls/vault.tld.crt
cp ~/certs/vault.tld.key /opt/vault/tls/vault.tld.key
chown vault:root /opt/vault/tls/vault.tld.crt /opt/vault/tls/vault.tld.key
service vault restart
service vault status
● vault.service - "HashiCorp Vault - A tool for managing secrets"
Loaded: loaded (/lib/systemd/system/vault.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2023-12-11 10:24:13 CET; 2s ago
Initialisation
Il faut maintenant initialiser vault, cette étape prépare le backend de stockage à recevoir des données.
Durant cette étape unique : vault génère une clef root (root key) cryptée, qui elle-même nécessite une clef de déverrouillage (unseal) pour la décrypter.
La configuration par défaut utilise le partage de secret Shamir, pour découper la root key en plusieurs morceaux (shards). Il allons donc choisir une clef en 3 shards, dont 2 sont requis pour unseal.
Soit on peut le faire via le GUI (https://vault.tld:8200) :
Soit en CLI :
vault operator init -key-shares=3 -key-threshold=2
Unseal Key 1: T+SwTYdaG+I0BloQr5t1J2pVjOYzsiRrCZaw0r+JFkrZ
Unseal Key 2: jxy4dhv/EftA+wVo7Z+XiYLf2PaRRW1njcks197kDVuD
Unseal Key 3: Wutk9WU1+hJq9A/wYPEoPtZbr1WUoZ3VjMNSL68n025x
Initial Root Token: hvs.UrJHjbk1AJ7PU87yC8YgxcL6
Vault initialized with 3 key shares and a key threshold of 2. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 2 of these keys to unseal it
before it can start servicing requests.
Vault does not store the generated root key. Without at least 2 keys to
reconstruct the root key, Vault will remain permanently sealed!
Nous avons désormais les 3 « unseal keys », ainsi que le root token.
Vous devez les sauvegarder (ailleurs que sur l’OS), et la bonne pratique est qu’au moins 1 personne physique possède une « unseal key », et une seconde personne les 2 autres.
Cela dépend évidemment des pratiques mises en place au sein de l’entreprise.
vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed true # cette valeur doit être à "false"
Total Shares 3
Threshold 2
Unseal Progress 0/2
Unseal Nonce n/a
Version 1.15.4
Build Date 2023-12-04T17:45:28Z
Storage Type file
HA Enabled false
vault operator unseal jxy4dhv/EftA+wVo7Z+XiYLf2PaRRW1njcks197kDVuD
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed true
Total Shares 3
Threshold 2
Unseal Progress 1/2
Unseal Nonce 43e0cf65-802c-850d-1b4f-bd071c3f1fe8
Version 1.15.4
Build Date 2023-12-04T17:45:28Z
Storage Type file
HA Enabled false
vault operator unseal T+SwTYdaG+I0BloQr5t1J2pVjOYzsiRrCZaw0r+JFkrZ
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false # la valeur se trouve à false, le vault est disponible
Total Shares 3
Threshold 2
Version 1.15.4
Build Date 2023-12-04T17:45:28Z
Storage Type file
Cluster Name vault-cluster-d250c160
Cluster ID 5c9ea8e9-6f2b-f649-27ed-7a9d722862fb
HA Enabled false
Vault est désormais utilisable. A chaque redémarrage du service, il faut « unseal ».
Le root token ne doit être utilisé que pour l’initialisation et pour créer un token avec des privilèges moindres (admin).
Activation d’un « path » kv et kv v2
Afin de stocker des données sensibles, nous devons activer un path type kv.
Ce dernier est un « magasin » permettant de stocker des clefs/valeurs.
Il existe 2 versions, v1 et v2, voici quelques différences :
- En v1, comme il n’y a pas d’historique des secrets, il y a un gain de place et de performances.
- En v2, les secrets sont versionnés/historisés,
- En v2, quand une version est supprimée, la donnée ne l’est pas réellement, elle est seulement la marquée en « deleted ». Ces versions peuvent être restaurées.
Activer un chemin v2 nommé « path-v2 » :
vault login # insérer le root token
vault secrets enable -path=path-v2 -description='chemin en V2' kv-v2
Success! Enabled the kv-v2 secrets engine at: path-v2/
vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_e7482773 per-token private secret storage
identity/ identity identity_b20fe705 identity store
path-v2/ kv kv_8dac4e11 chemin en V2
sys/ system system_e84357be system endpoints used for control, policy and debugging
Activer un chemin v1 nommé « path-v1 » :
vault login # insérer le root token
vault secrets enable -path=path-v1 -description='chemin en V1" kv-v1
Success! Enabled the kv-v1 secrets engine at: path-v1/
vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_e7482773 per-token private secret storage
identity/ identity identity_b20fe705 identity store
path-v1/ kv kv_89d7587d chemin en V1
path-v2/ kv kv_8dac4e11 chemin en V2
sys/ system system_e84357be system endpoints used for control, policy and debugging
Et sur le GUI :
Créer un token et une policy
Pour enregistrer, mettre à jour ou supprimer des clefs/valeurs sur le chemin « path-v1 », nous avons besoins d’un token et d’une policy (ACL) associée.
Créer une policy adaptée :
tee path-v2-policy.hcl <<EOF
path "path-v2/*"
{
capabilities = ["create", "read", "update", "delete", "list"]
}
EOF
vault policy write path-v2-policy path-v2-policy.hcl
Success! Uploaded policy: path-v2-policy
Création du token :
vault token create -policy="path-v2-policy"
Key Value
--- -----
token hvs.CAESII2-sl33KdAWnS-4FQiRK6aIXaC5nU6yxfKi2cABto42Gh4KHGh2cy4yTXpsYkNvcm0wblFVR0VJbllCTGxUQXQ
token_accessor vKGyP3Y8A1XyGe5jrZqm6dS9
token_duration 768h
token_renewable true
token_policies ["default" "path-v2-policy"]
identity_policies []
policies ["default" "path-v2-policy"]
Nous avons juste à récupérer le token, le token accessor peut être utile à récupérer pour plus tard.
On envoie une clef/valeur :
vault login # on entre le vault token lié au path-v2-policy
vault kv put -mount=path-v2 foo=a bar=b
Lire le secret :
vault kv get -mount=path-v2 foo=a
=== Secret Path ===
path-v2/data/foo=a
======= Metadata =======
Key Value
--- -----
created_time 2023-12-13T13:06:00.457071226Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
=== Data ===
Key Value
--- -----
bar b
Comments are closed