> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Créer une landing zone avec la fast fabric de Google.
- URL: https://www.sfeir.dev/cloud/creer-une-landing-zone-gcp/
- Published: 2024-07-19T12:39:23.000Z
- Updated: 2024-07-22T08:49:05.000Z
- Description: Cloud foundation fabric ou comment avoir une landing zone opérationnelle rapidement.
- Author: Laurent Al Hossri
- Tags: Cloud, GCP, Terraform

## Introduction

Déplacer certaines de nos charges de travail dans le cloud est maintenant chose courante pour beaucoup d'entreprises. Cependant, avant de lancer nos premiers conteneurs ou nos premières fonctions as a service, il faut créer nos fondations. Sous Google Cloud, cela se traduit de manière non exhaustive par la mise en place des org policies, de la facturation, des rôles personnalisés, du Workload Identity Federation ou encore par l'interconnexion entre un éventuel réseau on-premise et Google cloud. Avec un ensemble de blueprints et de modules basés sur Terraform, Google propose au travers de sa fabric un outil permettant de créer des landing zones utilisables en production.

### La fast fabric

Afin de faciliter la mise en place d'une landing zone, l'outil de Google propose aussi Fast, un ensemble de fichiers Terraform rassemblés en stages, à lancer dans un ordre précis et utilisant les outputs pour assurer la cohérence entre les stages. Ils s'appuient sur des modules maintenus par Google et nous permettent de créer nos fondations étape par étape. Pour commencer à jouer avec, il suffit de cloner le dépôt suivant :

```
git clone https://github.com/GoogleCloudPlatform/cloud-foundation-fabric.git
```

## Les stages

Ils ne sont pas tous nécessaires au déploiement d'une landing zone. Les principaux à utiliser sont les suivants: 

### 0-bootstrap

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2024/07/bootstrap.png)

bootstrap: mise en place brique de l'organisation

Ce stage permet de mettre en place les éléments suivants (liste non exhaustive)

