Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Une Graine est une plateforme de tests, d’exploration et de partage entre passionnés et anciens collègues.

Rien n’est parfait et tout nous pousse vers toujours plus de compréhension, de maîtrise, d’expertise dans différents domaines et contextes.

Les choix sont très souvents expliqués ou même documentés.

Ce book est commun et chacun est libre de l’éditer. Il est généré à l’aide de mdBook.

Projet Graine

Les sources du projet Graine sont disponibles ici.

Vous pouvez lire l’ensemble des pages suivantes si vous souhaitez vous servir des sources pour vos propres besoins, ou par plaisir 🤓

Providers

Une Graine est hébergé sur les datacenters européens du provider Hetzner et utilise les services de 1Password, Gandi, Posteo et Let’s Encrypt.

Ces choix sont expliqués dans les pages suivantes.

op_hetzner_worker

1Password

Ce service est utilisé pour:

  • stocker des secrets
  • alimenter les données sensibles IaC
  • alimenter les objets Secrets du cluster via l’opérateur 1Password Connect

Le coût pour un compte individuel est de 38,16€ TTC par an.

Choix

1Password est retenu comme gestionnaire de secrets pour les raisons suivantes:

Les +

  • expérience globale:
    • génération de mot de passe / passphrase complexe
    • ACL sur les coffres
    • le CLI est utile sur plusieurs niveaux (local et CI/CD par exemple)
    • le coût annuel du premier forfait est bien plus raisonnable comparé à d’autres solutions
  • expérience personnelle
    • gestion des MFA
    • intégration avec le navigateur
  • expérience professionelle
    • facilite l’expérience local
    • possibilité de n’avoir aucuns secrets stockés en local (dans un dotenv par exemple)
    • intégration kubernetes simple et performante

Les -

  • pas de relation entre les objets
    • on peut les référencer mais l’injection ne prend pas encore en charge les références
  • la recherche n’est pas précise
    • si vous cherchez un secret par un mot ou un ensemble de mots stricts, il n’est pas certain que vous trouviez une correspondance
    • il est donc nécessaire d’utiliser toutes les fonctions d’un objet, comme les tags, et d’établir règle de nommage précise pour retrouver un secret

Autres solutions testées

Les deux premières solutions ici sont différentes dans le sens où nous avons déployé les solutions afin de les tester, contrairement à 1Password où nous n’utilisations que l’opérateur. De plus, la question se pose d’utiliser ces solutions sur le même cluster où les secrets seront injectés…

Vault = non !

OpenBao = non plus !

  • OpenBao
  • Bao est un fork de Vault, faisant suite au rachat d’HashiCorp par IBM et la modification des licences. Il n’y a que peu de différence avec Vault, même dans sa version 2.0.

Pulumi ESC = presque oui !

  • Pulumi ESC
  • les solutions Pulumi sont plutôt intéressantes et stables
  • l’intégration avec Kubernetes est simple et l’injection des secrets l’est tout autant
  • son utilisation sur un compte gratuit est possible avec quelques limites toutefois difficile à identifier dans l’immédiat puisque la documentation est pauvre sur les différences avec le premier forfait payant (40$/mo !)

Hetzner

Hetzner est un provider Allemand dont les datacenters Européens sont situés sur les sites de Nuremberg (NBG), Falkenstein (FSN) et Helsinki (HEL).

En dehors d’un coût très faible, Hetzner est très stable, est certifié ISO 27001:2022, ISO 14001:2015 et bien d’autres. Enfin, Hetzner propose des VPS et des Serveurs dédiés type ARM (Ampere) d’une grande performance.

Le coût mensuel de la plateforme - composée de 5 VPS, 2 Load Balancer, 5 Primary IP , 4 Volumes et 1 zone DNS - est de moins de 50€ TTC, soit le prix moyen d’un VPS ARM chez Scaleway.

Choix

Le choix du provider s’est fait selon les critères suivants:

  • architecture ARM
  • stabilité reconue
  • datacenter bas carbone
  • tarifs
  • feedback
ProviderARMLocalisationStableBas carboneTarifs
AWSOuiEuropeMoyenNonÉlevé
GoogleOuiEuropeOuiNonTrès Élevé
AzureOuiFranceOuiNonÉlevé
OVHNon-NonNonBas
HetznerOuiEuropeOuiOuiBas
ScalewayOuiFranceNonOuiÉlevé

Feedbacks:

  • AWS: Les services managés sont top. Docs et configurations plutôt lourdes. Très opaque sur consommation énergétique.
  • Google: On se perd dans trop de docummentation multi-niveaux et configurations parfois lourdes. Surconsommation d’eau pour refroidir leur datacenter (étiquette low-carbon mensongère)
  • Azure: Deux ans d’expérience, deux ans de sueurs. Très opaque sur consommation énergétique.
  • Hetzner: Plusieurs feedback de scale-up et grands saas. Focus sur la fourniture de Bare Metal et VPS pour une grande stabilité. Transparent sur sa consommation énergétique. D’un point de vue production entreprise: Plus d’un an avec ce provider et seulement 1 incident mineur de moins de 30 minutes.
  • Scaleway: Deux ans d’expérience. 1 incident mineur par mois et 1 incident majeur par trimestre en moyenne. Plutôt transparent sur sa consommation énergétique.

