Compare commits

13 Commits
main ... main

Author SHA1 Message Date
58cf0c33a1 feat: result md 2025-12-04 11:36:19 +01:00
cf309ad25e fix: potential fix on plan firewall 2025-12-04 10:30:12 +01:00
0ce8512917 fix: potential fix on plan firewall 2025-12-04 10:18:56 +01:00
5697b71dbe fix: potential fix on plan firewall 2025-12-04 10:13:06 +01:00
3c74853b94 feat: main outputs 2025-12-04 10:01:35 +01:00
442239cd7d fix: project id iam 'google_os_login_ssh_public_key' 2025-12-04 09:57:33 +01:00
58eee8b122 feat: iam module 2025-12-04 09:51:23 +01:00
f0cdaf15f0 iam md 2025-12-04 09:36:44 +01:00
d48f45abe7 fix: zone error 2025-12-03 17:02:53 +01:00
1e8a026e41 feat: compute module 2025-12-03 16:54:57 +01:00
e23e646c48 feat: env/dev var 2025-12-03 16:14:07 +01:00
fce17b31d2 feat: environments dev 2025-12-03 15:55:14 +01:00
4d39543590 feat: network module 2025-12-03 15:54:45 +01:00
15 changed files with 1057 additions and 0 deletions

90
iam-step.md Normal file
View File

@@ -0,0 +1,90 @@
# TP : Gestion des Identités (IAM) et Accès SSH
Dans cette partie, vous allez configurer les accès pour que Terraform puisse interagir avec le projet et pour que vous puissiez vous connecter aux futures machines virtuelles.
## Objectifs
1. Créer une identité machine (Service Account).
2. Lui donner des droits sur le projet.
3. Configurer votre propre clé SSH via le service **OS Login** de GCP.
---
## Étape 1 : Créer l'identité machine
**Objectif :** Créer un compte de service (Service Account) qui sera utilisé par nos scripts d'automatisation.
* **Ressource à utiliser :** `google_service_account`
* **Consignes :**
* Donnez-lui l'ID `terraform`.
* Ajoutez un `display_name` explicite pour qu'on le reconnaisse dans la console GCP.
## Étape 2 : Générer une clé d'accès
**Objectif :** Pour utiliser ce compte de service depuis l'extérieur (ou via Terraform), nous avons besoin d'une clé.
* **Ressource à utiliser :** `google_service_account_key`
* **Consignes :**
* Vous devez lier cette ressource au compte de service créé à l'étape 1 via son attribut `name` (ex: `google_service_account.votre_nom.name`).
* Définissez le type de clé publique sur `"TYPE_X509_PEM_FILE"`.
## Étape 3 : Donner des droits (IAM)
**Objectif :** Un compte de service naît sans aucun droit. Vous devez lui donner le rôle de "Viewer" sur le projet pour qu'il puisse lire les ressources.
* **Ressource à utiliser :** `google_project_iam_binding`
* **Consignes :**
* **Project :** Utilisez votre variable `var.project_id`.
* **Role :** Le rôle cible est `"roles/viewer"`.
* **Members :** C'est une liste. Attention à la syntaxe spécifique GCP pour désigner un membre : `"serviceAccount:..."`. Vous devez concaténer ce préfixe avec l'email du service account créé à l'étape 1 (`.email`).
## Étape 4 : Récupérer votre identité
**Objectif :** Terraform doit savoir "qui" lance le script actuellement pour associer la clé SSH à la bonne personne.
* **Data Source à utiliser :** `data "google_client_openid_userinfo"`
* **Consignes :**
* Déclarez simplement ce bloc `data` avec le nom `me`. Il n'a pas besoin d'arguments à l'intérieur. Il servira juste à récupérer votre email dynamiquement.
## Étape 5 : Ajouter votre clé SSH (OS Login)
**Objectif :** Uploader votre clé publique SSH locale vers GCP pour permettre la connexion aux VMs sans gestion manuelle.
* **Ressource à utiliser :** `google_os_login_ssh_public_key`
* **Consignes :**
* **User :** Utilisez l'email récupéré grâce au data source de l'étape 4 (`.email`).
* **Key :** Vous devez lire le contenu de votre fichier de clé publique locale.
* **Fonction Terraform :** Utilisez la fonction `file("chemin/vers/la/clé")`.
* **Chemin recommandé :** `~/.ssh/id_ed25519.pub`.
> **Attention :** Vérifiez impérativement que vous avez bien généré une clé SSH sur votre poste local avant de lancer le `terraform apply`. Sinon, Terraform ne trouvera pas le fichier et plantera.
---
### Résumé des liens entre ressources
Assurez-vous que vos ressources se référencent correctement :
* La **Clé** référencie le **Service Account**.
* L'**IAM Binding** référencie le **Service Account**.
* L'**OS Login** référencie le **Data User Info**.
Voici la suite du document Markdown (MD) à ajouter à la suite de l'étape 5.
---
## Étape 6 : Exposer les résultats (Outputs)
**Objectif :** Une fois le déploiement terminé, Terraform masque par défaut certaines informations. Nous devons définir explicitement quelles valeurs nous voulons voir ou récupérer (notamment pour les utiliser dans d'autres scripts).
* **Fichier à utiliser :** `outputs.tf` (c'est une bonne pratique de séparer les outputs du `main.tf`).
### Consigne A : L'email du Service Account
Nous aurons besoin de connaître l'adresse email complète générée par Google pour ce compte.
* Créez un output nommé `service_account_email`.
* Dans la valeur (`value`), référencez l'attribut `.email` de la ressource créée à l'**Étape 1**.
### Consigne B : La Clé Privée (Attention Sécurité)
Nous devons récupérer la clé privée générée pour pouvoir authentifier des applications externes.
* Créez un output nommé `service_account_key`.
* Dans la valeur, référencez l'attribut `.private_key` de la ressource créée à l'**Étape 2**.
* **Important :** Terraform refusera d'afficher cette valeur ou l'affichera en clair dans vos logs si vous ne faites pas attention. Vous **devez** ajouter l'argument suivant dans ce bloc output pour masquer la valeur dans le terminal :
```hcl
sensitive = true
```

556
result.md Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,37 @@
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 6.12.0"
}
}
}
provider "google" {
project = var.project_id
region = var.region
}
module "network" {
source = "../../modules/network"
project_name = var.project_name
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
}
module "compute" {
source = "../../modules/compute"
instance_type = var.instance_type
zone = var.zone
frontend_subnet_id = module.network.subnet_ids["frontend"]
backend_subnet_id = module.network.subnet_ids["backend"]
database_subnet_id = module.network.subnet_ids["database"]
}
module "iam" {
source = "../../modules/iam"
project_id = var.project_id
}

View File

@@ -0,0 +1,34 @@
# Outputs du module Network
output "vpc_id" {
description = "ID du VPC"
value = module.network.vpc_id
}
output "subnet_ids" {
description = "IDs des sous-réseaux"
value = module.network.subnet_ids
}
# Outputs du module Compute
output "internal_ips" {
description = "IPs internes des instances"
value = module.compute.internal_ips
}
output "frontend_public_ip" {
description = "IP publique du frontend"
value = module.compute.frontend_public_ip
}
output "instance_names" {
description = "Noms des instances"
value = module.compute.instance_names
}
# Outputs du module IAM
output "service_account_email" {
description = "Email du Service Account"
value = module.iam.service_account_email
}
output "service_account_key" {
description = "Clé privée du Service Account"
value = module.iam.service_account_key
sensitive = true
}

View File

@@ -0,0 +1,10 @@
project_id = "ecole-478713"
project_name = "test-terraform"
region = "europe-west9"
zone = "europe-west9-b"
instance_type = "e2-small"
frontend_cidr = "10.0.1.0/24"
backend_cidr = "10.0.2.0/24"
database_cidr = "10.0.3.0/24"
ssh_source_ranges = "0.0.0.0/0"

View File

@@ -0,0 +1,53 @@
variable "project_id" {
description = "ID du projet GCP"
type = string
}
variable "project_name" {
description = "Nom du projet"
type = string
default = "mon-projet"
}
variable "region" {
description = "Région GCP"
type = string
default = "europe-west9"
}
variable "zone" {
description = "Zone GCP pour les instances"
type = string
default = "europe-west9-b"
}
variable "instance_type" {
description = "Type d'instance GCP"
type = string
default = "e2-small"
}
variable "frontend_cidr" {
description = "CIDR pour le sous-réseau frontend"
type = string
default = "10.0.1.0/24"
}
variable "backend_cidr" {
description = "CIDR pour le sous-réseau backend"
type = string
default = "10.0.2.0/24"
}
variable "database_cidr" {
description = "CIDR pour le sous-réseau database"
type = string
default = "10.0.3.0/24"
}
variable "ssh_source_ranges" {
description = "Plages d'adresses IP source autorisées pour SSH"
type = string
default = "0.0.0.0/0"
}

View File

@@ -0,0 +1,67 @@
resource "google_compute_instance" "frontend-vm" {
name = "frontend-vm"
machine_type = var.instance_type
zone = var.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
size = 10
}
}
network_interface {
access_config {}
subnetwork = var.frontend_subnet_id
}
tags = ["frontend", "ssh"]
metadata = {
enable-oslogin = "TRUE"
}
}
resource "google_compute_instance" "backend-vm" {
name = "backend-vm"
machine_type = var.instance_type
zone = var.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
size = 10
}
}
network_interface {
subnetwork = var.backend_subnet_id
}
tags = ["backend", "ssh"]
metadata = {
enable-oslogin = "TRUE"
}
}
resource "google_compute_instance" "database-vm" {
name = "database-vm"
machine_type = var.instance_type
zone = var.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
size = 20
}
}
network_interface {
subnetwork = var.database_subnet_id
}
tags = ["database", "ssh"]
metadata = {
enable-oslogin = "TRUE"
}
}

View File

@@ -0,0 +1,22 @@
output "internal_ips" {
description = "IPs internes de toutes les instances"
value = {
frontend = google_compute_instance.frontend-vm.network_interface[0].network_ip
backend = google_compute_instance.backend-vm.network_interface[0].network_ip
database = google_compute_instance.database-vm.network_interface[0].network_ip
}
}
output "frontend_public_ip" {
description = "IP publique du frontend"
value = google_compute_instance.frontend-vm.network_interface[0].access_config[0].nat_ip
}
output "instance_names" {
description = "Noms des instances"
value = {
frontend = google_compute_instance.frontend-vm.name
backend = google_compute_instance.backend-vm.name
database = google_compute_instance.database-vm.name
}
}

View File

@@ -0,0 +1,24 @@
variable "instance_type" {
description = "Type d'instance"
type = string
}
variable "zone" {
description = "Zone GCP des instances"
type = string
}
variable "frontend_subnet_id" {
description = "ID du sous-réseau frontend"
type = string
}
variable "backend_subnet_id" {
description = "ID du sous-réseau backend"
type = string
}
variable "database_subnet_id" {
description = "ID du sous-réseau database"
type = string
}

View File

@@ -0,0 +1,23 @@
resource "google_service_account" "terraform" {
account_id = "terraform"
display_name = "Service Account for Terraform"
}
resource "google_service_account_key" "terraform_key" {
service_account_id = google_service_account.terraform.name
public_key_type = "TYPE_X509_PEM_FILE"
}
resource "google_project_iam_binding" "terraform_viewer" {
project = var.project_id
role = "roles/viewer"
members = ["serviceAccount:${google_service_account.terraform.email}"]
}
data "google_client_openid_userinfo" "me" {}
resource "google_os_login_ssh_public_key" "default" {
project = var.project_id
user = data.google_client_openid_userinfo.me.email
key = file("~/.ssh/id_ed25519.pub")
}

View File

@@ -0,0 +1,10 @@
output "service_account_email" {
description = "Email du Service Account"
value = google_service_account.terraform.email
}
output "service_account_key" {
description = "Clé privée du Service Account"
value = google_service_account_key.terraform_key.private_key
sensitive = true
}

View File

@@ -0,0 +1,4 @@
variable "project_id" {
description = "ID du projet GCP"
type = string
}

View File

@@ -0,0 +1,80 @@
# VPC
resource "google_compute_network" "vpc" {
name = "${var.project_name}-vpc"
auto_create_subnetworks = false
}
# Sous-réseaux
resource "google_compute_subnetwork" "frontend" {
name = "${var.project_name}-frontend"
network = google_compute_network.vpc.id
ip_cidr_range = var.frontend_cidr
region = var.region
}
resource "google_compute_subnetwork" "backend" {
name = "${var.project_name}-backend"
network = google_compute_network.vpc.id
ip_cidr_range = var.backend_cidr
region = var.region
}
resource "google_compute_subnetwork" "database" {
name = "${var.project_name}-database"
network = google_compute_network.vpc.id
ip_cidr_range = var.database_cidr
region = var.region
}
# Firewall
resource "google_compute_firewall" "allow_http" {
name = "${var.project_name}-allow-http"
network = google_compute_network.vpc.id
allow {
protocol = "tcp"
ports = ["80", "443"]
}
source_ranges = ["0.0.0.0/0"]
target_tags = ["frontend"]
}
resource "google_compute_firewall" "allow_ssh" {
name = "${var.project_name}-allow-ssh"
network = google_compute_network.vpc.id
allow {
protocol = "tcp"
ports = ["22"]
}
source_ranges = [var.ssh_source_ranges]
target_tags = ["ssh"]
}
resource "google_compute_firewall" "allow_frontend_to_backend" {
name = "test-terraform-allow-frontend-to-backend"
network = google_compute_network.vpc.id
allow {
protocol = "tcp"
ports = ["8000"]
}
source_tags = ["frontend"]
target_tags = ["backend"]
}
resource "google_compute_firewall" "allow_backend_to_database" {
name = "test-terraform-allow-backend-to-database"
network = google_compute_network.vpc.id
allow {
protocol = "tcp"
ports = ["3306"]
}
source_tags = ["backend"]
target_tags = ["database"]
}

View File

@@ -0,0 +1,13 @@
output "vpc_id" {
description = "ID du VPC"
value = google_compute_network.vpc.id
}
output "subnet_ids" {
description = "IDs des sous-réseaux frontend, backend, database"
value = {
"frontend" = google_compute_subnetwork.frontend.id
"backend" = google_compute_subnetwork.backend.id
"database" = google_compute_subnetwork.database.id
}
}

View File

@@ -0,0 +1,34 @@
variable "project_name" {
description = "Nom du projet"
type = string
default = "mon-projet"
}
variable "region" {
description = "Région du projet"
type = string
default = "europe-west9"
}
variable "frontend_cidr" {
description = "CIDR pour frontend"
type = string
default = "10.0.1.0/24"
}
variable "backend_cidr" {
description = "CIDR pour backend"
type = string
default = "10.0.2.0/24"
}
variable "database_cidr" {
description = "CIDR pour database"
type = string
default = "10.0.3.0/24"
}
variable "ssh_source_ranges" {
description = "Plages d'adresses IP source autorisées pour SSH"
type = string
}