Aller au contenu
Cloud medium

Référence Terraform sur OUTSCALE — provider, ressources, patterns Well-Architected

20 min de lecture

logo 3ds outscale

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.

ComposantVersion cibleNote
Provider OUTSCALEoutscale/outscale v1.5.0Source officielle, v1.x change la syntaxe du provider (voir « Provider »).
Terraform1.10.x ou plus récentLa doc README du provider exige 1.10.x or latest.
OpenTofuCompatibleSource 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_linkoutscale_volume_link). Suivre le guide de migration officiel avant terraform init -upgrade.

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.

terraform {
required_version = ">= 1.10.0"
required_providers {
outscale = {
source = "outscale/outscale"
version = "1.5.0"
}
}
}

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.

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) :

VariableUsage
OUTSCALE_ACCESSKEYIDAccess key (équivalent attribut access_key_id)
OUTSCALE_SECRETKEYIDSecret key (équivalent secret_key_id)
OUTSCALE_REGIONRégion cible (équivalent api.region et oks.region)
OUTSCALE_X509CERTChemin du certificat x509 client
OUTSCALE_X509KEYChemin de la clé privée x509
OSC_PROFILENom du profil dans le fichier de configuration OSC
OSC_CONFIG_FILEChemin du fichier de configuration OSC (défaut ~/.osc/config.json)

Avec ces variables exportées, un provider "outscale" {} vide suffit pour l’authentification :

Fenêtre de terminal
# Linux / macOS
export OUTSCALE_ACCESSKEYID="..."
export OUTSCALE_SECRETKEYID="..."
export OUTSCALE_REGION="eu-west-2"
# Bloc provider minimal
provider "outscale" {}

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.

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.

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 :

Fenêtre de terminal
aws s3 mb s3://lab-terraform \
--profile outscale \
--endpoint https://oos.eu-west-2.outscale.com \
--region eu-west-2

Patterns 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.

WAF — Reliability, Security, Performance. Le réseau est la première fondation, taguée multi-AZ et segmentée par tier.

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.

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).

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
}

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"
}
}
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
}

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
}
}
}
resource "outscale_keypair" "admin" {
keypair_name = "admin-key"
public_key = file("~/.ssh/id_ed25519.pub")
}
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.

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.

WAF — Reliability, Performance, Cost. Voir Stockage — BSU, volumes, IOPS pour le choix du type.

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).

⚠️ Attention migration v1 : la ressource s’appelait outscale_volumes_link avant la v1.0.0. Renommée en outscale_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"
}
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.

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.

data "outscale_images" "ubuntu_2204" {
filter {
name = "image_names"
values = ["ubuntu_2204_steph"]
}
}
# Usage
resource "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 »).

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"]
}
}

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.

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.

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.

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).

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 :

demo.aws_ec2.yml
plugin: amazon.aws.aws_ec2
aws_profile: outscale
regions:
- eu-west-2
keyed_groups:
- key: tags.Application
separator: ''
- key: tags.env
separator: ''
hostnames:
- ip-address
- private-ip-address

L’inventaire dynamique se synchronise automatiquement avec ce que Terraform a déployé, à condition que le tagging soit discipliné (cf. pattern Tagging unifié).

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.

  • Provider outscale/outscale v1.5.0 — auth via access_key_id + secret_key_id, configuration par service dans api { ... } et oks { ... }.
  • Backend OOS centralisé avec versioning, chiffrement, accès restreint via rôle EIM dédié.
  • Format TINA natif tinavW.cXrYpZ pour vm_type, pas les noms AWS-style.
  • Tagging unifiéName, env, project, owner, cost-center sur toutes les ressources facturées, contrôlé en CI.
  • Stacks séparées par cycle de vie (réseau, bastion, workloads), backend key distinct 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é.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn