
Cette référence récapitule l’usage du provider Terraform OUTSCALE version 1.5.0 : configuration du provider avec les nouveaux blocs api { ... } / oks { ... }, backend d’état centralisé sur OOS, ressources et datasources principales (Net, Subnet, VM, Volume, Security Group, Public IP, Route Table…), patterns alignés sur les piliers Well-Architected, antipatterns observés. Les exemples sont repris du guide pratique existant et alignés sur la syntaxe v1.5.0. La page est organisée par topic pour une consultation ciblée plutôt qu’une lecture linéaire.
Versions et compatibilité
Section intitulée « Versions et compatibilité »| Composant | Version cible | Note |
|---|---|---|
| Provider OUTSCALE | outscale/outscale v1.5.0 | Source officielle, v1.x change la syntaxe du provider (voir « Provider »). |
| Terraform | 1.10.x ou plus récent | La doc README du provider exige 1.10.x or latest. |
| OpenTofu | Compatible | Source outscale/outscale valide pour tofu init (ou registry.opentofu.org/outscale/outscale). |
La migration depuis les versions 0.x du provider implique des renommages d’état (par exemple outscale_volumes_link → outscale_volume_link). Suivre le guide de migration officiel avant terraform init -upgrade.
Provider — configuration v1.5.0
Section intitulée « Provider — configuration v1.5.0 »WAF — Operational Excellence, Security. Le provider est la porte d’entrée du pipeline IaC. Sa configuration centralise authentification, endpoint et région ; elle se versionne au même titre que le code applicatif.
Required providers
Section intitulée « Required providers »terraform { required_version = ">= 1.10.0" required_providers { outscale = { source = "outscale/outscale" version = "1.5.0" } }}Provider — blocs api et oks
Section intitulée « Provider — blocs api et oks »Depuis la v1.4.0, le provider expose des blocs par service : api { ... } pour l’OAPI principale (réseau, compute, stockage…) et oks { ... } pour OKS (Kubernetes managé). Les attributs racine region, endpoints { ... }, x509_cert_path, x509_key_path, insecure sont deprecated et seront retirés au prochain major.
provider "outscale" { access_key_id = var.access_key_id secret_key_id = var.secret_key_id
api { endpoint = "https://api.eu-west-2.outscale.com" region = "eu-west-2" }
oks { endpoint = "https://api.eu-west-2.oks.outscale.com/api/v2" region = "eu-west-2" }}Pour la région SecNumCloud, remplacer eu-west-2 par cloudgouv-eu-west-1 dans les blocs et adapter les endpoints en conséquence.
Authentification — variables d’environnement
Section intitulée « Authentification — variables d’environnement »Le provider lit directement ses identifiants depuis les variables d’environnement standard OUTSCALE — pas besoin de les passer via des var Terraform. Les variables reconnues (validées sur la documentation officielle du provider v1.5.0) :
| Variable | Usage |
|---|---|
OUTSCALE_ACCESSKEYID | Access key (équivalent attribut access_key_id) |
OUTSCALE_SECRETKEYID | Secret key (équivalent secret_key_id) |
OUTSCALE_REGION | Région cible (équivalent api.region et oks.region) |
OUTSCALE_X509CERT | Chemin du certificat x509 client |
OUTSCALE_X509KEY | Chemin de la clé privée x509 |
OSC_PROFILE | Nom du profil dans le fichier de configuration OSC |
OSC_CONFIG_FILE | Chemin du fichier de configuration OSC (défaut ~/.osc/config.json) |
Avec ces variables exportées, un provider "outscale" {} vide suffit pour l’authentification :
# Linux / macOSexport OUTSCALE_ACCESSKEYID="..."export OUTSCALE_SECRETKEYID="..."export OUTSCALE_REGION="eu-west-2"# Bloc provider minimalprovider "outscale" {}Profil et fichier de configuration OSC
Section intitulée « Profil et fichier de configuration OSC »Alternative à l’export en variables : pointer un profil dans le fichier ~/.osc/config.json (le même que celui de oapi-cli).
provider "outscale" { config_file = "./.osc/config.json" profile = "default"}Ou via les variables OSC_CONFIG_FILE et OSC_PROFILE — utile pour basculer entre comptes (par exemple OSC_PROFILE=prod vs OSC_PROFILE=secnumcloud) sans toucher au code Terraform.
x509 (authentification certificat)
Section intitulée « x509 (authentification certificat) »Pour les contextes qui imposent l’authentification par certificat client (typique des environnements cloudgouv-eu-west-1), placer les chemins dans le bloc api :
provider "outscale" { api { x509_cert_path = "/etc/outscale/client.crt" x509_key_path = "/etc/outscale/client.key" }}Ou via les variables d’environnement OUTSCALE_X509CERT et OUTSCALE_X509KEY. Les attributs racine x509_cert_path / x509_key_path du provider sont deprecated.
Backend d’état — OOS
Section intitulée « Backend d’état — OOS »WAF — Operational Excellence, Security, Reliability. Centraliser l’état Terraform sur OOS garantit reproductibilité, collaboration et traçabilité. C’est le mécanisme qui transforme un script local en pipeline équipe.
terraform { backend "s3" { bucket = "lab-terraform" key = "infrastructure/terraform.tfstate" region = "eu-west-2" endpoint = "https://oos.eu-west-2.outscale.com"
skip_credentials_validation = true skip_region_validation = true }}Les options skip_credentials_validation et skip_region_validation sont nécessaires car le backend s3 natif Terraform vérifie par défaut une authenticité AWS qui n’a pas lieu d’être ici (OOS est S3-compatible mais pas hébergé chez AWS).
Le bucket de backend doit être créé avant le premier terraform init. La méthode la plus simple en aws-cli :
aws s3 mb s3://lab-terraform \ --profile outscale \ --endpoint https://oos.eu-west-2.outscale.com \ --region eu-west-2Patterns de hardening à appliquer sur le bucket de backend : activer le versioning (récupération en cas de corruption d’état), chiffrement serveur (aws s3api put-bucket-encryption — voir Stockage OOS — versioning, lifecycle), accès restreint à un rôle EIM dédié au pipeline IaC, isolation dans un compte d’audit séparé du compte applicatif.
Ressources réseau
Section intitulée « Ressources réseau »WAF — Reliability, Security, Performance. Le réseau est la première fondation, taguée multi-AZ et segmentée par tier.
outscale_net — Net (VPC)
Section intitulée « outscale_net — Net (VPC) »Le Net est l’équivalent VPC. Préférer un /16 qui laisse la marge nécessaire au peering futur.
resource "outscale_net" "main" { ip_range = "192.168.0.0/16"
tags { key = "Name" value = "main-net" } tags { key = "env" value = "prod" }}Référence du paramètre IpRange (au format CIDR RFC 1918) : voir Réseau — design Net + Subnets.
outscale_subnet — Subnet par sous-région
Section intitulée « outscale_subnet — Subnet par sous-région »resource "outscale_subnet" "public_a" { net_id = outscale_net.main.net_id subregion_name = "eu-west-2a" ip_range = "192.168.2.0/24"
tags { key = "Name" value = "public-a" }}Pour le pilier Reliability, créer un subnet par tier (public / privé / data) et par sous-région (eu-west-2a, eu-west-2b, eu-west-2c).
Internet Service et liaison
Section intitulée « Internet Service et liaison »resource "outscale_internet_service" "igw" {}
resource "outscale_internet_service_link" "igw_link" { internet_service_id = outscale_internet_service.igw.internet_service_id net_id = outscale_net.main.net_id}NAT Service et IP publique
Section intitulée « NAT Service et IP publique »Le NAT Service vit dans un subnet public et porte une IP publique allouée séparément.
resource "outscale_public_ip" "nat_eip" {}
resource "outscale_nat_service" "nat" { subnet_id = outscale_subnet.public_a.subnet_id public_ip_id = outscale_public_ip.nat_eip.public_ip_id
tags { key = "Name" value = "nat-public-a" }}Routes et tables de routage
Section intitulée « Routes et tables de routage »resource "outscale_route_table" "public" { net_id = outscale_net.main.net_id}
resource "outscale_route_table" "private" { net_id = outscale_net.main.net_id}
resource "outscale_route" "public_to_igw" { route_table_id = outscale_route_table.public.route_table_id destination_ip_range = "0.0.0.0/0" gateway_id = outscale_internet_service.igw.internet_service_id}
resource "outscale_route" "private_to_nat" { route_table_id = outscale_route_table.private.route_table_id destination_ip_range = "0.0.0.0/0" nat_service_id = outscale_nat_service.nat.nat_service_id}
resource "outscale_route_table_link" "public_link" { subnet_id = outscale_subnet.public_a.subnet_id route_table_id = outscale_route_table.public.route_table_id}Ressources sécurité réseau
Section intitulée « Ressources sécurité réseau »WAF — Security. Le pattern SG-to-SG (un Security Group autorise un autre Security Group plutôt qu’un CIDR) est la base d’une posture défendable. Voir Réseau — Security Groups.
outscale_security_group et outscale_security_group_rule
Section intitulée « outscale_security_group et outscale_security_group_rule »resource "outscale_security_group" "web" { description = "HTTP/HTTPS from Internet" security_group_name = "web-public" net_id = outscale_net.main.net_id}
resource "outscale_security_group_rule" "web_https" { flow = "Inbound" security_group_id = outscale_security_group.web.id from_port_range = 443 to_port_range = 443 ip_protocol = "tcp" ip_range = "0.0.0.0/0"}⚠️ Le nom du Security Group passé à security_group_name ne doit pas commencer par sg- (réservé aux IDs internes du provider). Utiliser un préfixe métier (web-public, app-back, db-data).
Antipattern à éviter : ip_range = "0.0.0.0/0" sur le port 22. Le SSH ne doit jamais être ouvert sur Internet — il transite par le bastion dans le subnet public, qui est lui-même restreint à votre IP fixe ou au CIDR de votre VPN.
Pour le pattern SG-to-SG, utiliser security_group_name_to_link (référence à un autre SG par nom) ou les blocs rules { security_groups_members { security_group_id = ... } } :
resource "outscale_security_group_rule" "db_from_app" { flow = "Inbound" security_group_id = outscale_security_group.database.id rules { from_port_range = 5432 to_port_range = 5432 ip_protocol = "tcp" security_groups_members { security_group_id = outscale_security_group.app.id } }}Ressources compute
Section intitulée « Ressources compute »outscale_keypair
Section intitulée « outscale_keypair »resource "outscale_keypair" "admin" { keypair_name = "admin-key" public_key = file("~/.ssh/id_ed25519.pub")}outscale_vm
Section intitulée « outscale_vm »resource "outscale_vm" "bastion" { image_id = data.outscale_images.bastion_omi.images[0].image_id vm_type = "tinav5.c1r2p2" keypair_name = outscale_keypair.admin.keypair_name security_group_ids = [outscale_security_group.bastion_sg.id] subnet_id = outscale_subnet.public_a.subnet_id
tags { key = "Name" value = "bastion" } tags { key = "env" value = "prod" } tags { key = "owner" value = "platform" }}WAF — Performance Efficiency, Cost. Le vm_type suit le format TINA natif tinavW.cXrYpZ (voir Calcul — instances TINA et sizing). Les noms AWS-style (t2.small, m5.large) sont acceptés par compatibilité mais déconseillés en parcours OUTSCALE — préférer le format natif qui exprime exactement le couple vCPU / RAM / flag de performance.
outscale_public_ip et outscale_public_ip_link
Section intitulée « outscale_public_ip et outscale_public_ip_link »resource "outscale_public_ip" "bastion_eip" {}
resource "outscale_public_ip_link" "bastion_link" { vm_id = outscale_vm.bastion.vm_id public_ip = outscale_public_ip.bastion_eip.public_ip}WAF — Cost. Une EIP allouée mais non attachée à une VM est facturée — c’est un gisement classique de gaspillage. Auditer périodiquement via oapi-cli ReadPublicIps.
Ressources stockage
Section intitulée « Ressources stockage »WAF — Reliability, Performance, Cost. Voir Stockage — BSU, volumes, IOPS pour le choix du type.
outscale_volume
Section intitulée « outscale_volume »resource "outscale_volume" "data" { subregion_name = "eu-west-2a" size = 100 volume_type = "gp2"
tags { key = "Name" value = "app-data" }}Pour io1, ajouter iops (entier) avec un plafond de 13 000 IOPS par volume et un ratio maximum de 300 IOPS/GiB (validé sur la spec OAPI CreateVolume).
outscale_volume_link
Section intitulée « outscale_volume_link »⚠️ Attention migration v1 : la ressource s’appelait
outscale_volumes_linkavant la v1.0.0. Renommée enoutscale_volume_link(singulier).
resource "outscale_volume_link" "data_attach" { vm_id = outscale_vm.app.vm_id volume_id = outscale_volume.data.volume_id device_name = "/dev/xvdf"}outscale_snapshot
Section intitulée « outscale_snapshot »resource "outscale_snapshot" "data_snapshot" { volume_id = outscale_volume.data.volume_id
tags { key = "Name" value = "app-data-backup" } tags { key = "backup-date" value = "2026-04-29" }}WAF — Reliability, Cost. Snapshots couvrent les niveaux 1 et 2 de la règle 3-2-1 ; le niveau 3 (hors-site) est un export OOS dans un compte séparé. Voir Sauvegardes — RPO/RTO/PRA.
Datasources principales
Section intitulée « Datasources principales »WAF — Operational Excellence. Les datasources évitent de hardcoder des IDs (qui changent) et permettent de référencer des ressources créées dans une autre stack ou hors Terraform.
outscale_images — chercher une OMI
Section intitulée « outscale_images — chercher une OMI »data "outscale_images" "ubuntu_2204" { filter { name = "image_names" values = ["ubuntu_2204_steph"] }}
# Usageresource "outscale_vm" "app" { image_id = data.outscale_images.ubuntu_2204.images[0].image_id # ...}Antipattern : référencer une OMI publique avec un nom comprenant latest. Pour la reproductibilité, fixer un nom de version explicite (ubuntu_2204_v3 plutôt que ubuntu_latest) — c’est le métier de Packer (voir page « Référence Packer »).
outscale_subnet, outscale_security_group
Section intitulée « outscale_subnet, outscale_security_group »Les datasources utilisent le pattern filter { name = "..." values = [...] } validé sur la documentation officielle du provider v1.5.0. Le filtre par nom de groupe se fait via name = "security_group_names" (pluriel — c’est un nom de filtre, pas l’attribut singulier de la ressource).
data "outscale_subnet" "public_a" { filter { name = "tag_values" values = ["public-a"] }}
data "outscale_security_group" "web" { filter { name = "security_group_names" values = ["web-public"] }}Patterns Well-Architected
Section intitulée « Patterns Well-Architected »Stacks séparées par lifecycle
Section intitulée « Stacks séparées par lifecycle »WAF — Operational Excellence, Reliability. Découper le code Terraform en stacks (modules logiques avec leur propre backend) selon le cycle de vie : réseau (rare changement), compute (changements applicatifs), bastion (sécurité). L’arborescence type :
terraform/├── infrastructure/ # Net, Subnets, IGW, NAT, SG (fondations)├── bastion/ # VM bastion + clé SSH├── workloads/ # VMs applicatives└── shared/ # Resources transverses (DNS, certificats)Chaque répertoire pointe vers une key distincte du backend OOS (infrastructure/terraform.tfstate, bastion/terraform.tfstate, etc.) pour éviter les blast radius cross-stack.
Tagging unifié systématique
Section intitulée « Tagging unifié systématique »WAF — Operational Excellence, Cost. Cinq tags structurants à appliquer sur toutes les ressources facturées : Name, env, project, owner, cost-center. Sur OUTSCALE, le tagging Terraform suit la syntaxe à blocs tags { key = "..." value = "..." } (différent du tags = { ... } AWS provider).
resource "outscale_vm" "app" { # ... tags { key = "Name" value = "app-prod-01" } tags { key = "env" value = "prod" } tags { key = "project" value = "billing-api" } tags { key = "owner" value = "platform-team" } tags { key = "cost-center" value = "BU-DSI" }}Le contrôle CI sur la présence des tags rend la discipline non-négociable. Voir Pilier Operational Excellence.
Pipeline IaC — porte d’entrée unique
Section intitulée « Pipeline IaC — porte d’entrée unique »WAF — Operational Excellence, Security. Toute modification de la production passe par un commit Git → revue PR → exécution Terraform sur runner CI dédié. Pas de terraform apply depuis un poste développeur sur la production. Le compte EIM utilisé par le runner est dédié au pipeline avec une politique scopée à ce qu’il a réellement le droit de modifier.
Une break-glass procedure documente les rares cas où une intervention directe est autorisée (incident majeur, indisponibilité du pipeline) avec enregistrement systématique et commit de réconciliation dans les 24 heures.
Articulation Terraform / Packer / Ansible
Section intitulée « Articulation Terraform / Packer / Ansible »WAF — Operational Excellence, Security. Les trois outils ont des rôles complémentaires :
- Packer construit des OMI durcies (image immuable + Ansible côté provisionneur).
- Terraform déploie l’infrastructure à partir de ces OMI.
- Ansible configure le runtime sur les VMs déployées (déploiement applicatif, secrets injectés au runtime).
Le découpage évite l’antipattern « Terraform qui fait tout » (lent, fragile sur les mises à jour applicatives) et le complémentaire « Ansible qui provisionne l’infra » (peu reproductible).
Inventaire dynamique Ansible via le plugin AWS
Section intitulée « Inventaire dynamique Ansible via le plugin AWS »WAF — Operational Excellence. OUTSCALE étant compatible AWS sur l’API EC2, le plugin d’inventaire Ansible amazon.aws.aws_ec2 fonctionne pour découvrir les VMs taguées. Configuration minimale :
plugin: amazon.aws.aws_ec2aws_profile: outscaleregions: - eu-west-2keyed_groups: - key: tags.Application separator: '' - key: tags.env separator: ''hostnames: - ip-address - private-ip-addressL’inventaire dynamique se synchronise automatiquement avec ce que Terraform a déployé, à condition que le tagging soit discipliné (cf. pattern Tagging unifié).
Antipatterns à éviter
Section intitulée « Antipatterns à éviter »Hardcoder des IDs. Référencer un image_id = "ami-a3ca408c" directement dans le code. Le code casse à la moindre rotation de l’OMI. Préférer le datasource outscale_images avec un filtre par nom versionné.
Provisionner depuis Cockpit puis « faire du Terraform ». Créer des ressources via le Cockpit puis tenter d’importer dans Terraform a posteriori. Le résultat est une dette technique persistante. Démarrer Terraform-first dès le J1.
Backend local en équipe. Stocker l’état dans terraform.tfstate localement quand plusieurs personnes travaillent sur la stack. Les conflits d’état arrivent au premier apply concurrent. Backend OOS centralisé dès le J1.
Mélange tags = { ... } AWS-style et tags { key = "..." value = "..." } natif. Le provider OUTSCALE utilise la syntaxe à blocs. Le mélange provoque des erreurs de validation ou un tagging silencieusement perdu.
Région au niveau provider (deprecated). Utiliser region = "eu-west-2" à la racine du bloc provider "outscale" est deprecated en v1.5.0. Migrer vers api { region = "..." }.
Une seule stack géante. Tout dans un seul main.tf → blast radius énorme, terraform plan interminable, conflits d’équipe permanents. Découper par cycle de vie.
À retenir
Section intitulée « À retenir »- Provider
outscale/outscalev1.5.0 — auth viaaccess_key_id+secret_key_id, configuration par service dansapi { ... }etoks { ... }. - Backend OOS centralisé avec versioning, chiffrement, accès restreint via rôle EIM dédié.
- Format TINA natif
tinavW.cXrYpZpourvm_type, pas les noms AWS-style. - Tagging unifié —
Name,env,project,owner,cost-centersur toutes les ressources facturées, contrôlé en CI. - Stacks séparées par cycle de vie (réseau, bastion, workloads), backend
keydistinct par stack. - Pipeline IaC comme porte d’entrée unique des changements production, break-glass documentée.
- Articulation Packer / Terraform / Ansible — OMI durcie, infra déployée, runtime configuré.