Industrialiser une infrastructure souveraine en IaC : providers Terraform OVHcloud et Scaleway, de zéro à la production
Infrastructure as Code

Industrialiser une infrastructure souveraine en IaC : providers Terraform OVHcloud et Scaleway, de zéro à la production

23 octobre 20268 min de lectureTerraformOVHcloudScaleway

Guide pratique pour industrialiser une infrastructure souveraine avec les providers Terraform OVHcloud et Scaleway : backend d'état, IAM, Kubernetes managé et observabilité auto-hébergée.

Choisir un fournisseur cloud européen est une décision d'achat. En faire une plateforme fiable, reproductible et auditable est une décision d'ingénierie. Entre « nous avons signé avec OVHcloud » et « nous sommes en production dessus », l'écart se comble presque entièrement avec de l'Infrastructure as Code, de la gestion d'identités et de l'observabilité. Cet article parcourt ce chemin concrètement : la couverture réelle des providers Terraform ovh/ovh et scaleway/scaleway, l'amorçage d'un backend d'état souverain, et une stack d'observabilité auto-hébergée qui n'expédie pas votre télémétrie vers un SaaS soumis au droit extraterritorial.

La souveraineté est une propriété opérationnelle, pas un logo

Une infrastructure souveraine, c'est une infrastructure où vous répondez sans hésiter à trois questions : où la donnée réside physiquement, qui contrôle juridiquement l'opérateur, et qui détient techniquement les secrets. L'IaC est ce qui rend la troisième question répondable. Sans elle, la souveraineté se réduit à quelques consoles cliquées par trois personnes, sans historique ni reproductibilité — exactement l'inverse de ce qu'attend un auditeur, ou une évaluation DORA/NIS2.

Une nuance mérite d'être dite franchement : « hébergeur européen » et « qualifié SecNumCloud » ne sont pas synonymes. Une qualification porte sur un périmètre précis d'une offre précise, pas sur une entreprise entière. Si votre cible de conformité l'exige, vérifiez le périmètre exact plutôt que de supposer que tout le catalogue est couvert — et structurez votre code Terraform pour qu'un déplacement de charge entre une région public cloud standard et un périmètre qualifié soit un changement de module, pas une réécriture.

Ce que couvrent réellement les deux providers

Les deux providers sont suffisamment matures pour la production, mais leur forme diffère. Le provider Scaleway est unique et cohérent, couvrant la quasi-totalité du catalogue. Côté OVHcloud, l'histoire est scindée : ovh/ovh gère la couche compte et services managés (Kubernetes, bases managées, IAM, DNS, load balancers, vRack), tandis que les instances, réseaux et volumes Public Cloud passent souvent par le provider OpenStack, OVHcloud Public Cloud étant un déploiement OpenStack.

DomaineOVHcloudScaleway
Compute (VM)openstack_compute_instance_v2 (ou ovh_cloud_project_instance)scaleway_instance_server
Kubernetes managéovh_cloud_project_kube + ..._nodepoolscaleway_k8s_cluster + scaleway_k8s_pool
Réseau privévRack + réseaux OpenStack (ovh_vrack_cloudproject)scaleway_vpc / scaleway_vpc_private_network
Bases managéesovh_cloud_project_database (PG, MySQL, Kafka, OpenSearch…)scaleway_rdb_instance, scaleway_redis_cluster
Stockage objet (API S3)Endpoints compatibles S3, souvent pilotés via le provider AWSscaleway_object_bucket
IAMovh_iam_policy, ovh_iam_resource_groupscaleway_iam_application, _policy, _api_key
DNSovh_domain_zone_recordscaleway_domain_record

Conséquence pratique : ne construisez pas de faux module « cloud-agnostique » abstrayant les deux. Les modèles de ressources, la sémantique réseau et les règles de cycle de vie diffèrent assez pour que l'abstraction fuie en quelques semaines. Écrivez deux modules spécifiques exposant les mêmes outputs (kubeconfig, id de VPC, endpoint de base) et gardez le code consommateur générique. C'est la portabilité qui survit réellement au contact de la production.

Amorçage : un backend d'état qui ne quitte pas l'Europe

L'état Terraform contient des secrets, des IP et toute la topologie. Le stocker sur un bucket américain annule l'exercice. Les deux fournisseurs exposent un stockage objet compatible S3, utilisable avec le backend natif s3 à condition de désactiver toutes les vérifications spécifiques à AWS.

