Vault sur Clever Cloud
Série d'articles : Terraform et Clever Cloud
Pour les besoins des cours que je donne Ă l’UniversitĂ© de Lille, j’ai dĂ» configurer un serveur Vault sur Clever Cloud.
Et bien entendu, j’ai fait tout ça avec Terraform.
Cet article dĂ©crit comment utiliser le provider Terraform de Clever Cloud pour dĂ©ployer un serveur Vault. Un article suivant dĂ©crira comment le configurer pour l’authentification OIDC avec GitLab et y stocker quelques secrets Ă titre d’exemple.
Le code de cet article est aussi disponible sur GitHub : https://github.com/juwit/terraform-clevercloud-playground/tree/main/vault.
Cet article a été écrit avec des commandes Terraform, mais fonctionne également avec les commandes OpenTofu équivalentes.
Architecture cible
Avant d’entrer dans la mise en pratique, il convient ici d’expliquer quelques choix illustrĂ©s par le schĂ©ma suivant.

Clever Cloud propose de dĂ©ployer des applications dans de nombreux langages. Pour hĂ©berger une instance Vault, le plus simple semblait d’utiliser une instance Docker.
Par dĂ©fault, Vault propose l’utilisation du backend de stockage Integrated storage pour le stockage des donnĂ©es. Ătant donnĂ© la nature du dĂ©ploiement avec une instance Docker sur un seul nĆud et le fait que Clever Cloud ne supporte pas le stockage persistant pour ce type d’instance, il m’a semblĂ© judicieux d’utiliser un backend de stockage externalisĂ©. Parmi les options proposĂ©es par Vault, 3 options sont envisageables sur Clever Cloud : les bases de donnĂ©es MySQL ou PostgreSQL, ou S3 via l’implĂ©mentation Cellar fournie par Clever Cloud.
Le stockage externalisĂ© sur S3 ne supporte pas la haute disponibilitĂ© et pourrait s’avĂ©rer incompatible avec l’implĂ©mentation Cellar (cf. les adaptations requises par le backend Terraform S3 pour Cellar), donc je l’ai directement Ă©cartĂ© et j’ai privilĂ©giĂ© l’implĂ©mentation avec PostgreSQL.
L’authentification via GitLab permet Ă mes Ă©tudiants d’utiliser leur compte GitLab existant, en exploitant l’instance GitLab fournie par l’UniversitĂ© de Lille. C’est donc trĂšs pratique pour eux (pas besoin d’avoir un compte ailleurs) et pour moi (pas besoin de crĂ©er et de fournir des comptes). J’aurais aussi pu utiliser une instance KeyCloak pour implĂ©menter l’authentification, mais cela aurait complexifiĂ© inutilement l’implĂ©mentation.
Ă noter aussi que je ne suis pas expert Vault, donc je ne suis pas Ă l’abri d’avoir fait une erreur de configuration quelque part, alors attention si vous utilisez cette configuration en production đ
SetUp de Terraform
Dans un article prĂ©cĂ©dent, j’ai dĂ©jĂ expliquĂ© comment configurer Terraform pour Clever Cloud, ainsi que comment configurer un backend via un bucket Cellar. Ces Ă©tapes ne sont pas dĂ©crites ici pour ne pas alourdir cet article, mais sont bien nĂ©cessaires.
Création de la base de données avec Terraform
La premiÚre étape consiste à créer une base de données consacrée à Vault. Avec Terraform, la création de la base de données se fait avec le code suivant :
resource "clevercloud_postgresql" "vault_storage" {
name = "vault_storage"
plan = "dev"
region = "par"
}
Vault nĂ©cessite que le schĂ©ma de la base de donnĂ©es soit initialisĂ© avant que l’application ne soit dĂ©marrĂ©e. Le schĂ©ma est fourni dans la documentation du backend :
CREATE TABLE vault_kv_store (
parent_path TEXT COLLATE "C" NOT NULL,
path TEXT COLLATE "C",
key TEXT COLLATE "C",
value BYTEA,
CONSTRAINT pkey PRIMARY KEY (path, key)
);
CREATE INDEX parent_path_idx ON vault_kv_store (parent_path);
Ce script peut ĂȘtre passĂ© Ă la main via psql, ou dans la console Clever Cloud.
Il est aussi possible d’utiliser un provisioner Terraform pour exĂ©cuter le script aprĂšs la crĂ©ation de la base de donnĂ©es :
resource "clevercloud_postgresql" "vault_storage" {
name = "vault_storage"
plan = "dev"
region = "par"
provisioner "local-exec" {
# wait for the database to be up
command = "sleep 10 && psql -f vault-schema.sql"
environment = {
PGHOST = self.host
PGPORT = self.port
PGDATABASE = self.database
PGUSER = self.user
PGPASSWORD = self.password
}
}
}
Ici, le provisioner local-exec est utilisé pour exécuter la commande psql aprÚs avoir attendu quelques secondes, le temps que la base de données soit effectivement créée.
Les variables d’environnement nĂ©cessaires Ă l’exĂ©cution de psql sont Ă©galement positionnĂ©es.
Je ne suis pas un grand fan de l’exĂ©cution de provisioners, car ils impliquent une dĂ©pendance avec la machine qui exĂ©cute Terraform. Ici, c’est le binaire
psqlet la commandesleepdans le script shell qui sont nécessaires.
CrĂ©ation de l’instance Vault avec Terraform
Une fois la base de donnĂ©es créée et le schĂ©ma initialisĂ©, on peut crĂ©er l’instance Docker pour notre Vault sur Clever Cloud avec le code suivant :
resource "clevercloud_docker" "vault_instance" {
name = "vault_instance"
# vertical auto-scaling disabled
smallest_flavor = "XS"
biggest_flavor = "XS"
# horizontal auto-scaling disabled
min_instance_count = 1
max_instance_count = 1
# network setup
additional_vhosts = ["vault-instance.cleverapps.io"]
redirect_https = true
# URL for the storage backend
environment = {
VAULT_LOCAL_CONFIG = jsonencode(
{
"storage"Â : {
"postgresql"Â : {
"connection_url"Â : "postgres://${clevercloud_postgresql.vault_storage.user}:${clevercloud_postgresql.vault_storage.password}@${clevercloud_postgresql.vault_storage.host}:${clevercloud_postgresql.vault_storage.port}/${clevercloud_postgresql.vault_storage.database}"
}
},
"listener"Â : [{ "tcp"Â : { "address"Â : "0.0.0.0:8080", "tls_disable"Â : true } }],
"disable_mlock"Â : true,
"ui"Â : true
})
}
}
Parmi les paramĂštres de configuration intĂ©ressants, on retrouve les paramĂštres principaux de la ressource clevercloud_docker, avec les paramĂštres de scalabilitĂ© horizontale et verticale, ainsi que la dĂ©claration d’un nom de domaine customisĂ©.
Les variables d’environnement permettent de passer sa configuration Ă Vault (plutĂŽt que d’utiliser un fichier).
C’est un des aspects bien pratique de l’image Docker de Vault (documentĂ© sur dockerhub).
Ici, on utilise la variable VAULT_LOCAL_CONFIG, dans laquelle on donne du contenu formatĂ© en JSON, Ă l’aide de la fonction Terraform jsonencode().
Concernant la configuration de Vault, le stockage sur l’instance PostgreSQL est dĂ©fini Ă travers le paramĂštre "storage" : { "postgresql" : {} }. L’URL de connexion est passĂ©e en paramĂštre, elle est reconstruite Ă partir des attributs de la ressource clevercloud_postgresql.vault_storage. Le paramĂštre listener permet de forcer Vault Ă Ă©couter sur le port 8080, Ă la place du port par dĂ©faut 8200, qui est le port d’Ă©coute attendu par Clever Cloud. L’utilisation de l’adresse 0.0.0.0 permet aussi d’Ă©couter sur les connexions provenant d’internet (Ă la place de l’adresse localhost 127.0.0.1 par dĂ©faut). C’est aussi Clever Cloud qui va s’occuper de l’exposition d’un certificat pour l’accĂšs en HTTPS Ă l’instance, on dĂ©sactive donc le TLS avec l’option tls_disable.
Enfin, on dĂ©sactive le lock de mĂ©moire en RAM avec disable_mlock, car l’exĂ©cution de containers Docker sur Clever Cloud ne permet pas, Ă ma connaissance, l’utilisation de la capability Linux IPC_LOCK. Cette capability de Linux permet de donner les droits Ă un processus de verrouiller sa mĂ©moire en RAM pour Ă©viter que la mĂ©moire soit Ă©crite sur le swap. Le paramĂštre ui permet d’activer la console graphique de Vault, qui sera bien pratique pour les Ă©tapes suivantes.
Une fois l’application Docker créée, on peut rĂ©cupĂ©rer son identifiant Clever Cloud avec un output Terraform :
output "vault_instance_id" {
description = "Clever Cloud id for the instance. Use with `clever link` before deploying."
value = clevercloud_docker.vault_instance.id
}
$ terraform output -raw vault_instance_id
app_72d4b5a4-1ab8-4653-a825-9be0c62e0fa1
Cet output permettra d’exĂ©cuter les commande clever link et clever deploy pour dĂ©ployer l’instance Vault Ă l’Ă©tape suivante.
Déploiement de Vault
Le dĂ©ploiement d’une application Docker sur Clever Cloud passe par l’Ă©criture d’un Dockerfile et l’exĂ©cution de la commande clever deploy.
Le contenu du fichier Dockerfile est simpliste :
FROM hashicorp/vault:1.18
CMD ["server"]
On part d’une version fixĂ©e de Vault, (la version 1.18 Ă©tant la plus rĂ©cente Ă l’heure de l’Ă©criture de ces lignes), et on surcharge la commande exĂ©cutĂ©e par Vault au dĂ©marrage de l’application avec la directive CMD ["server"].
Par dĂ©faut, Vault dĂ©marre en mode « dĂ©veloppement », avec la commande CMD ["server", "-dev"]. Si vous souhaitez simplifier vos tests, vous pouvez conserver cette directive, mais elle est dĂ©conseillĂ©e pour de la production. Je l’ai donc dĂ©sactivĂ©e dans cet article.
AprĂšs avoir créé un repository Git pour notre fichier et commitĂ© celui-ci, le dĂ©ploiement se fait en 2 commandes, clever link pour associer le repository Git courant Ă l’instance Clever Cloud Docker, puis clever deploy pour soumettre le code source Ă Clever Cloud :
$ clever link app_72d4b5a4-1ab8-4653-a825-9be0c62e0fa1
Your application has been successfully linked!
$ clever deploy
Remote application is app_id=app_72d4b5a4-1ab8-4653-a825-9be0c62e0fa1, alias=vault_instance, name=vault_instance
Remote application belongs to orga_0331b635-5a61-4786-8f2f-dee81a1b8970
App is brand new, no commits on remote yet
New local commit to push is c6eb36c12ee5ca4a6f0cbcaa2683310856ef7f42 (from refs/heads/main)
Pushing source code to Clever Cloud
Your source code has been pushed to Clever Cloud.
Waiting for deployment to start
Deployment started (deployment_f5deb5ec-e9af-4f19-a5c2-978356632954)
Waiting for application logs
Couldn't start vault with IPC_LOCK. Disabling IPC_LOCK, please use --cap-add IPC_LOCK
==> Vault server configuration:
Administrative Namespace:
Cgo: disabled
Environment Variables: APP_HOME, APP_ID, CC_APP_ID, CC_APP_NAME, CC_COMMIT_ID, CC_DEPLOYMENT_ID, CC_ENVIRON_UPDATE_TOKEN, CC_ENVIRON_UPDATE_URL, CC_INSTANCE_ID, CC_OWNER_ID, CC_PRETTY_INSTANCE_NAME, CC_REVERSE_PROXY_IPS, CC_USE_PULSAR_LOGSCOLLECTION, COMMIT_ID, HOME, HOSTNAME, INSTANCE_ID, INSTANCE_NUMBER, INSTANCE_TYPE, NAME, PATH, PORT, PWD, SHLVL, VAULT_LOCAL_CONFIG, VAULT_PG_CONNECTION_URL, VERSION
Go Version: go1.23.3
Listener 1: tcp (addr: "0.0.0.0:8080", cluster address: "0.0.0.0:8081", disable_request_limiter: "false", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level:
Mlock: supported: true, enabled: false
Recovery Mode: false
Storage: postgresql (HA disabled)
Version: Vault v1.18.3, built 2024-12-16T14:00:53Z
Version Sha: 7ae4eca5403bf574f142cd8f987b8d83bafcd1de
2025-01-03T14:25:52.301Z [INFO] proxy environment: http_proxy="" https_proxy="" no_proxy=""
2025-01-03T14:25:52.333Z [INFO] incrementing seal generation: generation=1
2025-01-03T14:25:52.333Z [WARN] no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set
2025-01-03T14:25:52.336Z [INFO] core: Initializing version history cache for core
2025-01-03T14:25:52.336Z [INFO] events: Starting event system
==> Vault server started! Log data will stream in below:
Application start successful
Successfully deployed in 0 minutes and 28 seconds
Au démarrage, Vault indique que la configuration est bien chargée, et affiche quelques warnings.
Concernant le warning mentionnant l’IPC_LOCK, il n’est pas possible Ă ma connaissance de forcer l’option
--cap-add IPC_LOCKsur Clever Cloud. Néanmoins, ce warning ne pose pas de problÚme, puisque le lock de la mémoire est désactivé avec le paramÚtredisable_mlock.
Une fois le dĂ©marrage terminĂ©, la commande clever open permet d’ouvrir un navigateur web sur notre instance de Vault !
$ clever open
Opening the application in your browser
L’URL d’accĂšs Ă Vault peut aussi ĂȘtre rĂ©cupĂ©rĂ©e de deux maniĂšres : avec la commande clever domain, ou avec un output Terraform qu’on ajoute au code qui crĂ©e l’instance Docker.
$ clever domain
app_72d4b5a4-1ab8-4653-a825-9be0c62e0fa1.cleverapps.io
* vault-instance.cleverapps.io
output "vault_url" {
description = "URL of the Vault instance."
value = clevercloud_docker.vault_instance.vhost
}
$ terraform output -raw vault_url
app_72d4b5a4-1ab8-4653-a825-9be0c62e0fa1.cleverapps.io
Initialisation du Vault
Lors de sa premiĂšre ouverture, Vault doit ĂȘtre initialisĂ©, puis dĂ©verrouillĂ©. Ces Ă©tapes permettent de crĂ©er ses clĂ©s de dĂ©verrouillage (unseal keys), ainsi que le token d’accĂšs root qui permettra d’utiliser l’API dans un premier temps.
Ces opĂ©rations doivent ĂȘtre faites une seule fois Ă la crĂ©ation du serveur Vault et doivent ĂȘtre faites manuellement via le CLI Vault ou sa console. Dans cet exemple, nous allons effectuer ces manipulations dans la console de Vault :

Une fois le nombre de clĂ©s choisi, ainsi que les diffĂ©rentes options de chiffrement, Vault gĂ©nĂšre les clĂ©s et les met Ă disposition sur l’Ă©cran suivant :

Ces clĂ©s ne doivent ĂȘtre perdues en aucune circonstance ! En cas d’utilisation en production, le nombre de clĂ©s souhaitĂ© sera probablement diffĂ©rent de 1 !
AprĂšs avoir stockĂ© les clĂ©s en lieu sĂ»r, l’Ă©cran suivant nous invite Ă dĂ©verrouiller Vault en saisissant une clĂ© de dĂ©verrouillage. Lorsque suffisamment de clĂ©s auront Ă©tĂ© entrĂ©es, Vault sera dĂ©verrouillĂ© et prĂȘt Ă l’utilisation.

Une fois Vault dĂ©verrouillĂ©, l’Ă©cran de login apparaĂźt, il est alors possible de se connecter avec le token d’accĂšs root obtenu aux Ă©tapes prĂ©cĂ©dentes :

La console de Vault est maintenant disponible :

Vault est maintenant initialisĂ©, dĂ©verrouillĂ© et prĂȘt Ă ĂȘtre utilisé !
L’article suivant traitera de la configuration de Vault pour utiliser l’authentification OIDC de GitLab, et finaliser cette architecture.
En conclusion
Cet article a prĂ©sentĂ© comment mettre en Ćuvre l’installation et la configuration d’un serveur Vault sur Clever Cloud.
C’est cette infrastructure qui m’a permis de pouvoir mettre Ă disposition rapidement un serveur Vault pour mes Ă©tudiants, afin de les former Ă la rĂ©cupĂ©ration de secrets depuis une application Spring Boot.
Pour exĂ©cuter l’infrastructure proposĂ©e dans cet article, il vous en coĂ»tera environ 16 âŹ/mois avec les plans utilisĂ©s :
| article | prix/mois |
|---|---|
| PostgreSQL - Dev | 0 ⏠|
| Docker - Plan XS | 16 ⏠|
Cette architecture n’est pas parfaite, mais permet de facilement dĂ©ployer un Vault pour des cas d’usage simples ou un environnement de dev. Il faudrait bien entendu la revoir (en particulier les plans utilisĂ©s) pour un environnement de production.
Liens et références
- Exemples de code de cet article sur GitHub
- Page d’accueil de Clever Cloud
- Installation du CLI Clever Cloud
- Installation du CLI Terraform
- Installation du CLI OpenTofu
- Documentation du provider Terraform Clever Cloud :
- Ressource
clevercloud_postgresql - Ressource
clevercloud_docker
- Ressource
- Documentation de Vault :
- L’image Docker de Vault sur dockerhub
- Configuration du storage PostgreSQL
- IPC_LOCK et mlock :
- Manpage des capabilities Linux (pour l’option
--cap-add IPC_LOCK) - Manpage de l’appel systĂšme mlock
- Un article Vault and mlock() dans le help center de HashiCorp
- Le paramĂštre
disable_mlockdans la configuration de Vault
- Manpage des capabilities Linux (pour l’option
- Photo de couverture par Jason Dent sur Unsplash