Bien qu’Hetzner ne soit pas présent en france, le provider répond à un nombre suffisant de critères.

Posteo

Posteo est un service mail Allemand.

C’est un serive mail payant dont le coût est de 12€ TTC par an.

Choix

Le choix d’utiliser Posteo repose sur divers critères dont les plus importants sont les suivants:

Autre solutions

Note

Si vous n’envisagez pas l’envoi de notifications mail, le provider mail n’est pas nécessaire !

Gandi

Gandi est utilisé comme registrar pour le domaine une-graine.fr.

Choix

Le service d’enregistrement de nom de domaine est utilisé par Mathieu depuis plus de 20 ans sans qu’il n’y ait eu d’incident. Il paraît donc naturel de leur faire à nouveau confiance.

Autres solutions

Let’s Encrypt

Let’s Encrypt est une Authorité de Certification.

Libre d’une quelconque interface et de compte, nous nous en servons générer des certificats TLS et ainsi proposer une navigation sécurisée.

Les certificats de Let’s Encrypt ont une durée de vie de 3 mois.

Nous utilisons l’outil Cert Manager afin d’automatiser la génération et le renouvellement des certificats.

Choix

Le choix de Let’s Encrypt s’est fait pour deux raisons:

  • gratuité du service
  • pas de compte nécessaire
  • intégration simple avec Cert Manager et le solver dns01
  • pas d’enregistrements DNS ACME poluants

Autre solution

Peu de veille sur d’autres solutions.

Une seule autre solution éprouvée: ZeroSSL

Après plus de 3 ans d’utilisation en milieu professionnel, son seul intérêt est la possibilité de générer des certificats d’1 an et une certaine stabilité.

De plus, son offre gratuite est très limité.

Prérequis

L’ensemble des projets repose sur divers outils ou services.

1Password, Hetzner, Posteo et Gandi demandent quelques actions manuelles, expliquées dans les pages suivantes.

La page Recommandation est dédiée à 1Password pour une bonne organisation et gestion des secrets.

Recommandation

1Password

Vous le verrez pas la suite, nous faisons régulièrement appel à 1Password.

Lors des précédentes expériences avec le CLI et l’opérateur, l’approche était d’utiliser les UID des coffres et des objets.

C’est une bonne pratique dans le sens où ces UID ne changent pas.

En revanche, ça devient compliqué lorsque l’on utilise plusieurs coffres et que nous cherchons plusieurs objets, pour des dizaines de services et d’environnements.

Avant

{{op://b359a4160b93b562f5e356988/b7b3741739d732b5ed371d5b3/SECRET}}
{{op://b359a4160b93b562f5e356988/f3c1b48438b2489fb89fcae30/SECRET}}
{{op://071f644d5b1b58014541b8d98/61b24431093fe1d8519ceaaf9/SECRET}}

ou encore, pour les objets OnePasswordItem Kubernetes:

vaults/b359a4160b93b562f5e356988/items/b7b3741739d732b5ed371d5b3
vaults/b359a4160b93b562f5e356988/items/f3c1b48438b2489fb89fcae30
vaults/071f644d5b1b58014541b8d98/items/61b24431093fe1d8519ceaaf9

Après

Pour redonner un peu de lisibilité, une règle de nommage est appliquée sous la forme suivante:

  • le nom du coffre et des objets est en minuscule, sans espaces, underscore autorisé
  • les objets suivent les règles de nommage suivantes:
    • context_service_target
    • context_service
  • le context peut avoir les valeurs:
    • iac: objet utilisée uniquement par graine-cluster
    • gitops: objet utilisée uniquement par graine-gitops
    • shared: objet pouvant être utilisée par de multiple sources (dev, gitops, iac)

Ainsi, nous obtenons:

{{op://graine/iac_csi_volumes_passphrase/VOLUMES_PASSPHRASE}}
{{op://graine/iac_forgejo_smtp/SMTP_ADDRESS}}
{{op://graine/iac_forgejo_smtp/SMTP_PORT}}
{{op://graine/iac_hetzner_token/HETZNER_TOKEN}}
{{op://graine/iac_lets_encrypt/EMAIL}}
{{op://graine/iac_op_connect/OP_CONNET_TOKEN}}
{{op://graine/shared_forge_registry/ACCESS_KEY}}
{{op://graine/shared_forge_registry/EMAIL}}
{{op://graine/shared_service_token/TOKEN}}
vaults/graine/items/gitops_harbor_cache
vaults/graine/items/gitops_harbor_database
vaults/graine/items/shared_forge_registry
vaults/graine/items/shared_service_token

Note

ces règles peuvent encore évoluées !

1Password - Compte & Ops

La création d’un compte est nécessaire.

Créez un coffre

Il est préférable de créer un coffre dédié au projet. Par exemple, pour ce projet, nous utilisons le coffre graine qui ne contient que les secrets du projet.

Vous pouvez créer le coffre en passant par l’application web ou en passant par l’application lourde.

Créez un connecteur

  • Sur l’interface web, dirigez-vous vers Développeur puis Serveurs de connexion

  • Cliquez un Nouveau serveur de connexion

  • Saisissez le nom de l’environnement cible puis sélectionnez le coffre précédemment créé, en lecture uniquement op_connect_1

  • Cliquez sur Ajouter un environnement

  • Saisissez un nom de token, son expiration et de nouveau, sélectionnez le coffre précédemment créé, toujours en lecture uniquement op_connect_2

  • Cliquez sur Émettre le jeton

  • Sur l’étape suivante, enregistrez le fichier JSON ainsi que le token dans votre coffre dédié op_connect_3

  • Vous avez maintenant 2 objets dans votre coffre contenant le JSON et le token op_connect_vault

OP CLI

  • Installez le CLI 1Password
  • Si vous utilisez le client lourd et que vous souhaitez récupérer les UID, activez l’option suivante op_desktop_cli

Hetzner - Compte & Ops

La création d’un compte est nécessaire.

Informations et limites

Comme la majorité des providers (AWS fait exception), les VPS d’Hetzner sont limités à 16 volumes attachés.

De plus, il vous faudra une ancienneté d’un mois avant de pouvoir lever les limites et restrictions suivantes:

VPSVolumesSnapshotsFloating IPPrimary IPL.B.DNS
51024 Go30105525

Passé un mois et sans incident sur votre compte, une simple demande au support permet d’augmenter ces limites.

SSH Keys

  • Générez une clé SSH dédiée
    ssh-keygen -t ed25519 -C "your_email@example.com" -f $HOME/.ssh/hetzner_ed25519
    
  • Créez un objet dans votre coffre 1Password et ajouter la clé publique et privée
  • Connectez-vous à la console Cloud Hetzner
  • Cliquez sur Security
  • Dans la section SSH Keys, ajoutez votre clé SSH publique

Note: Le nom que vous donnez à cette clé est importante et nécessaire lors de l’initialisation d’un VPS.

API Token

  • Connectez-vous à la console Cloud Hetzner
  • Cliquez sur Security
  • Dans la section API Tokens, créez un token en lecture + écriture
  • Créez un objet dans votre coffre 1Password contenant ce token

DNS Zones

  • Connectez-vous à la console Cloud Hetzner
  • Cliquez sur DNS
  • Cliquez sur Add DNS Zone
  • Saisissez votre nom de domaine
  • Sélectionnez Create an empty zone
  • Cliquez sur Add DNS zone

La zone est alors créée en quelques secondes et contient les enregistrements NS et SOA

Cette zone sera automatiquement alimentée par le projet graine-cluster/hetzner-base suivant vos besoins.

Notes

L’ajout de la clé SSH ainsi que la création de la zone DNS peuvent être incluent dans le projet graine-cluster/hetzner-base.

🚧 En cours de tests !

Gandi

Que ce soit Gandi ou un autre registrar, le plus important est d’avoir la possibilité de configurer les Serveurs de noms.

La liste est la suivante:

helium.ns.hetzner.de
hydrogen.ns.hetzner.com
oxygen.ns.hetzner.com

Exemple avec Gandi:

gandi_server_name

Posteo

Si vous souhaitez utiliser Posteo et afin de pouvoir utiliser le protocole SMTP, il est nécéssaire de créer un mot de passe d’application.

Pour cela:

  • connectez-vous à votre compte Posteo
  • allez dans les Paramètres
  • allez dans Mot de passe et sécurité
  • en bas de la page, dans le bloc Mots de passe d'application (mots de passe d'appareils)
    • cliquez sur Créer un mot de passe d'application
    • saisissez une Description
    • sauvegardez le mot de passe généré par Posteo dans 1Password
    • saisissez le mot de passe vous permettant de vous connecter à votre compte
    • validez la création

Lorsque vous souhaiterez utiliser le protocole SMTP de Posteo, les informations seront les suivantes:

  • serveur: posteo.de
  • port: 465 ou 587, en fonction du chiffrement souhaité
  • login: votre identifiant de connexion ou un alias
  • mot de passe: le mot de passe d’application que vous venez de générer

Graine Cluster

Le cluster d’Une Graine est déployé suivant la topologie HA Stacked

Il se compose de:

  • 3 control plane CAX11 sur les sites NBG, FSN et HEL
  • 2 worker CAX21 sur le site NBG
  • 1 worker CAX21 sur le site FSN (soon)
  • 2 load balancer LB11 sur le site NBG

une_graine_cluster

Organisation des sources

hetzner-infrastructure ne contient que l’IaC concernant l’infrastructure et l’initialisation du cluster en utilisant principalement le provider tofu/terraform hetznercloud/hcloud.

hetzner-base ne contient que l’IaC concernant le socle applicatif du cluster.

Les services et les applications sont quant à eux uniquement gérés par ArgoCD via le projet graine-gitops

Prérequis

Pour initier le cluster, il vous faudra:

Hetzner Infrastructure

Prenez le temps de lire les points suivants 😉

Note

On ajoute NodeRestriction et PodNodeSelector au plugin Admission Control ce qui nous donnera la possibilité de restreindre un Namespace à utiliser un worker ou un pool de worker.

Le runtime utilisé est Containerd

Prérequis

Vous devez créer 4 objets dans votre coffre 1Password dédié.

Objets

iac_kubeconfig

  • desc: Fichier kubeconfig
  • type: fichier
  • clés: laisser l’objet vide, il sera alimenté à l’initialisation du cluster

iac_hetzner_token

  • desc: Token Hetzner
  • type: string
  • clés:
    • HETZNER_TOKEN: valeur du token

iac_ssh_keys

iac_vps_sshd_port

  • desc: Port SSH personnalisé
  • type: string
  • clés:
    • VPS_SSH_PORT: une valeur autre que 22

Fichier(s) objet

Le fichier graine_ssh_key.dist doit être modifié selon:

  • le nom de votre coffre
  • le nom de l’objet si modifié
  • le nom de la clé SSH privée

Vous pouvez également renommer ce fichier, il vous faudra alors modifier La ligne 16 et 17 de Taskfile.

Terraform tfvars dist

Ici nous allons nous attarder sur le fichier de distribution tfvars dont le contenu est le suivant:

#######################
#     YOU CAN EDIT    #
#######################
control_plane = [
  {
    name = "control-plane-nbg"
    # 10.0.1.0/24 range
    private_ip = "10.0.1.10"
    location   = "nbg1"
    model      = "cax11"
    image      = "ubuntu-24.04"
    # place is_main where you want the main control plane
    is_main = true
  },
  {
    name = "control-plane-fsn"
    # 10.0.1.0/24 range
    private_ip = "10.0.1.11"
    location   = "fsn1"
    model      = "cax11"
    image      = "ubuntu-24.04"
  },
  {
    name = "control-plane-hel"
    # 10.0.1.0/24 range
    private_ip = "10.0.1.12"
    location   = "hel1"
    model      = "cax11"
    image      = "ubuntu-24.04"
  }
]

node = [
  # Pool Graine
  {
    name = "terre"
    # 10.0.1.0/24 range
    private_ip = "10.0.1.20"
    location   = "nbg1"
    model      = "cax21"
    image      = "ubuntu-24.04"
    pool       = "graine"
  },
  {
    name = "eau"
    # 10.0.1.0/24 range
    private_ip = "10.0.1.30"
    location   = "nbg1"
    model      = "cax21"
    image      = "ubuntu-24.04"
    pool       = "graine"
  }
]

cluster_name         = "graine"
kubernetes_version   = "1.34"
lb_kube_api_location = "nbg1"
lb_kube_api_model    = "lb11"
lb_traefik_location  = "nbg1"
lb_traefik_model     = "lb11"
local_ssh_key_name   = "graine_ed25519"
placement_group_name = "graine-placement-group"
private_network_name = "graine-private-network"
ssh_keys             = ["graine"]

# Set the vault and item names
op_vault_kubeconfig = "graine"
op_item_kubeconfig  = "iac_kubeconfig"

# From 1Password
hetzner_token = "{{op://graine/iac_hetzner_token/HETZNER_TOKEN}}"
sshd_port     = "{{op://graine/iac_vps_sshd_port/VPS_SSH_PORT}}"

###################################
# !!! DO NOT EDIT, ADMIN ONLY !!! #
###################################
lb_kube_api_name       = "lb-kube-api"
lb_kube_api_private_ip = "10.0.1.2"
lb_traefik_name        = "lb-traefik"
lb_traefik_private_ip  = "10.0.1.4"
pod_network_cidr       = "10.244.0.0/16"
private_network_range  = "10.0.1.0/24"

Liste control_plane

control_planeest la liste contenant les specs de nos VPS Control plan.

variable "control_plane" {
  description = "List of Control Planes"
  type = list(object({
    name       = string
    private_ip = string
    location   = string
    model      = string
    image      = string
    ipv4_id    = optional(string)
    pool       = optional(string, "control-plane")
    is_main    = optional(bool, false)
    is_backup  = optional(bool, false)
    is_amd     = optional(bool, false)
    workload   = optional(string, "")
  }))
}

name

Nom du control plan

private_ip

IPv4 privée assignée au control plan, dont le range est 10.0.1.0/24, définit par la variable private_network_range

location

Localisation du datacenter parmis les choix fixes suivants: nbg1, fns1 et hel1

model

Model du VPS. Exemple pour les VPS ARM: CAX11, CAX21, CAX31 et CAX41

image

Image de l’OS à utiliser parmis un large choix comme ubuntu-24.04, debian-13 etc

ipv4_id

Optionnel, uniquement si vous possédeez déjà des Primary IPv4

pool

Optionnel, uniquement si vous souhaitez associer vos control plan à un pool. la valeur par défaut est control-plane

is_main

Semi-optionnel. Au moins un control plan doit avoir cette valeur à true. Ce sera le control plan où l’initialisation se lancée.

is_backup

N’est utile que pour le merge présent dans 04-vps-common-setup.tf

is_amd

N’est utile que pour le merge présent dans 04-vps-common-setup.tf

workload

N’est utile que pour le merge présent dans 04-vps-common-setup.tf


Liste node

nodeest la liste contenant les specs de nos VPS Worker.

Identique à la liste control_plane, seul les valeurs strictes ou possibles sont expliquées.

variable "node" {
  description = "List of Nodes"
  type = list(object({
    name       = string
    private_ip = string
    location   = string
    model      = string
    image      = string
    ipv4_id    = optional(string)
    pool       = string
    is_main    = optional(bool, false)
    is_backup  = optional(bool, false)
    is_amd     = optional(bool, false)
    workload   = optional(string, "")
  }))
}

pool

Le nom du pool auquel appartient le worker.

is_main

N’est utile que pour le merge présent dans 04-vps-common-setup.tf

is_backup

Optionnel. Uniquement si vous déployez des worker de backup sur des datacenter différent.

is_amd

Optionnel. Uniquement si vous déployez des worker dont le vCPU est de type AMD.

workload

Optionnel. Uniquement si le worker appartient à un pool dédié à des montées en charge fréquentes par exemple.


Variables

cluster_name

Nom du cluster. Impact kubernetes_config_context d’Hetzner Base

kubernetes_version

Version de Kubernetes à utiliser, sous la forme "MAJOR.MINOR". Exemple: "1.33", "1.34"

lb_kube_api_location

Localisation du load balancer Kube API parmis les choix fixes suivants: nbg1, fns1 et hel1

lb_kube_api_model

Model du load balancer Kube API parmis les choix fixes suivants: lb11, lb21 et lb31

lb_traefik_location

Localisation du load balancer Traefik parmis les choix fixes suivants: nbg1, fns1 et hel1

lb_traefik_model

Model du load balancer TRaefik parmis les choix fixes suivants: lb11, lb21 et lb31

local_ssh_key_name

Nom local de la clé ssh privée. Les lignes 16 et 17 de Taskfile doit être modifiée en conséquence.

placement_group_name

Nom du groupe de placement

ssh_keys

Nom de la clé SSH saisie lors des prérequis Hetzner

op_vault_kubeconfig

Nom du coffre 1Password contenant l’objet kubeconfig

op_item_kubeconfig

Nom de l’objet 1Password qui recevra le fichier kubeconfig généré

hetzner_token

Chemin 1Password pour récupérer la valeur du token Hetzner. Exemple: "{{op://graine/iac_hetzner_token/HETZNER_TOKEN}}"

sshd_port

Chemin 1Password pour récupérer la valeur du port SSH. Exemple: "{{op://graine/iac_vps_sshd_port/VPS_SSH_PORT}}"


Caution

Les variables suivantes sont à éditer en connaissance et avec précaution !

lb_kube_api_name

Nom du load balancer Kube API. En minuscule et sans espaces.

lb_kube_api_private_ip

IPv4 privée du load balancer Kube API

lb_traefik_name

Nom du load balancer Traefik. En minuscule et sans espaces. Impact lb_traefik_name d’Hetzner Base

lb_traefik_private_ip

IPv4 privée du load balancer Traefik

pod_network_cidr

Range CIDR assigné au Pods

private_network_name

Nom du réseau privée. En minuscule et sans espaces. Impact private_network_name d’Hetzner Base

private_network_range

Range du réseau privée. Impact control_plane, node, lb_kube_api_private_ip et lb_traefik_private_ip

Initialisation

Lorsque les précédentes étapes sont appliquées, lancez les commandes suivantes:

task init

task apply:all

task init va:

  • générer le fichier terraform.tfvars tout en récupérer les valeurs des objets 1Password
  • télécharger les providers Tofu / Terraform

task apply:all va:

  • initialiser votre cluster et les load balancer
  • générer le fichier SUMMARY.md contenant les noms des VPS et leur IPv4 publique

Hetzner Base

Les sources de cet IaC déploieront la stack et les configurations suivantes:

Optionel:

Prérequis

Vous devez créer plusieurs objets dans votre coffre 1Password dédié.

Objets

iac_argocd_ssh_keys

  • desc: Clé SSH publique et privée dédiée à ArgoCD
  • type: fichier(s)
  • clés:
    • argocd_ed25519
    • argocd_ed25519.pub
  • tips: ssh-keygen -t ed25519 -C "your_email@example.com" -f $HOME/.ssh/argocd_ed25519

iac_csi_volumes_passphrase

  • desc: Passphrase pour le chiffrement des volumes
  • type: string
  • clés:
    • VOLUMES_PASSPHRASE: Une passphrase de votre choix

iac_grafana_admin

  • desc: Compte admin de Grafana
  • type: string(s)
  • clés:
    • admin-user: nom d’utilisateur
    • admin-password: mot de passe

iac_hetzner_token

déjà présent puisque nécessaire pour Hetzner Infrastructure

  • desc: Token Hetzner
  • type: string
  • clés:
    • HETZNER_TOKEN: valeur du token

iac_lets_encrypt

  • desc: Email à destination de Let’s Encrypt
  • type: string(s)
  • clés:
    • EMAIL: une adresse mail valide

iac_op_connect

  • desc: Token et JSON 1Password
  • type: mixte
  • clés:
    • OP_CONNET_TOKEN: le token du connecteur
    • 1password-credentials.json

Objets Optionels

iac_forgejo_admin

  • desc: Compte admin de Forgejo
    • type: string(s)
    • clés:
      • username: nom d’utilisateur
      • password: mot de passe
      • email: une adresse mail valide

iac_forgejo_runners

  • desc: Configuration des runners
  • type: string(s)
  • clés:
    • CONFIG_INSTANCE: url de la forge (exemple: https://forge.tools.une-graine.fr)
    • CONFIG_NAME: nom du pool de runner
    • CONFIG_TOKEN: valeur temporaire

iac_forgejo_smtp

  • desc: Configuration SMTP
  • type: string(s)
  • clés:
    • SMTP_FROM: une adresse mail valide
    • SMTP_PROTOCOL: le protocol utilisé (ex posteo: smtp+starttls)
    • SMTP_ADDRESS: l’adresse du serveur SMTP (ex posteo: posteo.de)
    • SMTP_PORT: le port à utiliser (ex posteo: 465 ou 587)
    • SMTP_ACCESS_KEY: le nom du compte autorisé à utiliser le serveur SMTP
    • SMTP_SECRET_KEY: le secret associé à SMTP_ACCESS_KEY (exemple posteo)

shared_forge_argocd

  • desc: Compte ArgoCD pour à la forge
  • type: string(s)
  • clés:
    • ACCESS_KEY: le nom du compte
    • SECRET_KEY: mot de passe du compte
    • EMAIL: une adresse mail valide

shared_forge_dispatch

  • desc: token du compte ArgoCD pour la forge
  • type: string
  • clés:
    • TOKEN: valeur temporaire

shared_forge_registry

  • desc: Compte de service pour accéder au registre Forgejo
  • type: string(s)
  • clés:
    • ACCESS_KEY: le nom du compte
    • SECRET_KEY: mot de passe du compte
    • EMAIL: une adresse mail valide

Fichier(s) objet

Les fichiers:

Doivent être modifiés selon:

  • le nom de votre coffre
  • le nom de l’objet si modifié

Vous pouvez également renommer ces fichier, il vous faudra alors modifier Les lignes 17 à 19 de Taskfile.

Terraform tfvars dist

Ici nous allons nous attarder sur le fichier de distribution tfvars dont le contenu est le suivant:

#######################
#     YOU CAN EDIT    #
#######################
namespaces = [
  {
    name = "base-services"
  },
  {
    name = "shared-services"
  },
  {
    name = "internal-services"
  },
  {
    name = "monitoring-services"
  },
]

dns = [
  {
    content = "@"
    type    = "A"
  },
  {
    content = "www"
    type    = "A"
  },
  {
    content = "*.internal"
    type    = "A"
  },
  {
    content = "*.tools"
    type    = "A"
  }
]

cert_manager_dns_list = [
  # A Records (wilcard)
  {
    is_wildcard = true
    name        = "internal"
    sub         = "*.internal"
  },
  {
    is_wildcard = true
    name        = "tools"
    sub         = "*.tools"
  },
  # A Records
  {
    is_wildcard = false
    name        = "www"
    sub         = "www"
  }
]

argocd_url                   = "https://gitops.internal.une-graine.fr"
domain_name                  = "une-graine.fr"
forge_enabled                 = true
forge_ingress_cluster_issuer = "letsencrypt-tools-wildcard"
forge_ingress_tls_secret     = "forgejo-tools-wildcard-cert"
forge_ssh_url                = "ssh://git@forge.tools.une-graine.fr:13924/graine"
forge_ssh_port               = "13924"
forge_url                    = "forge.tools.une-graine.fr"
grafana_admin_secret         = "vaults/graine/items/iac_grafana_admin"
smtp_subject_prefix          = "Une Graine - "

# Set the items path
argocd_dispatch_object     = "vaults/graine/items/shared_forge_dispatch"
forge_admin_secret_object  = "vaults/graine/items/iac_forgejo_admin"
forge_runner_secret_object = "vaults/graine/items/iac_forgejo_runners"

# From 1Password
argocd_ssh_key_pub        = "{{op://graine/iac_argocd_ssh_keys/argocd_ed25519.pub}}"
forge_admin_access_key    = "{{op://graine/iac_forgejo_admin/username}}"
forge_admin_email         = "{{op://graine/iac_forgejo_admin/email}}"
forge_admin_secret_key    = "{{op://graine/iac_forgejo_admin/password}}"
forge_argocd_access_key   = "{{op://graine/shared_forge_argocd/ACCESS_KEY}}"
forge_argocd_email        = "{{op://graine/shared_forge_argocd/EMAIL}}"
forge_argocd_secret_key   = "{{op://graine/shared_forge_argocd/SECRET_KEY}}"
forge_registry_access_key = "{{op://graine/shared_forge_registry/ACCESS_KEY}}"
forge_registry_email      = "{{op://graine/shared_forge_registry/EMAIL}}"
forge_registry_secret_key = "{{op://graine/shared_forge_registry/SECRET_KEY}}"
hetzner_token             = "{{op://graine/iac_hetzner_token/HETZNER_TOKEN}}"
letsencrypt_email         = "{{op://graine/iac_lets_encrypt/EMAIL}}"
smtp_address              = "{{op://graine/iac_forgejo_smtp/SMTP_ADDRESS}}"
smtp_from                 = "{{op://graine/iac_forgejo_smtp/SMTP_FROM}}"
smtp_port                 = "{{op://graine/iac_forgejo_smtp/SMTP_PORT}}"
smtp_protocol             = "{{op://graine/iac_forgejo_smtp/SMTP_PROTOCOL}}"
smtp_access_key           = "{{op://graine/iac_forgejo_smtp/SMTP_ACCESS_KEY}}"
smtp_secret_key           = "{{op://graine/iac_forgejo_smtp/SMTP_SECRET_KEY}}"
volumes_passphrase        = "{{op://graine/iac_csi_volumes_passphrase/VOLUMES_PASSPHRASE}}"
onepassword_token         = "{{op://graine/iac_op_connect/OP_CONNET_TOKEN}}"

#######################################
# !!! DO NOT EDIT UNLESS YOU KNOW !!! #
#######################################
kubernetes_config_path            = "./sensitive/kubeconfig.yaml"
kubernetes_config_context         = "kubernetes-admin@graine"
lb_traefik_name                   = "lb-traefik"
onepassword_credentials_file_name = "1password-credentials.json"
private_network_name              = "graine-private-network"


Liste namespaces

namespaces est la liste des namespaces qui seront créés.

variable "namespaces" {
  description = "List of Namespaces"
  type = list(object({
    name = string
    pool = optional(string, "")
  }))
}

name

Nom du namespace

pool

Uniquement si vous associez un namespace à un pool de worker

Caution

Les namespaces base-services, shared-services, internal-services et monitoring-services sont requis pour le déploiement du socle.

Si vous souhaitez modifier les noms, il faudra alors mettre à jour toutes les ressources TF.


Liste dns

dnsest la liste des enregistrements DNS qui seront mis à jour dans le DNS Zone d’Hetzner.

variable "dns" {
  description = "Zone pointing to LB Traefik"
  type = list(object({
    content = string
    type    = string
  }))
}

content

@ pour all et les sous domaines

type

Type d’enregistrement (A, CNAME etc)


Liste cert_manager_dns_list

cert_manager_dns_list est la liste des sous domaines pour lesquels des certificats seront créés et distribués dans les différents namespaces.

variable "cert_manager_dns_list" {
  description = "List of Wildcard"
  type = list(object({
    is_wildcard = bool
    name        = string
    sub-name    = optional(string, "")
    sub         = string
  }))
}

is_wildcard

S’il s’agit d’un wildcard

name

Nom sera utilisé dans différents CRD de Cert Manager

sub-name

Unqiuement si l’on souhaite un sous-sous-domaine. Par exemple, si vous souhaitez le sous domaine *.perso.tools, alors la valeur de sub-name sera perso.tools

sub

Sous domaine (exemple: *.tools)

Note

Les noms des Issuers seront sous les formes suivantes:

  • letsencrypt-{name}-wildcard si is_wildcard est à true
  • letsencrypt-{name} si is_wildcard est à false

Les noms des certificats seront sous les formes suivantes:

  • {name}-wildcard-cert si is_wildcard est à true
  • {name}-cert si is_wildcard est à false

Variables

argocd_url

URL d’ArgoCD (exemple: https://gitops.internal.une-graine.fr)

domain_name

Nom de domaine (exemple: une-graine.fr)

forge_enabled

On passe à false si l’on ne souhaite déployer la forge et ses composants

forge_ingress_cluster_issuer

Optionel. Nom de l’issuer Cert Manager

forge_ingress_tls_secret

Optionel. Nom du secret contenant le certificat

forge_ssh_url

Optionel. URL SSH de la forge à destination d’ArgoCD. Comme nous utilisons un port différent de 22, l’URL est sous la forme suivante: ssh://git@{forge_url}:{forge_ssh_port}/{projet}

forge_ssh_port

Optionel. Port SSH, différent de 22. Impact forge_ssh_url

forge_url

Optionel. URL de la forge. Impact forge_ssh_url

grafana_admin_secret

Chemin standard vers l’objet 1Password iac_grafana_admin (exemple: vaults/graine/items/iac_grafana_admin)

smtp_subject_prefix

Optionel. Préfixe des objets des emails envoyés par la forge

forge_admin_secret_object

Optionel. Chemin standard vers l’objet 1Password iac_forgejo_admin (exemple: vaults/graine/items/iac_forgejo_admin)

forge_runner_secret_object

Optionel. Chemin standard vers l’objet 1Password iac_forgejo_runners (exemple: vaults/graine/items/iac_forgejo_runners)

argocd_dispatch_object

Optionel. Chemin standard vers l’objet 1Password shared_forge_dispatch (exemple: vaults/graine/items/shared_forge_dispatch)

argocd_ssh_key_pub

Optionel. Chemin CLI vers le fichier argocd_ed25519.pub de l’objet 1Password iac_argocd_ssh_keys (exemple: {{op://graine/iac_argocd_ssh_keys/argocd_ed25519.pub}})

forge_admin_access_key

Optionel. Chemin CLI vers la clé username de l’objet 1Password iac_forgejo_admin (exemple: {{op://graine/iac_forgejo_admin/username}})

forge_admin_email

Optionel. Chemin CLI vers la clé email de l’objet 1Password iac_forgejo_admin (exemple: {{op://graine/iac_forgejo_admin/email}})

forge_admin_secret_key

Optionel. Chemin CLI vers la clé password de l’objet 1Password iac_forgejo_admin (exemple: {{op://graine/iac_forgejo_admin/password}})

forge_argocd_access_key

Optionel. Chemin CLI vers la clé ACCESS_KEY de l’objet 1Password shared_forge_argocd (exemple: {{op://graine/shared_forge_argocd/ACCESS_KEY}})

forge_argocd_email

Optionel. Chemin CLI vers la clé EMAIL de l’objet 1Password shared_forge_argocd

forge_argocd_secret_key

Optionel. Chemin CLI vers la clé SECRET_KEY de l’objet 1Password shared_forge_argocd

forge_registry_access_key

Optionel. Chemin CLI vers la clé ACCESS_KEY de l’objet 1Password shared_forge_registry (exemple: {{op://graine/shared_forge_registry/ACCESS_KEY}})

forge_registry_email

Optionel. Chemin CLI vers la clé EMAIL de l’objet 1Password shared_forge_registry

forge_registry_secret_key

Optionel. Chemin CLI vers la clé SECRET_KEY de l’objet 1Password shared_forge_registry

hetzner_token

Chemin CLI vers la clé HETZNER_TOKEN de l’objet 1Password iac_hetzner_token

letsencrypt_email

Chemin CLI vers la clé EMAIL de l’objet 1Password iac_lets_encrypt

smtp_address

Optionel. Chemin CLI vers la clé SMTP_ADDRESS de l’objet 1Password iac_forgejo_smtp

smtp_from

Optionel. Chemin CLI vers la clé SMTP_FROM de l’objet 1Password iac_forgejo_smtp

smtp_port

Optionel. Chemin CLI vers la clé SMTP_PORT de l’objet 1Password iac_forgejo_smtp

smtp_protocol

Optionel. Chemin CLI vers la clé SMTP_PROTOCOL de l’objet 1Password iac_forgejo_smtp

smtp_access_key

Optionel. Chemin CLI vers la clé SMTP_ACCESS_KEY de l’objet 1Password iac_forgejo_smtp

smtp_secret_key

Optionel. Chemin CLI vers la clé SMTP_SECRET_KEY de l’objet 1Password iac_forgejo_smtp

volumes_passphrase

Chemin CLI vers la clé VOLUMES_PASSPHRASE de l’objet 1Password iac_csi_volumes_passphrase

onepassword_token

Chemin CLI vers la clé OP_CONNET_TOKEN de l’objet 1Password iac_op_connect


Caution

Les variables suivantes sont à éditer en connaissance et avec précaution !

kubernetes_config_path

Chemin local vers le fichier kubeconfig.yaml

kubernetes_config_context

Contexte présent dans le fichier kubeconfig.yaml (exemple: kubernetes-admin@graine)

lb_traefik_name

Nom du load balancer Traefik

onepassword_credentials_file_name

Nom du fichier JSON 1Password

private_network_name

Nom du réseau privée

Initialisation

Lorsque les précédentes étapes sont appliquées, lancez les commandes suivantes:

Sans la forge

task init

task apply

Avec la forge

Dans un premier temps:

task init

task apply:all

task init va:

  • générer le fichier terraform.tfvars tout en récupérer les valeurs des objets 1Password
  • télécharger les providers Tofu / Terraform

task apply va:

  • installer toute la stack à l’exception de la forge et tout ce qui la concerne

task apply:base va déployer en plus:

  • forgejo
  • 2 runners act
  • créer un compte ArgoCD et un compte de service permettant l’accès au registre
  • ajouter la clé SSH publique ArgoCD à son compte
  • créer un token associé au compte ArgoCD permettant le dispatch des actions

Graine Gitops