terraform {
  required_version = ">= 1.10"

  required_providers {
    ovh      = { source = "ovh/ovh",           version = "~> 2.0" }
    scaleway = { source = "scaleway/scaleway", version = "~> 2.48" }
    helm     = { source = "hashicorp/helm",    version = "~> 2.17" }
  }

  backend "s3" {
    bucket = "m2c-tfstate-prod"
    key    = "platform/par/terraform.tfstate"
    region = "fr-par"
    endpoints = { s3 = "https://s3.fr-par.scw.cloud" }

    use_path_style              = true
    skip_credentials_validation = true
    skip_region_validation      = true
    skip_requesting_account_id  = true
    skip_metadata_api_check     = true
    skip_s3_checksum            = true

    use_lockfile = true   # verrou natif S3, nécessite les écritures conditionnelles
  }
}

use_lockfile (Terraform 1.10+) remplace la table DynamoDB par un objet de verrou écrit via les écritures conditionnelles S3. Testez-le réellement sur l'endpoint de votre fournisseur avant de compter dessus : le support des écritures conditionnelles varie selon les implémentations compatibles S3. Si ce n'est pas supporté, repliez-vous sur le backend pg adossé à une base PostgreSQL managée : parfaitement souverain, verrouillage transactionnel réel, et plus simple à sauvegarder qu'une table de verrous.

Chiffrez l'état au repos dans tous les cas : chiffrement côté serveur sur le bucket, et idéalement chiffrement côté client via le state encryption de Terraform ou un coffre externe. Activez le versioning d'objets et une règle de cycle de vie conservant quelques dizaines de versions — c'est votre seul recours après un terraform apply -replace malheureux.

Les identités : la vraie difficulté

C'est là que les acteurs européens restent en retrait des hyperscalers. OVHcloud s'authentifie via un triplet application key / application secret / consumer key, à durée de vie longue et par défaut largement permissif. Scaleway utilise des applications IAM avec clés d'API. Aucun des deux n'offre aujourd'hui la fédération OIDC généralisée qui permet à un job GitHub Actions d'assumer un rôle sans secret stocké — vérifiez l'état de l'offre, mais partez du principe que vous gérerez des secrets statiques.

Les mitigations qui fonctionnent :

  • Une application IAM (Scaleway) ou une consumer key à policy IAM étroite (OVHcloud) par pipeline et par environnement. Jamais de clé admin partagée.
  • Un projet par environnement (prod, staging, dev), pour que le rayon d'explosion soit imposé par la plateforme et non par la discipline HCL.
  • Des secrets stockés dans Vault ou OpenBao, injectés à l'exécution, et une rotation planifiée.
  • Des identifiants en lecture seule pour le plan sur les merge requests, des identifiants en écriture uniquement sur le job de la branche protégée.

Un vrai cluster, en code

Chez OVHcloud, un cluster Kubernetes managé de production rattaché à un réseau privé vRack ressemble à ceci :

resource "ovh_cloud_project_kube" "prod" {
  service_name = var.ovh_project_id
  name         = "prod-gra"
  region       = "GRA11"
  version      = "1.31"

  private_network_id = var.openstack_private_network_id

  update_policy = "MINIMAL_DOWNTIME"

  customization_apiserver {
    admissionplugins {
      enabled  = ["NodeRestriction"]
      disabled = ["AlwaysPullImages"]
    }
  }
}

resource "ovh_cloud_project_kube_nodepool" "workers" {
  service_name  = var.ovh_project_id
  kube_id       = ovh_cloud_project_kube.prod.id
  name          = "workers"
  flavor_name   = "b3-16"
  desired_nodes = 3
  min_nodes     = 3
  max_nodes     = 9
  autoscale     = true

  template {
    metadata { labels = { "m2c.io/pool" = "workers" } }
  }
}

Deux pièges. D'abord, private_network_id attend l'identifiant du réseau OpenStack rattaché au vRack, pas l'identifiant du vRack : erreur classique de premier jour. Ensuite, update_policy gouverne la façon dont OVHcloud applique les mises à jour de patch au control plane et aux nœuds ; choisissez-la délibérément et alignez-la sur vos fenêtres de maintenance, plutôt que de la découvrir pendant un incident.

L'équivalent Scaleway est plus autonome :

resource "scaleway_vpc_private_network" "prod" {
  name   = "prod-par"
  region = "fr-par"
}

resource "scaleway_k8s_cluster" "prod" {
  name                        = "prod-par"
  version                     = "1.31"
  cni                         = "cilium"
  private_network_id          = scaleway_vpc_private_network.prod.id
  delete_additional_resources = false

  autoscaler_config {
    scale_down_delay_after_add = "10m"
    estimator                  = "binpacking"
  }
}

resource "scaleway_k8s_pool" "workers" {
  cluster_id  = scaleway_k8s_cluster.prod.id
  name        = "workers"
  node_type   = "PRO2-S"
  size        = 3
  min_size    = 3
  max_size    = 9
  autoscaling = true
  autohealing = true
}

Notez delete_additional_resources = false : laissé permissif, la destruction du cluster peut aussi supprimer les load balancers et volumes créés par le cloud controller manager. En production, positionnez-le explicitement et nettoyez de façon délibérée.

Observabilité auto-hébergée et souveraine

Héberger son infrastructure en Europe tout en expédiant chaque métrique, log et trace vers un SaaS contrôlé hors UE est une incohérence évidente — et un auditeur la trouvera. Bonne nouvelle : la stack d'observabilité open source est aujourd'hui de qualité production et peu coûteuse à opérer sur du stockage objet.

Une stack de référence pragmatique :

SignalComposantStockage long terme
MétriquesPrometheus (mode Agent) + Mimir ou Thanos, ou VictoriaMetricsBucket S3 (fr-par / GRA)
LogsGrafana Alloy / Promtail → LokiBucket S3, chunks + index
TracesOpenTelemetry Collector → TempoBucket S3
Dashboards & alertingGrafana + AlertmanagerPostgreSQL managé pour l'état Grafana

Tout s'adosse au même stockage objet souverain que celui de votre état Terraform. La configuration Loki est typique :

loki:
  storage:
    type: s3
    bucketNames:
      chunks: m2c-loki-chunks
      ruler:  m2c-loki-ruler
    s3:
      endpoint:         s3.fr-par.scw.cloud
      region:           fr-par
      s3ForcePathStyle: true
      insecure:         false
  limits_config:
    retention_period: 720h

Trois points opérationnels comptent davantage que le choix des composants. La rétention : le stockage objet est bon marché, les appels d'API et la sortie réseau beaucoup moins — ajustez la taille des chunks et la compaction, pas seulement la durée de rétention. La haute disponibilité : répliquez le chemin d'écriture, mais acceptez qu'une stack mono-région devienne aveugle si cette région tombe ; si votre SLA l'exige, répliquez les métriques vers une seconde région, idéalement chez l'autre fournisseur. Et l'isolation : le cluster d'observabilité ne doit pas tourner sur le cluster qu'il observe. Un petit cluster géré séparément — idéalement chez le second fournisseur — est l'assurance la moins chère de toute la plateforme.

Livrer : du GitOps pour l'infrastructure

Épinglez strictement les versions de providers (~> sur le mineur, jamais de majeur flottant) et commitez le lock file : les deux providers introduisent des ruptures entre majeures. Exécutez un plan sur chaque merge request avec des identifiants en lecture seule, publiez-le en commentaire, et conditionnez l'apply à une fusion approuvée. Atlantis fonctionne bien ici car il ne dépend pas d'OIDC natif ; un job GitLab CI avec injection Vault également.

Attention au rate limiting des API sur les gros applies : réduire -parallelism à 5 ou 10 fait souvent la différence entre un pipeline instable et un pipeline déterministe. Et planifiez une détection de drift : sur des providers où certains attributs forcent un remplacement (changer le réseau privé d'un cluster, par exemple), mieux vaut découvrir la dérive dans un plan nocturne que pendant un changement d'urgence.

Checklist de mise en production

  • État dans un bucket européen, versionné, chiffré, avec verrouillage fonctionnel (testé, pas supposé).
  • Un projet et un identifiant restreint par environnement ; aucune clé admin partagée ; rotation automatisée.
  • Versions de providers épinglées et lock file commité.
  • Modules par fournisseur exposant des outputs identiques — pas d'abstraction prématurée.
  • Observabilité auto-hébergée, sur son propre cluster, télémétrie stockée dans la même juridiction.
  • Procédure de restauration documentée et testée pour l'état et les sauvegardes de bases managées.
  • Périmètre de conformité vérifié : quelles régions, quelle offre, quelle qualification s'applique réellement.

Rien d'exotique là-dedans. C'est la même discipline que chez un hyperscaler, moins quelques conforts (fédération OIDC, largeur du catalogue managé) et plus une propriété qui compte : vous savez exactement où vivent vos données et vos secrets.

← Retour au blog