diff --git a/terraform/environments/dev/main.tf b/terraform/environments/dev/main.tf new file mode 100644 index 0000000..31c2879 --- /dev/null +++ b/terraform/environments/dev/main.tf @@ -0,0 +1,68 @@ +# Configuration Provider +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "~> 5.0" + } + } +} + +provider "google" { + project = var.project_id + region = var.region +} + +# 1. Appel du Module IAM (pour configurer l'accès avant de créer les VMs) +module "iam" { + source = "../../modules/iam" + + project_id = var.project_id + gcp_user_email = var.gcp_user_email + ssh_public_key = var.ssh_public_key +} + +# 2. Appel du Module Network +module "network" { + source = "../../modules/network" + + project_id = var.project_id + region = var.region + frontend_cidr = var.frontend_cidr + backend_cidr = var.backend_cidr + database_cidr = var.database_cidr + ssh_source_ranges = var.ssh_source_ranges +} + +# 3. Appel du Module Compute +module "compute" { + source = "../../modules/compute" + + # Dépendances du module network + frontend_subnet_id = module.network.subnets_map.frontend + backend_subnet_id = module.network.subnets_map.backend + database_subnet_id = module.network.subnets_map.database + + project_id = var.project_id + instance_type = var.instance_type + zone = var.zone + # Assurez-vous que l'IAM est configuré avant de créer les instances + depends_on = [module.iam] +} + +# 4. Créer le fichier de configuration Ansible (template) +# C'est un bloc data pour lire le template +data "template_file" "ansible_cfg_tpl" { + template = file("../../templates/ansible.cfg.tpl") + vars = { + frontend_ip = module.compute.internal_ips.frontend + backend_ip = module.compute.internal_ips.backend + database_ip = module.compute.internal_ips.database + } +} + +# C'est une ressource pour écrire le fichier final (inventaire Ansible) +resource "local_file" "ansible_inventory" { + content = data.template_file.ansible_cfg_tpl.rendered + filename = "ansible-inventory.cfg" # Crée le fichier dans environments/dev +} \ No newline at end of file diff --git a/terraform/environments/dev/outputs.tf b/terraform/environments/dev/outputs.tf new file mode 100644 index 0000000..9a71b50 --- /dev/null +++ b/terraform/environments/dev/outputs.tf @@ -0,0 +1,21 @@ +# IPs publiques et internes pour l'accès et Ansible +output "frontend_public_ip" { + description = "IP publique du Frontend pour les tests HTTP/HTTPS." + value = module.compute.frontend_public_ip +} + +output "internal_ips" { + description = "Map des IPs internes pour la configuration Ansible." + value = module.compute.internal_ips +} + +# Information OS Login +output "gcp_user_for_ssh" { + description = "Nom d'utilisateur pour se connecter en SSH via OS Login." + value = regex("^(.*)@", var.gcp_user_email)[0] # Extrait le nom avant @ +} + +output "service_account_email" { + description = "Email du compte de service Terraform." + value = module.iam.service_account_email +} \ No newline at end of file diff --git a/terraform/environments/dev/variables.tf b/terraform/environments/dev/variables.tf new file mode 100644 index 0000000..e8dadab --- /dev/null +++ b/terraform/environments/dev/variables.tf @@ -0,0 +1,13 @@ +output "service_account_email" { + description = "L'email du compte de service créé." + value = google_service_account.terraform_sa.email +} + +/* +# Décommentez si vous avez créé la clé +output "service_account_key" { + description = "La clé privée encodée du compte de service." + value = google_service_account_key.terraform_sa_key.private_key_base64 + sensitive = true # Marquer comme sensible +} +*/ \ No newline at end of file diff --git a/terraform/modules/compute/main.tf b/terraform/modules/compute/main.tf new file mode 100644 index 0000000..e9dd677 --- /dev/null +++ b/terraform/modules/compute/main.tf @@ -0,0 +1,86 @@ +# Définition du disque de démarrage +locals { + disk_config = { + frontend = 10 + backend = 10 + database = 20 # 20GB pour la base de données + } +} + +# Instance Frontend (publique) +resource "google_compute_instance" "frontend_instance" { + project = var.project_id + name = "frontend-instance" + machine_type = var.instance_type + zone = var.zone + tags = ["frontend", "ssh"] # Tags pour les règles de firewall + + boot_disk { + initialize_params { + image = var.image + size = local.disk_config.frontend + } + } + + network_interface { + subnetwork = var.frontend_subnet_id + # Configuration IP publique + access_config { + # Laissez vide pour IP éphémère + } + } + + metadata = { + enable-oslogin = "TRUE" # OS Login enabled + } +} + +# Instance Backend (privée) +resource "google_compute_instance" "backend_instance" { + project = var.project_id + name = "backend-instance" + machine_type = var.instance_type + zone = var.zone + tags = ["backend", "ssh"] + + boot_disk { + initialize_params { + image = var.image + size = local.disk_config.backend + } + } + + network_interface { + subnetwork = var.backend_subnet_id + # PAS de bloc access_config pour n'avoir qu'une IP interne + } + + metadata = { + enable-oslogin = "TRUE" + } +} + +# Instance Database (privée) +resource "google_compute_instance" "database_instance" { + project = var.project_id + name = "database-instance" + machine_type = var.instance_type + zone = var.zone + tags = ["database", "ssh"] + + boot_disk { + initialize_params { + image = var.image + size = local.disk_config.database + } + } + + network_interface { + subnetwork = var.database_subnet_id + # PAS de bloc access_config pour n'avoir qu'une IP interne + } + + metadata = { + enable-oslogin = "TRUE" + } +} \ No newline at end of file diff --git a/terraform/modules/compute/outputs.tf b/terraform/modules/compute/outputs.tf new file mode 100644 index 0000000..a48fce3 --- /dev/null +++ b/terraform/modules/compute/outputs.tf @@ -0,0 +1,22 @@ +output "frontend_public_ip" { + description = "L'IP publique de l'instance frontend." + value = google_compute_instance.frontend_instance.network_interface[0].access_config[0].nat_ip +} + +output "internal_ips" { + description = "Map des IPs internes de toutes les instances." + value = { + frontend = google_compute_instance.frontend_instance.network_interface[0].network_ip + backend = google_compute_instance.backend_instance.network_interface[0].network_ip + database = google_compute_instance.database_instance.network_interface[0].network_ip + } +} + +output "instance_names" { + description = "Map des noms des instances." + value = { + frontend = google_compute_instance.frontend_instance.name + backend = google_compute_instance.backend_instance.name + database = google_compute_instance.database_instance.name + } +} \ No newline at end of file diff --git a/terraform/modules/compute/variables.tf b/terraform/modules/compute/variables.tf new file mode 100644 index 0000000..379c31f --- /dev/null +++ b/terraform/modules/compute/variables.tf @@ -0,0 +1,35 @@ +variable "project_id" { + description = "L'ID du projet GCP." + type = string +} + +variable "instance_type" { + description = "Le type de machine (machine type) pour les instances (ex: e2-small)." + type = string +} + +variable "zone" { + description = "La zone GCP où déployer les instances." + type = string +} + +variable "image" { + description = "L'image du système d'exploitation à utiliser (ex: debian-cloud/debian-11)." + type = string + default = "debian-cloud/debian-11" +} + +variable "frontend_subnet_id" { + description = "L'ID du sous-réseau frontend." + type = string +} + +variable "backend_subnet_id" { + description = "L'ID du sous-réseau backend." + type = string +} + +variable "database_subnet_id" { + description = "L'ID du sous-réseau database." + type = string +} \ No newline at end of file diff --git a/terraform/modules/iam/main.tf b/terraform/modules/iam/main.tf new file mode 100644 index 0000000..2bf9a64 --- /dev/null +++ b/terraform/modules/iam/main.tf @@ -0,0 +1,48 @@ +# 1. Compte de service pour Terraform +resource "google_service_account" "terraform_sa" { + project = var.project_id + account_id = var.service_account_name + display_name = "Terraform Deployment SA" +} + +# Rôles nécessaires pour le déploiement de l'architecture +# Ces rôles doivent être adaptés au principe du moindre privilège +resource "google_project_iam_member" "sa_roles" { + for_each = toset([ + "roles/compute.admin", # Pour créer les VMs, VPCs, Firewalls + "roles/iam.serviceAccountUser", # Pour utiliser le SA + "roles/resourcemanager.projectIamAdmin" # Pour gérer les rôles (si nécessaire) + ]) + project = var.project_id + role = each.key + member = "serviceAccount:${google_service_account.terraform_sa.email}" +} + +# 2. Clé pour ce compte de service (nécessaire si vous voulez l'utiliser hors de la VM) +# ATTENTION : En général, il est préférable d'utiliser Workload Identity ou l'identité de la VM. +# Pour le TP, nous allons seulement créer la SA et les rôles. La clé n'est pas nécessaire si vous utilisez gcloud auth application-default login. +# Si une clé est requise pour le TP, décommentez ceci : +/* +resource "google_service_account_key" "terraform_sa_key" { + service_account_id = google_service_account.terraform_sa.name + public_key_type = "TYPE_X509_PEM_FILE" +} +*/ + +# 3. Configuration OS Login et 4. Clé SSH +# Attribution des rôles OS Login à votre utilisateur +resource "google_project_iam_member" "oslogin_roles" { + for_each = toset([ + "roles/compute.osLogin", + "roles/iam.serviceAccountUser" # Requis si vous utilisez un SA pour l'accès + ]) + project = var.project_id + role = each.key + member = "user:${var.gcp_user_email}" +} + +# Ajout de la clé SSH à votre compte GCP pour OS Login +resource "google_os_login_ssh_public_key" "user_ssh_key" { + user = var.gcp_user_email + key = var.ssh_public_key +} \ No newline at end of file diff --git a/terraform/modules/iam/outputs.tf b/terraform/modules/iam/outputs.tf new file mode 100644 index 0000000..e8dadab --- /dev/null +++ b/terraform/modules/iam/outputs.tf @@ -0,0 +1,13 @@ +output "service_account_email" { + description = "L'email du compte de service créé." + value = google_service_account.terraform_sa.email +} + +/* +# Décommentez si vous avez créé la clé +output "service_account_key" { + description = "La clé privée encodée du compte de service." + value = google_service_account_key.terraform_sa_key.private_key_base64 + sensitive = true # Marquer comme sensible +} +*/ \ No newline at end of file diff --git a/terraform/modules/iam/variables.tf b/terraform/modules/iam/variables.tf new file mode 100644 index 0000000..84578a3 --- /dev/null +++ b/terraform/modules/iam/variables.tf @@ -0,0 +1,20 @@ +variable "project_id" { + description = "L'ID du projet GCP." + type = string +} + +variable "service_account_name" { + description = "Nom du compte de service Terraform." + type = string + default = "terraform-deployer" +} + +variable "gcp_user_email" { + description = "Votre adresse e-mail GCP (pour OS Login)." + type = string +} + +variable "ssh_public_key" { + description = "Votre clé publique SSH (contenu du fichier ~/.ssh/id_ed25519.pub)." + type = string +} \ No newline at end of file diff --git a/terraform/modules/network/main.tf b/terraform/modules/network/main.tf new file mode 100644 index 0000000..22d727d --- /dev/null +++ b/terraform/modules/network/main.tf @@ -0,0 +1,94 @@ +# 1. VPC personnalisé +resource "google_compute_network" "vpc_network" { + project = var.project_id + name = "three-tier-vpc" + auto_create_subnetworks = false # Exigence respectée + routing_mode = "REGIONAL" +} + +# 2. Sous-réseaux (frontend, backend, database) +resource "google_compute_subnetwork" "frontend_subnet" { + project = var.project_id + name = "frontend-subnet" + ip_cidr_range = var.frontend_cidr + region = var.region + network = google_compute_network.vpc_network.id +} + +resource "google_compute_subnetwork" "backend_subnet" { + project = var.project_id + name = "backend-subnet" + ip_cidr_range = var.backend_cidr + region = var.region + network = google_compute_network.vpc_network.id +} + +resource "google_compute_subnetwork" "database_subnet" { + project = var.project_id + name = "database-subnet" + ip_cidr_range = var.database_cidr + region = var.region + network = google_compute_network.vpc_network.id +} + +# 3. Règles de firewall (4 règles) + +# Règle 1: HTTP/HTTPS vers frontend (80, 443) +resource "google_compute_firewall" "allow_web" { + project = var.project_id + name = "allow-http-https-frontend" + network = google_compute_network.vpc_network.name + direction = "INGRESS" + source_ranges = ["0.0.0.0/0"] + target_tags = ["frontend"] + + allow { + protocol = "tcp" + ports = ["80", "443"] + } +} + +# Règle 2: SSH vers toutes les instances (22) +resource "google_compute_firewall" "allow_ssh" { + project = var.project_id + name = "allow-ssh-all" + network = google_compute_network.vpc_network.name + direction = "INGRESS" + source_ranges = var.ssh_source_ranges + target_tags = ["ssh"] + + allow { + protocol = "tcp" + ports = ["22"] + } +} + +# Règle 3: Port 8000 de frontend vers backend +resource "google_compute_firewall" "allow_frontend_to_backend" { + project = var.project_id + name = "allow-frontend-to-backend-8000" + network = google_compute_network.vpc_network.name + direction = "INGRESS" + source_tags = ["frontend"] + target_tags = ["backend"] + + allow { + protocol = "tcp" + ports = ["8000"] + } +} + +# Règle 4: Port 3306 de backend vers database +resource "google_compute_firewall" "allow_backend_to_database" { + project = var.project_id + name = "allow-backend-to-database-3306" + network = google_compute_network.vpc_network.name + direction = "INGRESS" + source_tags = ["backend"] + target_tags = ["database"] + + allow { + protocol = "tcp" + ports = ["3306"] + } +} \ No newline at end of file diff --git a/terraform/modules/network/outputs.tf b/terraform/modules/network/outputs.tf new file mode 100644 index 0000000..06d7bd0 --- /dev/null +++ b/terraform/modules/network/outputs.tf @@ -0,0 +1,18 @@ +output "vpc_id" { + description = "L'ID du VPC créé." + value = google_compute_network.vpc_network.id +} + +output "subnets_map" { + description = "Map des IDs des sous-réseaux." + value = { + frontend = google_compute_subnetwork.frontend_subnet.id + backend = google_compute_subnetwork.backend_subnet.id + database = google_compute_subnetwork.database_subnet.id + } +} + +output "network_name" { + description = "Le nom du VPC créé." + value = google_compute_network.vpc_network.name +} \ No newline at end of file diff --git a/terraform/modules/network/variables.tf b/terraform/modules/network/variables.tf new file mode 100644 index 0000000..a743a45 --- /dev/null +++ b/terraform/modules/network/variables.tf @@ -0,0 +1,29 @@ +variable "project_id" { + description = "L'ID du projet GCP." + type = string +} + +variable "region" { + description = "La région GCP pour les sous-réseaux." + type = string +} + +variable "frontend_cidr" { + description = "Plage CIDR pour le sous-réseau frontend (public)." + type = string +} + +variable "backend_cidr" { + description = "Plage CIDR pour le sous-réseau backend (privé)." + type = string +} + +variable "database_cidr" { + description = "Plage CIDR pour le sous-réseau base de données (privé)." + type = string +} + +variable "ssh_source_ranges" { + description = "Plages CIDR autorisées pour l'accès SSH (par exemple, ['0.0.0.0/0'])." + type = list(string) +} \ No newline at end of file