968 lines
No EOL
25 KiB
Markdown
968 lines
No EOL
25 KiB
Markdown
# Templates Ansible & Terraform - Nomenclature v2.0
|
|
# L'Alliance Boréale
|
|
#
|
|
# Version: 1.0
|
|
# Date: 21 octobre 2025
|
|
# Licence: AGPL-3.0
|
|
|
|
################################################################################
|
|
# PARTIE 1: TEMPLATES ANSIBLE
|
|
################################################################################
|
|
|
|
# ==============================================================================
|
|
# 1. Inventaire Dynamique Proxmox
|
|
# ==============================================================================
|
|
|
|
# inventory/proxmox.yml
|
|
---
|
|
plugin: community.general.proxmox
|
|
url: https://proxmox.example.com:8006
|
|
user: ansible@pve
|
|
password: !vault |
|
|
$ANSIBLE_VAULT;1.1;AES256
|
|
...
|
|
validate_certs: no
|
|
|
|
# Grouper automatiquement par tags
|
|
compose:
|
|
ansible_host: proxmox_ipconfig0.ip | regex_replace('/.*', '')
|
|
|
|
keyed_groups:
|
|
# Grouper par couche (infrastructure)
|
|
- prefix: layer
|
|
key: proxmox_tags | select('match', '^layer-[1-4]$') | first | default('unknown')
|
|
|
|
# Grouper par tenant
|
|
- prefix: tenant
|
|
key: proxmox_tags | select('match', '^tenant-t[0-9]{3}$') | first | default('none')
|
|
|
|
# Grouper par environnement
|
|
- prefix: env
|
|
key: proxmox_tags | select('match', '^(prod|stg|dev|test)$') | first | default('unknown')
|
|
|
|
# Grouper par catégorie
|
|
- prefix: category
|
|
key: proxmox_tags | select('match', '^(infrastructure|tenant)$') | first | default('unknown')
|
|
|
|
# ==============================================================================
|
|
# 2. Playbook de Création VM Infrastructure
|
|
# ==============================================================================
|
|
|
|
# playbooks/create-infra-vm.yml
|
|
---
|
|
- name: Créer VM Infrastructure selon nomenclature v2.0
|
|
hosts: localhost
|
|
gather_facts: no
|
|
|
|
vars_prompt:
|
|
- name: vm_layer
|
|
prompt: "Couche (1-4)"
|
|
private: no
|
|
|
|
- name: vm_type
|
|
prompt: "Type service (ex: 00=DNS, 10=VPN, 20=Git)"
|
|
private: no
|
|
|
|
- name: vm_instance
|
|
prompt: "Instance (01-99)"
|
|
private: no
|
|
|
|
- name: vm_service_name
|
|
prompt: "Nom du service (ex: dns-master, ansible-ctrl)"
|
|
private: no
|
|
|
|
- name: vm_environment
|
|
prompt: "Environnement (prod/stg/dev/test)"
|
|
private: no
|
|
default: "prod"
|
|
|
|
vars:
|
|
member_id: "{{ lookup('env', 'MEMBER_ID') | default('czp', true) }}"
|
|
|
|
# Calcul VMID
|
|
vmid: "{{ '%s%02d' | format(tenant_id, vm_instance|int) }}"
|
|
|
|
# Construction nom VM
|
|
vm_name: "{{ member_id }}-t{{ tenant_id }}-{{ vm_service_type }}-{{ vm_environment }}-{{ '%02d' | format(vm_instance|int) }}"
|
|
|
|
# Allocation IP (via script ou manuel)
|
|
vm_ip: "{{ lookup('pipe', 'allocate-ip.sh ' + tenant_id) | regex_search('\\d+\\.\\d+\\.\\d+\\.\\d+') }}"
|
|
|
|
# DNS
|
|
vm_dns: "{{ vm_service_type }}.t{{ tenant_id }}.{{ member_id }}.alliance-boreale.ca"
|
|
|
|
tasks:
|
|
- name: Afficher plan de création
|
|
debug:
|
|
msg:
|
|
- "VMID: {{ vmid }}"
|
|
- "Nom: {{ vm_name }}"
|
|
- "IP: {{ vm_ip }}/23"
|
|
- "DNS: {{ vm_dns }}"
|
|
- "Tenant: {{ tenant_id }}"
|
|
|
|
- name: Confirmer création
|
|
pause:
|
|
prompt: "Créer cette VM? (Ctrl+C pour annuler)"
|
|
|
|
- name: Créer VM dans Proxmox
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_host }}"
|
|
api_user: "{{ proxmox_user }}"
|
|
api_password: "{{ proxmox_password }}"
|
|
node: "{{ proxmox_node }}"
|
|
|
|
vmid: "{{ vmid }}"
|
|
name: "{{ vm_name }}"
|
|
|
|
clone: "{{ vm_template | default('debian-12-template') }}"
|
|
full: yes
|
|
|
|
cores: "{{ vm_cores | default(2) }}"
|
|
memory: "{{ vm_memory | default(2048) }}"
|
|
|
|
net:
|
|
net0: "virtio,bridge=vmbr0,tag=10"
|
|
|
|
ipconfig:
|
|
ipconfig0: "ip={{ vm_ip }}/23,gw=10.0.0.1"
|
|
|
|
tags:
|
|
- tenant
|
|
- "tenant-t{{ tenant_id }}"
|
|
- "{{ vm_environment }}"
|
|
- "service-{{ vm_service_type }}"
|
|
|
|
state: present
|
|
|
|
- name: Enregistrer IP dans IPAM
|
|
ansible.builtin.lineinfile:
|
|
path: "/etc/alliance-boreale/ipam.txt"
|
|
line: "{{ tenant_id }} {{ vm_ip }} {{ ansible_date_time.date }} {{ vmid }}"
|
|
create: yes
|
|
|
|
- name: Créer entrée DNS
|
|
ansible.builtin.lineinfile:
|
|
path: "/var/lib/alliance-boreale/dns-records.zone"
|
|
line: "{{ vm_dns }}. IN A {{ vm_ip }}"
|
|
delegate_to: "{{ dns_master_host }}"
|
|
|
|
- name: Démarrer la VM
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_host }}"
|
|
api_user: "{{ proxmox_user }}"
|
|
api_password: "{{ proxmox_password }}"
|
|
vmid: "{{ vmid }}"
|
|
state: started
|
|
|
|
# ==============================================================================
|
|
# 4. Role Ansible - Conformité Nomenclature
|
|
# ==============================================================================
|
|
|
|
# roles/nomenclature_compliance/tasks/main.yml
|
|
---
|
|
- name: Vérifier que le VMID est conforme
|
|
ansible.builtin.assert:
|
|
that:
|
|
- inventory_hostname_short | regex_search('^[a-z]+-((infra)|(t[0-9]{3}))-')
|
|
fail_msg: "Nom VM non conforme au standard v2.0"
|
|
success_msg: "Nom VM conforme"
|
|
|
|
- name: Extraire les informations de nomenclature
|
|
ansible.builtin.set_fact:
|
|
vm_member: "{{ inventory_hostname_short | regex_replace('^([a-z]+)-.*', '\\1') }}"
|
|
vm_category: "{{ 'infrastructure' if 'infra' in inventory_hostname_short else 'tenant' }}"
|
|
vm_tenant_id: "{{ inventory_hostname_short | regex_replace('.*-(t[0-9]{3})-.*', '\\1') if 'infra' not in inventory_hostname_short else 'N/A' }}"
|
|
|
|
- name: Afficher informations extraites
|
|
debug:
|
|
msg:
|
|
- "Membre: {{ vm_member }}"
|
|
- "Catégorie: {{ vm_category }}"
|
|
- "Tenant: {{ vm_tenant_id }}"
|
|
|
|
- name: Vérifier cohérence IP
|
|
ansible.builtin.assert:
|
|
that:
|
|
- ansible_default_ipv4.address | regex_search('^10\\.0\\.')
|
|
fail_msg: "IP hors de la plage 10.0.0.0/8"
|
|
success_msg: "IP dans la plage correcte"
|
|
|
|
- name: Appliquer tags de conformité
|
|
ansible.builtin.set_fact:
|
|
nomenclature_compliant: true
|
|
nomenclature_version: "v2.0"
|
|
nomenclature_validated_date: "{{ ansible_date_time.iso8601 }}"
|
|
|
|
# ==============================================================================
|
|
# 5. Playbook d'Audit Ansible
|
|
# ==============================================================================
|
|
|
|
# playbooks/audit-nomenclature-ansible.yml
|
|
---
|
|
- name: Audit de conformité Nomenclature v2.0 via Ansible
|
|
hosts: all
|
|
gather_facts: yes
|
|
|
|
tasks:
|
|
- name: Vérifier nom VM
|
|
ansible.builtin.set_fact:
|
|
name_compliant: "{{ inventory_hostname_short | regex_search('^[a-z]+-(infra|t[0-9]{3})-[a-z0-9-]+-[a-z]+-[0-9]{2}
|
|
|
|
vars:
|
|
member_id: "{{ lookup('env', 'MEMBER_ID') | default('czp', true) }}"
|
|
|
|
# Calcul VMID
|
|
vmid: "{{ '0%s%02d%02d' | format(vm_layer, vm_type|int, vm_instance|int) }}"
|
|
|
|
# Construction nom VM
|
|
vm_name: "{{ member_id }}-infra-{{ vm_service_name }}-{{ vm_environment }}-{{ '%02d' | format(vm_instance|int) }}"
|
|
|
|
# Calcul IP selon couche
|
|
vm_ip: >-
|
|
{{
|
|
('10.0.0.' if vm_layer == '1' else
|
|
'10.0.1.' if vm_layer == '4' else
|
|
'10.0.2.' if vm_layer == '2' else
|
|
'10.0.3.') + (vm_type|int * 10 + vm_instance|int)|string
|
|
}}
|
|
|
|
# DNS
|
|
vm_dns: "{{ vm_service_name }}.infra.{{ member_id }}.alliance-boreale.ca"
|
|
|
|
tasks:
|
|
- name: Afficher plan de création
|
|
debug:
|
|
msg:
|
|
- "VMID: {{ vmid }}"
|
|
- "Nom: {{ vm_name }}"
|
|
- "IP: {{ vm_ip }}/24"
|
|
- "DNS: {{ vm_dns }}"
|
|
|
|
- name: Confirmer création
|
|
pause:
|
|
prompt: "Créer cette VM? (Ctrl+C pour annuler, Entrée pour continuer)"
|
|
|
|
- name: Créer VM dans Proxmox
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_host }}"
|
|
api_user: "{{ proxmox_user }}"
|
|
api_password: "{{ proxmox_password }}"
|
|
node: "{{ proxmox_node }}"
|
|
|
|
vmid: "{{ vmid }}"
|
|
name: "{{ vm_name }}"
|
|
|
|
clone: "debian-12-template"
|
|
full: yes
|
|
|
|
cores: 2
|
|
memory: 2048
|
|
|
|
net:
|
|
net0: "virtio,bridge=vmbr0,tag={{ '2' if vm_layer == '2' else '1' }}"
|
|
|
|
ipconfig:
|
|
ipconfig0: "ip={{ vm_ip }}/24,gw=10.0.0.1"
|
|
|
|
tags:
|
|
- infrastructure
|
|
- "layer-{{ vm_layer }}"
|
|
- "{{ vm_environment }}"
|
|
- "service-{{ vm_service_name }}"
|
|
|
|
state: present
|
|
register: vm_created
|
|
|
|
- name: Démarrer la VM
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_host }}"
|
|
api_user: "{{ proxmox_user }}"
|
|
api_password: "{{ proxmox_password }}"
|
|
vmid: "{{ vmid }}"
|
|
state: started
|
|
|
|
- name: Créer entrée DNS
|
|
ansible.builtin.lineinfile:
|
|
path: "/var/lib/alliance-boreale/dns-records.zone"
|
|
line: "{{ vm_dns }}. IN A {{ vm_ip }}"
|
|
create: yes
|
|
delegate_to: "{{ dns_master_host }}"
|
|
|
|
- name: Ajouter au monitoring
|
|
ansible.builtin.template:
|
|
src: templates/icinga2-host.conf.j2
|
|
dest: "/etc/icinga2/conf.d/hosts/{{ vm_name }}.conf"
|
|
delegate_to: "{{ monitoring_host }}"
|
|
notify: Reload Icinga2
|
|
|
|
# ==============================================================================
|
|
# 3. Playbook de Création VM Tenant
|
|
# ==============================================================================
|
|
|
|
# playbooks/create-tenant-vm.yml
|
|
---
|
|
- name: Créer VM Tenant selon nomenclature v2.0
|
|
hosts: localhost
|
|
gather_facts: no
|
|
|
|
vars_prompt:
|
|
- name: tenant_id
|
|
prompt: "Tenant ID (001-999)"
|
|
private: no
|
|
|
|
- name: vm_instance
|
|
prompt: "Instance (01-99)"
|
|
private: no
|
|
|
|
- name: vm_service_type
|
|
prompt: "Type (web/api/db/cache/worker)"
|
|
private: no
|
|
|
|
- name: vm_environment
|
|
prompt: "Environnement (prod/stg/dev) is not none }}"
|
|
|
|
- name: Vérifier IP dans plage correcte
|
|
ansible.builtin.set_fact:
|
|
ip_compliant: "{{ ansible_default_ipv4.address | regex_search('^10\\.0\\.') is not none }}"
|
|
|
|
- name: Extraire VMID si possible
|
|
ansible.builtin.shell: |
|
|
qm list | awk -v host="{{ inventory_hostname_short }}" '$2 == host {print $1}'
|
|
register: vmid_check
|
|
delegate_to: "{{ proxmox_node }}"
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Valider VMID
|
|
ansible.builtin.command: validate-vmid.sh {{ vmid_check.stdout }}
|
|
register: vmid_validation
|
|
delegate_to: localhost
|
|
changed_when: false
|
|
failed_when: false
|
|
when: vmid_check.stdout != ""
|
|
|
|
- name: Générer rapport
|
|
ansible.builtin.set_fact:
|
|
compliance_report:
|
|
hostname: "{{ inventory_hostname }}"
|
|
name_compliant: "{{ name_compliant }}"
|
|
ip_compliant: "{{ ip_compliant }}"
|
|
vmid: "{{ vmid_check.stdout | default('N/A') }}"
|
|
vmid_compliant: "{{ vmid_validation.rc == 0 if vmid_check.stdout != '' else false }}"
|
|
overall_compliant: "{{ name_compliant and ip_compliant and (vmid_validation.rc == 0 if vmid_check.stdout != '' else false) }}"
|
|
|
|
- name: Afficher résultat
|
|
ansible.builtin.debug:
|
|
var: compliance_report
|
|
|
|
- name: Sauvegarder rapport
|
|
ansible.builtin.copy:
|
|
content: "{{ compliance_report | to_nice_json }}"
|
|
dest: "/var/lib/alliance-boreale/compliance/{{ inventory_hostname }}.json"
|
|
delegate_to: localhost
|
|
|
|
################################################################################
|
|
# PARTIE 2: TEMPLATES TERRAFORM
|
|
################################################################################
|
|
|
|
# ==============================================================================
|
|
# 6. Module Terraform - VM Infrastructure
|
|
# ==============================================================================
|
|
|
|
# modules/infra-vm/main.tf
|
|
terraform {
|
|
required_providers {
|
|
proxmox = {
|
|
source = "telmate/proxmox"
|
|
version = "~> 2.9"
|
|
}
|
|
}
|
|
}
|
|
|
|
variable "member_id" {
|
|
description = "ID du membre (ex: czp, nul, tli)"
|
|
type = string
|
|
}
|
|
|
|
variable "layer" {
|
|
description = "Couche (1-4)"
|
|
type = number
|
|
validation {
|
|
condition = var.layer >= 1 && var.layer <= 4
|
|
error_message = "La couche doit être entre 1 et 4."
|
|
}
|
|
}
|
|
|
|
variable "service_type" {
|
|
description = "Type de service (00-99)"
|
|
type = number
|
|
}
|
|
|
|
variable "instance" {
|
|
description = "Numéro d'instance (01-99)"
|
|
type = number
|
|
}
|
|
|
|
variable "service_name" {
|
|
description = "Nom du service (ex: dns-master, ansible-ctrl)"
|
|
type = string
|
|
}
|
|
|
|
variable "environment" {
|
|
description = "Environnement (prod/stg/dev/test)"
|
|
type = string
|
|
default = "prod"
|
|
}
|
|
|
|
variable "cores" {
|
|
description = "Nombre de CPU cores"
|
|
type = number
|
|
default = 2
|
|
}
|
|
|
|
variable "memory" {
|
|
description = "RAM en MB"
|
|
type = number
|
|
default = 2048
|
|
}
|
|
|
|
variable "disk_size" {
|
|
description = "Taille disque en GB"
|
|
type = string
|
|
default = "20G"
|
|
}
|
|
|
|
# Calculs locaux
|
|
locals {
|
|
# VMID: 0CTTII
|
|
vmid = format("0%d%02d%02d", var.layer, var.service_type, var.instance)
|
|
|
|
# Nom VM: <membre>-infra-<type>-<env>-<instance>
|
|
vm_name = format("%s-infra-%s-%s-%02d",
|
|
var.member_id,
|
|
var.service_name,
|
|
var.environment,
|
|
var.instance
|
|
)
|
|
|
|
# IP selon couche
|
|
ip_base = var.layer == 1 ? "10.0.0" : (
|
|
var.layer == 2 ? "10.0.2" : (
|
|
var.layer == 3 ? "10.0.3" : "10.0.1"))
|
|
|
|
vm_ip = format("%s.%d", local.ip_base, var.service_type * 10 + var.instance)
|
|
|
|
# DNS
|
|
vm_dns = format("%s.infra.%s.alliance-boreale.ca",
|
|
var.service_name,
|
|
var.member_id
|
|
)
|
|
}
|
|
|
|
resource "proxmox_vm_qemu" "infra_vm" {
|
|
name = local.vm_name
|
|
vmid = local.vmid
|
|
target_node = var.proxmox_node
|
|
|
|
clone = "debian-12-template"
|
|
full_clone = true
|
|
|
|
cores = var.cores
|
|
memory = var.memory
|
|
|
|
network {
|
|
model = "virtio"
|
|
bridge = "vmbr0"
|
|
tag = var.layer == 2 ? 2 : 1
|
|
}
|
|
|
|
disk {
|
|
type = "scsi"
|
|
storage = "local-lvm"
|
|
size = var.disk_size
|
|
}
|
|
|
|
ipconfig0 = "ip=${local.vm_ip}/24,gw=10.0.0.1"
|
|
|
|
tags = join(";", [
|
|
"infrastructure",
|
|
"layer-${var.layer}",
|
|
var.environment,
|
|
"service-${var.service_name}",
|
|
"nomenclature-v2"
|
|
])
|
|
|
|
lifecycle {
|
|
ignore_changes = [
|
|
network,
|
|
]
|
|
}
|
|
}
|
|
|
|
output "vmid" {
|
|
value = local.vmid
|
|
}
|
|
|
|
output "vm_name" {
|
|
value = local.vm_name
|
|
}
|
|
|
|
output "vm_ip" {
|
|
value = local.vm_ip
|
|
}
|
|
|
|
output "vm_dns" {
|
|
value = local.vm_dns
|
|
}
|
|
|
|
# ==============================================================================
|
|
# 7. Module Terraform - VM Tenant
|
|
# ==============================================================================
|
|
|
|
# modules/tenant-vm/main.tf
|
|
terraform {
|
|
required_providers {
|
|
proxmox = {
|
|
source = "telmate/proxmox"
|
|
version = "~> 2.9"
|
|
}
|
|
}
|
|
}
|
|
|
|
variable "member_id" {
|
|
description = "ID du membre"
|
|
type = string
|
|
}
|
|
|
|
variable "tenant_id" {
|
|
description = "Tenant ID (001-999)"
|
|
type = string
|
|
validation {
|
|
condition = can(regex("^[0-9]{3}$", var.tenant_id))
|
|
error_message = "Tenant ID doit être au format NNN (ex: 001)."
|
|
}
|
|
}
|
|
|
|
variable "instance" {
|
|
description = "Numéro d'instance (01-99)"
|
|
type = number
|
|
}
|
|
|
|
variable "service_type" {
|
|
description = "Type de service (web/api/db/cache/worker)"
|
|
type = string
|
|
}
|
|
|
|
variable "environment" {
|
|
description = "Environnement"
|
|
type = string
|
|
default = "prod"
|
|
}
|
|
|
|
variable "ip_address" {
|
|
description = "Adresse IP (optionnel, auto-alloué si vide)"
|
|
type = string
|
|
default = ""
|
|
}
|
|
|
|
variable "cores" {
|
|
type = number
|
|
default = 2
|
|
}
|
|
|
|
variable "memory" {
|
|
type = number
|
|
default = 2048
|
|
}
|
|
|
|
locals {
|
|
# VMID: TTTII
|
|
vmid = format("%s%02d", var.tenant_id, var.instance)
|
|
|
|
# Nom VM
|
|
vm_name = format("%s-t%s-%s-%s-%02d",
|
|
var.member_id,
|
|
var.tenant_id,
|
|
var.service_type,
|
|
var.environment,
|
|
var.instance
|
|
)
|
|
|
|
# IP (utiliser celle fournie ou calculer)
|
|
vm_ip = var.ip_address != "" ? var.ip_address : format("10.0.10.%d",
|
|
(tonumber(var.tenant_id) - 1) * 10 + var.instance
|
|
)
|
|
|
|
# DNS
|
|
vm_dns = format("%s.t%s.%s.alliance-boreale.ca",
|
|
var.service_type,
|
|
var.tenant_id,
|
|
var.member_id
|
|
)
|
|
}
|
|
|
|
resource "proxmox_vm_qemu" "tenant_vm" {
|
|
name = local.vm_name
|
|
vmid = local.vmid
|
|
target_node = var.proxmox_node
|
|
|
|
clone = var.vm_template
|
|
full_clone = true
|
|
|
|
cores = var.cores
|
|
memory = var.memory
|
|
|
|
network {
|
|
model = "virtio"
|
|
bridge = "vmbr0"
|
|
tag = 10
|
|
}
|
|
|
|
disk {
|
|
type = "scsi"
|
|
storage = "local-lvm"
|
|
size = var.disk_size
|
|
}
|
|
|
|
ipconfig0 = "ip=${local.vm_ip}/23,gw=10.0.0.1"
|
|
|
|
tags = join(";", [
|
|
"tenant",
|
|
"tenant-t${var.tenant_id}",
|
|
var.environment,
|
|
"service-${var.service_type}",
|
|
"nomenclature-v2"
|
|
])
|
|
}
|
|
|
|
# Enregistrer dans IPAM
|
|
resource "null_resource" "register_ipam" {
|
|
provisioner "local-exec" {
|
|
command = "echo '${var.tenant_id} ${local.vm_ip} ${timestamp()} ${local.vmid}' >> /etc/alliance-boreale/ipam.txt"
|
|
}
|
|
|
|
depends_on = [proxmox_vm_qemu.tenant_vm]
|
|
}
|
|
|
|
output "vmid" {
|
|
value = local.vmid
|
|
}
|
|
|
|
output "vm_name" {
|
|
value = local.vm_name
|
|
}
|
|
|
|
output "vm_ip" {
|
|
value = local.vm_ip
|
|
}
|
|
|
|
output "vm_dns" {
|
|
value = local.vm_dns
|
|
}
|
|
|
|
# ==============================================================================
|
|
# 8. Exemple d'Utilisation Terraform
|
|
# ==============================================================================
|
|
|
|
# main.tf - Exemple de déploiement complet
|
|
terraform {
|
|
required_version = ">= 1.0"
|
|
|
|
required_providers {
|
|
proxmox = {
|
|
source = "telmate/proxmox"
|
|
version = "~> 2.9"
|
|
}
|
|
}
|
|
}
|
|
|
|
provider "proxmox" {
|
|
pm_api_url = var.proxmox_api_url
|
|
pm_user = var.proxmox_user
|
|
pm_password = var.proxmox_password
|
|
pm_tls_insecure = true
|
|
}
|
|
|
|
variable "proxmox_api_url" {}
|
|
variable "proxmox_user" {}
|
|
variable "proxmox_password" {}
|
|
variable "proxmox_node" { default = "pve1" }
|
|
variable "member_id" { default = "czp" }
|
|
|
|
# Infrastructure minimale Bronze
|
|
module "dns_master" {
|
|
source = "./modules/infra-vm"
|
|
|
|
member_id = var.member_id
|
|
layer = 2
|
|
service_type = 0 # DNS
|
|
instance = 1
|
|
service_name = "dns-master"
|
|
|
|
cores = 2
|
|
memory = 4096
|
|
}
|
|
|
|
module "ansible_controller" {
|
|
source = "./modules/infra-vm"
|
|
|
|
member_id = var.member_id
|
|
layer = 4
|
|
service_type = 0 # Ansible
|
|
instance = 1
|
|
service_name = "ansible-ctrl"
|
|
}
|
|
|
|
module "backup_server" {
|
|
source = "./modules/infra-vm"
|
|
|
|
member_id = var.member_id
|
|
layer = 3
|
|
service_type = 30 # Backup
|
|
instance = 1
|
|
service_name = "pbs-backup"
|
|
|
|
cores = 4
|
|
memory = 8192
|
|
disk_size = "500G"
|
|
}
|
|
|
|
# Premier tenant - Stack complète
|
|
module "tenant001_web" {
|
|
source = "./modules/tenant-vm"
|
|
|
|
member_id = var.member_id
|
|
tenant_id = "001"
|
|
instance = 1
|
|
service_type = "web"
|
|
}
|
|
|
|
module "tenant001_api" {
|
|
source = "./modules/tenant-vm"
|
|
|
|
member_id = var.member_id
|
|
tenant_id = "001"
|
|
instance = 11
|
|
service_type = "api-fastapi"
|
|
}
|
|
|
|
module "tenant001_db" {
|
|
source = "./modules/tenant-vm"
|
|
|
|
member_id = var.member_id
|
|
tenant_id = "001"
|
|
instance = 21
|
|
service_type = "db-postgres"
|
|
|
|
cores = 4
|
|
memory = 8192
|
|
}
|
|
|
|
# Outputs
|
|
output "infrastructure" {
|
|
value = {
|
|
dns_master = {
|
|
vmid = module.dns_master.vmid
|
|
name = module.dns_master.vm_name
|
|
ip = module.dns_master.vm_ip
|
|
dns = module.dns_master.vm_dns
|
|
}
|
|
ansible = {
|
|
vmid = module.ansible_controller.vmid
|
|
name = module.ansible_controller.vm_name
|
|
ip = module.ansible_controller.vm_ip
|
|
dns = module.ansible_controller.vm_dns
|
|
}
|
|
}
|
|
}
|
|
|
|
output "tenant_001" {
|
|
value = {
|
|
web = module.tenant001_web
|
|
api = module.tenant001_api
|
|
db = module.tenant001_db
|
|
}
|
|
}
|
|
|
|
# ==============================================================================
|
|
# 9. Variables Terraform
|
|
# ==============================================================================
|
|
|
|
# variables.tf
|
|
variable "member_id" {
|
|
description = "ID du membre de L'Alliance Boréale"
|
|
type = string
|
|
|
|
validation {
|
|
condition = can(regex("^[a-z]{2,4}$", var.member_id))
|
|
error_message = "member_id doit être 2-4 lettres minuscules."
|
|
}
|
|
}
|
|
|
|
variable "proxmox_node" {
|
|
description = "Nœud Proxmox cible"
|
|
type = string
|
|
default = "pve1"
|
|
}
|
|
|
|
variable "dns_domain" {
|
|
description = "Domaine DNS de L'Alliance"
|
|
type = string
|
|
default = "alliance-boreale.ca"
|
|
}
|
|
|
|
variable "vm_template" {
|
|
description = "Template VM par défaut"
|
|
type = string
|
|
default = "debian-12-template"
|
|
}
|
|
|
|
# ==============================================================================
|
|
# 10. Makefile pour Automatisation
|
|
# ==============================================================================
|
|
|
|
# Makefile
|
|
.PHONY: help audit migrate plan apply destroy
|
|
|
|
help:
|
|
@echo "Commandes disponibles:"
|
|
@echo " make audit - Audit de conformité"
|
|
@echo " make plan - Plan Terraform"
|
|
@echo " make apply - Appliquer Terraform"
|
|
@echo " make destroy - Détruire infrastructure Terraform"
|
|
@echo " make ansible - Exécuter playbooks Ansible"
|
|
|
|
audit:
|
|
@echo "=== Audit Nomenclature v2.0 ==="
|
|
audit-nomenclature.sh
|
|
ansible-playbook playbooks/audit-nomenclature-ansible.yml
|
|
|
|
plan:
|
|
terraform plan -out=tfplan
|
|
|
|
apply:
|
|
terraform apply tfplan
|
|
|
|
destroy:
|
|
terraform destroy
|
|
|
|
ansible:
|
|
ansible-playbook playbooks/configure-all.yml -i inventory/proxmox.yml
|
|
|
|
# ==============================================================================
|
|
# FIN DES TEMPLATES
|
|
# ==============================================================================
|
|
|
|
vars:
|
|
member_id: "{{ lookup('env', 'MEMBER_ID') | default('czp', true) }}"
|
|
|
|
# Calcul VMID
|
|
vmid: "{{ '0%s%02d%02d' | format(vm_layer, vm_type|int, vm_instance|int) }}"
|
|
|
|
# Construction nom VM
|
|
vm_name: "{{ member_id }}-infra-{{ vm_service_name }}-{{ vm_environment }}-{{ '%02d' | format(vm_instance|int) }}"
|
|
|
|
# Calcul IP selon couche
|
|
vm_ip: >-
|
|
{{
|
|
('10.0.0.' if vm_layer == '1' else
|
|
'10.0.1.' if vm_layer == '4' else
|
|
'10.0.2.' if vm_layer == '2' else
|
|
'10.0.3.') + (vm_type|int * 10 + vm_instance|int)|string
|
|
}}
|
|
|
|
# DNS
|
|
vm_dns: "{{ vm_service_name }}.infra.{{ member_id }}.alliance-boreale.ca"
|
|
|
|
tasks:
|
|
- name: Afficher plan de création
|
|
debug:
|
|
msg:
|
|
- "VMID: {{ vmid }}"
|
|
- "Nom: {{ vm_name }}"
|
|
- "IP: {{ vm_ip }}/24"
|
|
- "DNS: {{ vm_dns }}"
|
|
|
|
- name: Confirmer création
|
|
pause:
|
|
prompt: "Créer cette VM? (Ctrl+C pour annuler, Entrée pour continuer)"
|
|
|
|
- name: Créer VM dans Proxmox
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_host }}"
|
|
api_user: "{{ proxmox_user }}"
|
|
api_password: "{{ proxmox_password }}"
|
|
node: "{{ proxmox_node }}"
|
|
|
|
vmid: "{{ vmid }}"
|
|
name: "{{ vm_name }}"
|
|
|
|
clone: "debian-12-template"
|
|
full: yes
|
|
|
|
cores: 2
|
|
memory: 2048
|
|
|
|
net:
|
|
net0: "virtio,bridge=vmbr0,tag={{ '2' if vm_layer == '2' else '1' }}"
|
|
|
|
ipconfig:
|
|
ipconfig0: "ip={{ vm_ip }}/24,gw=10.0.0.1"
|
|
|
|
tags:
|
|
- infrastructure
|
|
- "layer-{{ vm_layer }}"
|
|
- "{{ vm_environment }}"
|
|
- "service-{{ vm_service_name }}"
|
|
|
|
state: present
|
|
register: vm_created
|
|
|
|
- name: Démarrer la VM
|
|
community.general.proxmox_kvm:
|
|
api_host: "{{ proxmox_host }}"
|
|
api_user: "{{ proxmox_user }}"
|
|
api_password: "{{ proxmox_password }}"
|
|
vmid: "{{ vmid }}"
|
|
state: started
|
|
|
|
- name: Créer entrée DNS
|
|
ansible.builtin.lineinfile:
|
|
path: "/var/lib/alliance-boreale/dns-records.zone"
|
|
line: "{{ vm_dns }}. IN A {{ vm_ip }}"
|
|
create: yes
|
|
delegate_to: "{{ dns_master_host }}"
|
|
|
|
- name: Ajouter au monitoring
|
|
ansible.builtin.template:
|
|
src: templates/icinga2-host.conf.j2
|
|
dest: "/etc/icinga2/conf.d/hosts/{{ vm_name }}.conf"
|
|
delegate_to: "{{ monitoring_host }}"
|
|
notify: Reload Icinga2
|
|
|
|
# ==============================================================================
|
|
# 3. Playbook de Création VM Tenant
|
|
# ==============================================================================
|
|
|
|
# playbooks/create-tenant-vm.yml
|
|
---
|
|
- name: Créer VM Tenant selon nomenclature v2.0
|
|
hosts: localhost
|
|
gather_facts: no
|
|
|
|
vars_prompt:
|
|
- name: tenant_id
|
|
prompt: "Tenant ID (001-999)"
|
|
private: no
|
|
|
|
- name: vm_instance
|
|
prompt: "Instance (01-99)"
|
|
private: no
|
|
|
|
- name: vm_service_type
|
|
prompt: "Type (web/api/db/cache/worker)"
|
|
private: no
|
|
|
|
- name: vm_environment
|
|
prompt: "Environnement (prod/stg/dev |