- **Org policies:** Des exemples sont fournis dans le projet, mais cela permet à une organisation de restreindre la création de ressources à une région spécifique. De plus, elle peut limiter les types de VM utilisables ou interdire les adresses IP externes sur celles-ci, par exemple.
- **Projets de démarrage:** Mise en place d'un projet dédié à la facturation, aux audits logs et à l'automatisation.
- **Workload Identity & Automatisation:** Création de buckets pour stocker les states terraform, les fichiers providers et les fichiers de variables des différents stages. En utilisant les variables `cicd_repositories` et `workload_identity_providers`, le WIF sera configuré pour permettre aux pipelines de se connecter à Google Cloud sans avoir besoin de comptes de service.
- **Comptes de services:** Création des comptes de services pour l'automatisation au travers de l'impersonate (prendre le rôle d'un compte de service ayant des droits supérieurs aux nôtres).
- **Attribution de droits aux groupes:** attributions de droits aux groupes `gcp-devops` `gcp-billing-admins` `gcp-network-admins` `gcp-organization-admins` `gcp-security-admins`, afin de permettre aux personnes de l'organisation de travailler convenablement, tout en respectant la règle du moindre privilège. Attention, ces groupes sont malgré tout permissifs, car destinés à des personnes de type administrateur.

En suivant la documentation, il est nécessaire de lancer plusieurs commandes pour créer les comptes de service dont on utilisera les droits par la suite. Il faut également lier le compte de facturation de l'organisation et créer les buckets qui seront utilisés pour stocker les états Terraform.

On commence par se placer dans le dossier `0-bootstrap`

```BASH
cd fast/stages/0-bootstrap
```

Attribuer les droits au compte d'initialisation :

```HCL
# set variable for current logged in user
export FAST_BU=$(gcloud config list --format 'value(core.account)')

# find and set your org id
gcloud organizations list
export FAST_ORG_ID=123456

# set needed roles
export FAST_ROLES="roles/billing.admin roles/logging.admin \
  roles/iam.organizationRoleAdmin roles/resourcemanager.projectCreator \
  roles/resourcemanager.organizationAdmin roles/resourcemanager.tagAdmin \
  roles/owner"

for role in $FAST_ROLES; do
  gcloud organizations add-iam-policy-binding $FAST_ORG_ID \
    --member user:$FAST_BU --role $role --condition None
done
```

Une fois les droits en place sur le compte, peupler le fichier `terraform.tfvars`, afin de fournir les informations relatives à notre organisation. En voici un exemple :

```HCL
billing_account = {
  id = "H3XA01-H3XA02-H3XA03" #Billing id de l'organisation
}

# Region de GCS, BigQuery et des logs buckets.
locations = {
  bq      = "EU"
  gcs     = "EU"
  logging = "eu"
  pubsub  = []
}

# utiliser `gcloud organizations list` pour trouver les informations.
organization = {
  domain      = "domaine.com"
  id          = 1111111092111
  customer_id = "CUST0MERID"
}

prefix = "dom" # prefix appliqué à toutes les ressources

groups = {
  gcp-devops              = "dom-gcp-devops"
  gcp-billing-admins      = "dom-gcp-bil-admin"
  gcp-network-admins      = "dom-gcp-net-admin"
  gcp-organization-admins = "dom-gcp-org-admin"
  gcp-security-admins     = "dom-gcp-secu-admin"
}

# exemple d'ajout de droits pour des personnes ou des groupes
iam_bindings_additive = {
  #  "user:prenom.nom@domain.com" = [
  #    { role = "roles/logging.admin" },
  #  ]
  #  "group:dom-gcp-log-admin@domain.com" = [
  #    { role = "roles/logging.admin" },
  #    { role = "roles/resourcemanager.folderAdmin" },
  #  ]
}

log_sinks = {
  audit-logs = {
    filter = "logName:\"/logs/cloudaudit.googleapis.com%2Factivity\" OR logName:\"/logs/cloudaudit.googleapis.com%2Fsystem_event\""
    type   = "logging"
  }
}

workload_identity_providers = {
  # Use a private instance of Gitlab and specify a custom issuer_uri
  gitlab = {
    issuer              = "gitlab"
    name                = "gitlab-wif"
    custom_settings     = {
      issuer_uri = "https://gitlab.domain.com"
      audiences = ["https://gitlab.domain.com"]
      jwks_json = "<mon_jwks>"
    }
  }
}

cicd_repositories = {
    bootstrap = {
      name              = "bootstrap"
      type              = "gitlab"
      branch            = "main"
      identity_provider = "gitlab"
    }
    resman = {
      name              = "resman"
      type              = "gitlab"
      branch            = "main"
      identity_provider = "gitlab"
    }
  }
```

Maintenant, lancer un `terraform apply` en utilisant la variable `bootstrap_user` permettant de créer l'essentiel au lancement du second apply.

```HCL
terraform init
terraform apply \
  -var bootstrap_user=$(gcloud config list --format 'value(core.account)')
```

Il faut maintenant récupérer le provider généré actuellement stocké dans un bucket, afin de migrer le state Terraform dans Google Cloud et finir le bootstrap. La partie suivante sera la gestion des ressources. Utiliser la commande ci-dessous en remplaçant dom par le préfixe choisi précédemment :

```BASH
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/providers/0-bootstrap-providers.tf ./
```

Appliquer une nouvelle fois le terraform, sans variable, afin de créer l'ensemble des ressources, en pensant à migrer les states dans le bucket dédié à cet effet :

```HCL
terraform init --migrate-state
terraform apply
```

### 1-resman

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2024/07/resman.png)

resman: mise en place de l'IAM, IaC et des dossiers de premier niveau

Ce stage permet de créer les dossiers `Networking` et `Security` afin de centraliser les projets, de mettre en place la CI/CD pour les stages networking, project factory, ..., de déployer une sandbox, des arborescences "typiques" (data, gke, etc.) ou bien des dossiers de premier niveau.

Pour lancer ce stage, il faut commencer par récupérer les variables du stage bootstrap et le provider généré, actuellement dans le bucket du projet `iac-core-0`. Pour cela, on lance les commandes cloud suivantes (penser à changer le préfixe) :

