Terraform
Terraform est un outil que j’utilise pour provisionner mes ressources hébergées chez cetains fournisseurs comme OVH, ScaleWay, Azure ou AWS. On parle dès lors d’infrastructure As Code (IaC) : cela permet d’automatiser certaines tâches. L’objectif est de provisionner des ressources chez un fournisseur. Plus d’informations : Browse Providers | Terraform Registry.
L’ensemble des commandes ci-dessous sont compatibles avec l’ensemble des clients (Windows, Mac, Linux). Nous allons dans notre exemple déployer une infrastructure chez Scaleway avec Terraform et executer des actions sur un serveur OVHcloud.
Installation de Terraform sur Mac OS
Il est possible d’installer manuellement le paquet sous Mac OS, ou via le gestionnaire de paquet Homebrew :
brew tap hashicorp/tap
Running `brew update --preinstall`...
==> Auto-updated Homebrew!
d 3 taps (hashicorp/tap, homebrew/core and homebrew/cask).
==> New Formulae
dbml-cli dotdrop [email protected] goctl libabw lndir octosql release-it sdl2_sound sftpgo xcode-kotlin
==> Updated Formulae
Updated 554 formulae.
==> New Casks
aethersx2 jquake plus42-binary ti-smartview-ce-for-the-ti-84-plus-family vieb
bike manila plus42-decimal tqsl yandex-music-unofficial
ferdium mega podman-desktop trivial
groestlcoin-core oxwu protokol universal-android-debloater
==> Updated Casks
Updated 731 casks.
==> Deleted Casks
entropy gloomhaven-helper indigo kite megax nbtexplorer shortery tifig twitch xoctave
brew install hashicorp/tap/terraform
==> Downloading https://releases.hashicorp.com/terraform/1.1.9/terraform_1.1.9_darwin_arm64.zip
######################################################################## 100.0%
==> Installing terraform from hashicorp/tap
???? /opt/homebrew/Cellar/terraform/1.1.9: 3 files, 71.4MB, built in 2 seconds
==> Running `brew cleanup terraform`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Je consulte ensuite le registre des fournisseurs existants et je recherche Scaleway : scaleway/scaleway | Terraform Registry et OVHcloud.
Configuration de Terraform
Pour démarrer, il est nécessaire de créer un dossier dédié à chaque projet Terraform. Puis il faut créer un fichier main.tf à l’intérieur. Il existe deux façons d’écrire notre configuration : via le language HashiCorp ou via le format structuré JSON. Dans mon cas, je préfère utiliser le formatage JSON.
Terraform avec Scaleway
Nous allons nous intéresser à une intégration chez le fournisseur Scaleway (les commandes init, plan, apply sont expliquées plus bas dans l’exemple avec le fournisseur OVH si besoin).
Voici un exemple de configuration chez Scaleway :
terraform {
required_providers {
scaleway = {
source = "scaleway/scaleway"
}
}
required_version = ">= 0.13"
}
provider "scaleway" {
alias = "production"
profile = "kassianoff-blog"
}
resource "scaleway_account_ssh_key" "jérémie" {
provider = scaleway.production
name = "Jérémie"
public_key = "ssh-ed25519 AABBCCDDEEFFGGAABBCCDDEEFFGGAABBCCDDEEFFGGAABBCCDDEEFFGGAABBCCDDEEFF"
}
resource "scaleway_instance_ip" "public_ip" {
provider = scaleway.production
}
locals {
ip_source = [
{ ip = "mon_ip_routable_01/32", port = "22" },
{ ip = "mon_ip_routable_02/32", port = "22" },
]
any_in = [
{ ip_range = "0.0.0.0/0", port = "80" },
{ ip_range = "0.0.0.0/0", port = "443" },
]
any_out = [
{ ip_range = "0.0.0.0/0", port = "53", protocol = "TCP" },
{ ip_range = "0.0.0.0/0", port = "53", protocol = "UDP" },
{ ip_range = "0.0.0.0/0", port = "80", protocol = "TCP" },
{ ip_range = "0.0.0.0/0", port = "443", protocol = "TCP" },
]
}
resource "scaleway_instance_security_group" "prod" {
provider = scaleway.production
description = "scaleway-firewall"
name = "Kassianoff scaleway firewall"
inbound_default_policy = "drop"
outbound_default_policy = "drop"
enable_default_security = false
dynamic "inbound_rule" {
for_each = local.ip_source && local.any_in
content {
action = "accept"
ip = inbound_rule.value.ip
ip_range = inbound_rule.value.ip_range
port = inbound_rule.value.port
}
}
dynamic "outbound_rule" {
for_each = local.any_out
content {
action = "accept"
ip_range = outbound_rule.value.ip_range
port = outbound_rule.value.port
protocol = outbound_rule.value.protocol
}
}
}
resource "scaleway_instance_server" "blog" {
provider = scaleway.production
name = "kassianoff blog"
type = "DEV1-L"
image = "ubuntu_jammy"
tags = [ "blog" ]
ip_id = scaleway_instance_ip.public_ip.id
security_group_id = scaleway_instance_security_group.blog.id
private_network {
pn_id = scaleway_vpc_private_network.blog.id
}
}
resource "scaleway_rdb_database" "blog" {
instance_id = scaleway_rdb_instance.blog.id
name = "kassianoff-database"
node_type = "DB-DEV-S"
engine = "PostgreSQL-14"
is_ha_cluster = true
disable_backup = true
user_name = "kassianoff"
password = "thiZ_is_v&ry_s3cret"
region= "fr-par"
tags = [ "db", "blog" ]
volume_type = "bssd"
volume_size_in_gb = 5
private_network {
ip_net = "192.168.1.254/24"
pn_id = "${scaleway_vpc_private_network.blog.id}"
}
}
resource scaleway_vpc_private_network blog {
name = "production"
}
N’oublions pas de configurer un profile pour notre provider Scaleway :
profiles:
kassianoff-blog:
access_key: XXXXXXXXXXXXXXXXXXXX
secret_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
default_organization_id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
default_project_id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
default_zone: fr-par-1
default_region: fr-par
api_url: https://api.scaleway.com
insecure: false
- Nous précisons le fournisseur avec qui l’on souhaite interagir, c’est à dire Scaleway.
- Nous avons défini un profil nommé « kassianoff-blog » pour contacter notre fournisseur. Cela fait référence à un fichier de configuration (qui n’est pas celui par défaut). Celui-ci contient nos secrets, notre zone de déploiement ainsi que le endpoint de Scaleway :
- Nous ajoutons une clé SSH à notre profil Scaleway afin de pouvoir nous connecter à notre prochaine instance.
- Nous ajoutons une ressource ip_publique afin de pouvoir obtenir une adresse IP sur notre prochaine instance.
- Nous déclarons une variable « locales » dans un array JSON avec plusieurs valeurs : ip_source, any_in, any_out, afin de pouvoir les réutiliser dans l’édition de la configuration du pare-feu Scaleway.
- Nous allons ensuite créer un groupe de sécurité Scaleway en y intégrant nos règles pare-feu dans une expression dynamique afin de réutiliser nos variables.
- Nous allons par la suite créer notre instance serveur en choisissant son nom, son type et ses caractéristiques. Nous remarquons que l’intégration avec l’ip publique et que le groupe de sécurité est bien visible.
- De plus, nous souhaitons créer une base de donnée managée par Scaleway afin de nous affranchir de sa gestion. Nous connectons en plus un réseau privé à notre base de données et configurons son interface dans le réseau privé.
- Un réseau privé sera créé afin de faire communiquer l’instance et la base de donnée dans un réseau privé (il vous faudra configuration votre interface ens5(eth1) sur le serveur linux pour accéder à la base de donnée).
Terraform avec OVHcloud
Voici un autre petit exemple pour basculer mon serveur kimsufi datant de 2013 en mode rescue et le redémarrer :
terraform {
required_providers {
ovh = {
source = "ovh/ovh"
}
}
}
provider "ovh" {
endpoint = "ovh-eu"
application_key = "namJkXXXXXXXXXXX"
application_secret = "rXXXXXXXXXXXX"
consumer_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
data ovh_dedicated_server_boots "rescue" {
service_name = "ksXXXXXXX.kimsufi.com"
boot_type = "rescue"
kernel = "rescue64-pro"
}
resource ovh_dedicated_server_update "server_on_rescue" {
service_name = "ksXXXXXXX.kimsufi.com"
boot_id = data.ovh_dedicated_server_boots.rescue.result[0]
monitoring = true
state = "ok"
}
resource ovh_dedicated_server_reboot_task "server_reboot" {
service_name = data.ovh_dedicated_server_boots.rescue.service_name
keepers = [
ovh_dedicated_server_update.server_on_rescue.boot_id,
]
}
L’une des premières commandes Terraform est « terraform init« . Elle est utilisée pour initialiser un répertoire de travail contenant les fichiers de configuration de Terraform. Il s’agit de la première commande à exécuter après l’écriture d’une nouvelle configuration Terraform.
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding ovh/ovh versions matching "~> 0.11.0"...
- Installing ovh/ovh v0.11.0...
- Installed ovh/ovh v0.11.0 (signed by a HashiCorp partner, key ID F56D1A6CBDAAADA5)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
La seconde commande est « terraform plan« . La commande crée un plan d’exécution, qui vous permet de prévisualiser les modifications que Terraform prévoit d’apporter à votre infrastructure.
Par défaut, lorsque Terraform crée un plan, il lit l’état actuel de tous les objets distants déjà existants pour s’assurer que l’état de Terraform est à jour. Il compare ensuite la configuration actuelle à l’état précédent et note toute différence. Il propose alors un ensemble d’actions de modification qui devraient, si elles sont appliquées, faire en sorte que les objets distants correspondent à la configuration actuelle :
terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# ovh_dedicated_server_reboot_task.server_reboot will be created
+ resource "ovh_dedicated_server_reboot_task" "server_reboot" {
+ comment = (known after apply)
+ done_date = (known after apply)
+ function = (known after apply)
+ id = (known after apply)
+ keepers = [
+ "1122",
]
+ last_update = (known after apply)
+ service_name = "ksxxxxxxx.kimsufi.com"
+ start_date = (known after apply)
+ status = (known after apply)
}
# ovh_dedicated_server_update.server_on_rescue will be created
+ resource "ovh_dedicated_server_update" "server_on_rescue" {
+ boot_id = 1122
+ id = (known after apply)
+ monitoring = true
+ service_name = "ksxxxxxxx.kimsufi.com"
+ state = "ok"
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
ovh_dedicated_server_update.server_on_rescue: Creating...
ovh_dedicated_server_update.server_on_rescue: Still creating... [10s elapsed]
ovh_dedicated_server_update.server_on_rescue: Creation complete after 11s [id=ksxxxxxxx.kimsufi.com]
ovh_dedicated_server_reboot_task.server_reboot: Creating...
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [10s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [20s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [30s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [40s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [50s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [1m0s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [1m10s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [1m20s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Still creating... [1m30s elapsed]
ovh_dedicated_server_reboot_task.server_reboot: Creation complete after 1m31s [id=251909160]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Un courriel d’OVH arrivera automatiquement dans votre boîte mail afin de vous transmettre les informations de connexion en mode rescue. Je vous invite à consulter la documentation OVH afin de déployer d’autres types de configuration et également la documentation Terraform pour en apprendre d’avantage.