Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
5.9 KiB
02 — Provisioning Hetzner
Durée : environ 1 h. Création des serveurs, du réseau privé, des firewalls et du volume de données, entièrement décrite en Terraform.
Le fichier de prévisions de coûts note explicitement le risque « bus factor DevOps — Terraform/IaC obligatoire ». C'est la raison d'être de ce dossier : l'infrastructure est reconstructible par quelqu'un d'autre, à partir du dépôt seul.
1. Token API Hetzner
Console Hetzner → projet xpeditis-prod → Security → API tokens →
Generate API token.
- Description :
terraform-prod - Permissions : Read & Write
Le token n'est affiché qu'une fois. Copiez-le dans votre gestionnaire de mots de passe immédiatement.
Créez un second token nommé github-actions-cicd, également Read & Write.
Il servira uniquement au firewall temporaire de la CI, ce qui permet de le
révoquer sans casser Terraform.
2. Configuration
cd infra/prod/terraform
cp terraform.tfvars.example terraform.tfvars
$EDITOR terraform.tfvars
À renseigner :
hcloud_token = "<token terraform-prod>"
ssh_public_key = "ssh-ed25519 AAAA... xpeditis-prod-admin" # cat ~/.ssh/xpeditis_prod.pub
admin_ip_allowlist = ["<votre IP>/32"] # curl -s https://ifconfig.me
Le reste des valeurs par défaut correspond au dimensionnement de la phase 1 :
cpx41 pour l'application, cpx31 pour les données, volume de 50 Go,
sauvegardes Hetzner activées.
terraform.tfvarsest ignoré par Git (infra/prod/.gitignore). Vérifiez-le avant tout commit :git statusne doit pas le mentionner.
3. Vérifier avant d'appliquer
make -C .. tf-init # ou : terraform init
make -C .. tf-plan # ou : terraform plan
Le plan doit annoncer 8 ressources à créer :
hcloud_network.main
hcloud_network_subnet.main
hcloud_ssh_key.admin
hcloud_placement_group.spread
hcloud_firewall.app
hcloud_firewall.db
hcloud_firewall.cicd
hcloud_server.app
hcloud_server.db
hcloud_volume.pgdata
Trois points à relire dans le plan :
hcloud_firewall.app— les règles 22 et 6443 portent uniquement votre IP. Si vous y voyez0.0.0.0/0, arrêtez tout.hcloud_firewall.db— seul le port 22 est ouvert. Ni 5432, ni 6379.hcloud_firewall.cicd— aucune règle. C'est normal : la CI les injecte puis les retire.
4. Appliquer
make -C .. tf-apply
Environ 90 secondes. Puis :
terraform output
Notez précieusement :
app_public_ipv4 = "..." → tous les enregistrements DNS Cloudflare
db_public_ipv4 = "..." → SSH d'administration UNIQUEMENT, jamais en DNS
db_private_ip = "10.10.1.20"
pgdata_volume_device = "/dev/disk/by-id/scsi-0HC_Volume_..."
5. Vérifier l'accès
ssh -i ~/.ssh/xpeditis_prod deploy@<app_public_ipv4> 'hostname; uptime'
ssh -i ~/.ssh/xpeditis_prod deploy@<db_public_ipv4> 'hostname; uptime'
cloud-init met une à deux minutes après la création du serveur. Si la connexion est refusée, attendez puis vérifiez :
ssh -i ~/.ssh/xpeditis_prod deploy@<ip> 'ls -l /var/log/cloud-init-xpeditis-done'
Le réseau privé doit fonctionner dans les deux sens :
ssh deploy@<app_public_ipv4> 'ping -c2 10.10.1.20'
6. Confirmer que la base est bien inaccessible
Depuis un autre réseau que votre IP d'administration (partage de connexion mobile, par exemple) :
nmap -Pn -p 22,80,443,5432,6379,6443 <db_public_ipv4>
Attendu : tous les ports filtered, y compris le 22 — puisque vous testez
depuis une IP non autorisée.
nmap -Pn -p 22,80,443,5432,6379,6443 <app_public_ipv4>
Attendu à ce stade : 80 et 443 ouverts uniquement si
restrict_http_to_cloudflare = false. Avec la valeur par défaut true, ils
apparaissent aussi filtered tant que la requête ne vient pas de Cloudflare —
c'est exactement l'effet recherché.
7. Storage Box
La Storage Box se commande séparément (Robot Hetzner, pas la console Cloud).
- Commandez une BX11 (1 To, 3,90 €/mois).
- Dans son interface : activez SSH et désactivez Samba/CIFS et WebDAV, inutiles ici et exposés sur Internet.
- Déposez la clé publique dédiée :
# Depuis votre poste
ssh-copy-id -p 23 -i ~/.ssh/xpeditis_storagebox.pub uXXXXXX@uXXXXXX.your-storagebox.de
# Créez l'arborescence
ssh -p 23 -i ~/.ssh/xpeditis_storagebox uXXXXXX@uXXXXXX.your-storagebox.de \
'mkdir -p xpeditis-prod/dumps'
La clé privée correspondante devra être déposée sur db-01 en
/root/.ssh/storagebox (04 — Nœud de données).
Activez les snapshots de la Storage Box (gratuits, dans son interface). Ils protègent contre le cas où un rançongiciel présent sur db-01 chiffrerait ou effacerait aussi les sauvegardes distantes via la connexion SSH existante.
8. Sauvegarder l'état Terraform
terraform.tfstate décrit toute votre infrastructure. Il est gitignoré à
dessein (il contient des données sensibles), mais le perdre signifie que
Terraform ne reconnaîtra plus vos ressources et proposera de tout recréer.
# Sauvegarde chiffrée dans le dépôt
sops -e terraform.tfstate > ../terraform-state-backup.sops.json
Ou, mieux, migrez vers un backend S3 sur Hetzner Object Storage : le bloc
backend "s3" est prêt, en commentaire, dans versions.tf.
9. Contrôle
[ ] terraform apply passé sans erreur
[ ] SSH fonctionne sur app-01 et db-01 avec la clé d'administration
[ ] Le ping app-01 → 10.10.1.20 répond
[ ] nmap depuis une IP non autorisée : tout est filtered
[ ] Storage Box commandée, SSH activé, Samba/WebDAV désactivés
[ ] Snapshots de la Storage Box activés
[ ] État Terraform sauvegardé
[ ] Les deux IP publiques notées dans le gestionnaire de mots de passe
→ Suite : 03 — Durcissement des serveurs