```
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/providers/1-resman-providers.tf ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./
```

On vient mettre à jour notre `terraform.tfvars` pour créer le dossier racine `data`, activer la `project_factory`, et mettre en place le workload identity federation pour les projets `networking`et `project_factory`

```HCL
# Lister dans top_level_folders la liste des folders à créer au premier niveau

top_level_folders = {
  data = {
    name = "data"
    parent = "folders/nnnnnnnnnn" #A remplacer par l'id du dossier
    automation = {
      enable = false
    }
    # iam = {
    #   "roles/viewer" = [
    #     "group:test-1-viewers@domaine.com"
    #   ]
    #}
   }
 }

fast_features = {
    project_factory = true
}

cicd_repositories = {
    networking = {
      name              = "networking"
      type              = "gitlab"
      branch            = "main"
      identity_provider = "gitlab"
    }
    project_factory_dev = {
      name              = "project_factory_dev"
      type              = "gitlab"
      branch            = "main"
      identity_provider = "gitlab"
    }
    project_factory_prod = {
      name              = "project_factory_prod"
      type              = "gitlab"
      branch            = "main"
      identity_provider = "gitlab"
    }
}
```

On peut maintenant créer l'arborescence avec les commandes init, plan et apply de terraform : 

```HCL
terraform init
terraform plan
terraform apply
```

### 2-networking

Cette partie est divisée en plusieurs stages possibles, mais seul le `2-networking-a-simple` sera présenté ici. Il permet de mettre en place un VPN HA entre l'on-premise d'une entreprise et Google Cloud afin de se connecter à des bases de données, envoyer les logs ou récupérer des fichiers. L'architecture mise en place est de type `hub & spoke`, tous les flux passant par la zone landing comme le montre le schéma suivant : 

![HA-VPN diagram](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/raw/master/fast/stages/2-networking-a-simple/diagram-vpn.svg)

exemple d'architecture VPN HA

Récupérer dans un premier temps les fichiers nécessaires à l'exécution de ce stage :

```bash
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/providers/2-networking-providers.tf ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/1-resman.auto.tfvars.json ./
```

Comme dans les précédentes étapes, il faut remplir le fichier `terraform.tfvars` dans le but de configurer le VPN.

```HCL
vpn_onprem_primary_config = {
  peer_external_gateways = {
    default = {
      redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT"
      interfaces      = ["8.8.8.8"]
    }
  }
  router_config = {
    asn = 65501
    custom_advertise = {
      all_subnets = false
      ip_ranges   = {
        "10.1.0.0/16"     = "gcp"
        "35.199.192.0/19" = "gcp-dns"
        "199.36.153.4/30" = "gcp-restricted"
      }
    }
  }
  tunnels = {
    "0" = {
      bgp_peer = {
        address = "169.254.1.1"
        asn     = 65500
      }
      bgp_session_range               = "169.254.1.2/30"
      peer_external_gateway_interface = 0
      shared_secret                   = "foo"
      vpn_gateway_interface           = 0
    }
    "1" = {
      bgp_peer = {
        address = "169.254.2.1"
        asn     = 64513
      }
      bgp_session_range               = "169.254.2.2/30"
      peer_external_gateway_interface = 1
      shared_secret                   = "foo"
      vpn_gateway_interface           = 1
    }
  }
}
```

On peut y rajouter la création de VMs de test dans les VPC spokes, la mise en place du cloud NAT afin d'avoir une sortie internet sur nos VMs, les IPs de nos resolvers DNS ou encore privilégier un VPN entre le hub et les spokes, afin de garder la transitivité (le VPC A peut parler au VPC C au travers du VPC B), sans avoir à définir de règles de routage. Pour cela, ajouter les variables suivantes dans le fichier `terraform.tfvars` :

```HCL
# Permet la création d'un tunnel entre hub et spoke
spoke_configs = { vpn_configs = {} }

# Permet de mettre en place de DNS forwarding
dns = {
  resolvers = ["192.168.1.1","192.168.1.2"]
  enable_logging = true
}

# Créer des vms spot de test dans les VPC spoke et le hub
create_test_instances = false

# Permet d'obtenir internet sur les VMs qui n'ont pas d'ip externe
enable_cloud_nat = false
```

