Stocker ses informations d’identification sur Vault (#1)

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