Si le terraform est appliqué, les subnets pour le hub et les spokes seront ceux définis dans les fichiers `data/subnets/dev` , `data/subnets/landing` et `data/subnets/prod`. Ne pas oublier de les adapter si nécessaire.

De plus, si des règles de firewall sont à définir directement dans les Shared VPC, il est possible d'utiliser les fichiers `data/firewall-rules/dev/rules.yaml`, `data/firewall-rules/landing/rules.yaml` et `data/firewall-rules/prod/rules.yaml`

Appliquer le terraform comme précédemment :

```HCL
terraform init
terraform plan
terraform apply
```

Notre landing zone est maintenant en place. Les comptes de service sont créés, les dossiers et le réseau fonctionnel. Il reste une partie intéressante de la fast fabric, nommée `project factory`. 

### 3-project-factory

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2024/07/Capture-d-e-cran-2024-07-16-a--08.56.58.png)

Project factory: créer ses dossiers et projets as code

Cette étape a pour but de créer l'arborescence des dossiers contenant les projets et de créer des projets avec l'automatisation et des paramètres prédéfinis, réduisant le risque d'erreur, tout en ayant l'ensemble as code. Comme chaque début de stage, on récupère les fichiers nécessaires

```bash
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/providers/3-project-factory-providers.tf ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/0-globals.auto.tfvars.json ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/0-bootstrap.auto.tfvars.json ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/1-resman.auto.tfvars.json ./
gcloud alpha storage cp gs://dom-prod-iac-core-outputs-0/tfvars/2-networking.auto.tfvars.json ./
```

Ce stage comporte seulement une variable `factories_config` à instancier dans le fichier `terraform.tfvars`, permettant de définir le chemin où se trouve les fichiers yaml. Un exemple est :

```HCL
factories_config = {
    hierarchy = {
      folders_data_path = "data/hierarchy"
      parent_ids = {
        default  =  "folders/1234567890"
      }
    }
    projects_data_path = "data/projects"
}

```

Pour créer l'arborescence `Dev/Application A/application-a-dev`, il faut donc créer le fichier `application-a-dev.yaml` dans le dossier `data/hierarachy/Dev/Application A/`. 

```application-a-dev.yaml
services:
  - compute.googleapis.com
  - storage.googleapis.com
  - datastream.googleapis.com
  - bigquery.googleapis.com

shared_vpc_service_config:
  host_project: dom-dev-net-spoke-0

labels:
  contact_primary: admin-domaine
  environment: dev
  workload: bigquery

iam:
  roles/compute.admin:
    - group:dom-grp-dev-admin@domaine.com
  roles/owner:
    - group:dom-grp-dev-appa-owner@domaine.com
```

Chaque dossier peut avoir ses propres droits IAM, en les définissant dans un fichier `_config.yaml`. Voici comment ajouter les droits en lecture au groupe `dom-grp-dev-reader` au dossier `dev` au travers de la création du fichier `data/hierarchy/dev/_config.yaml` 

```_config.yaml
name: Dev

iam:
  roles/viewer:
    - group:dom-grp-dev-reader@domaine.com
```

On peut maintenant appliquer notre terraform afin de créer les dossiers et le projet.

```bash
terraform init
terraform plan
terraform apply
```

## Conclusion

Il est facile de le coupler avec des outils tels que `Gitlab-CI` ou encore `GitHub Action` afin d'automatiser la création de nos ressources. Ceci pourra faire l'objet d'un autre article.

En résumé, cet outil est un ensemble de module Terraform permettant de créer une landing zone de zéro et en respectant les bonnes pratiques de Google. Bien sur, cette rapidité se troque contre la modularité. Beaucoup de paramètres sont à modifier dans les fichiers `.tf` si ceux par défaut ne conviennent pas aux besoins. Dans ce cas, il faudra prendre en main l'outil, ce qui est forcément plus compliqué qu'avec des modules que l'ont a développé, mais le jeu en vaut la chandelle 😄.