diff --git a/apps/applicationset-cert-manager.yaml b/apps/applicationset-cert-manager.yaml new file mode 100644 index 0000000..155cace --- /dev/null +++ b/apps/applicationset-cert-manager.yaml @@ -0,0 +1,56 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: cert-manager-apps + namespace: argocd-ops +spec: + generators: + # Utilise un générateur merge pour combiner : + # 1. Les répertoires Helm existants (détermine quels environnements sont disponibles pour cert-manager) + # 2. Les fichiers de config partagés (pour obtenir name et server) + - merge: + generators: + # Premier générateur : scanne uniquement les répertoires Helm qui existent pour cert-manager + - git: + repoURL: https://git.gkdomaine.fr/kubernetes/argocd.git + revision: main + directories: + - path: "helm/cert-manager/*" + # Deuxième générateur : lit les fichiers de config partagés + # ApplicationSet utilisera seulement les fichiers config.json dont le basename + # correspond à un répertoire Helm trouvé + - git: + repoURL: https://git.gkdomaine.fr/kubernetes/argocd.git + revision: main + files: + - path: "configs/*/config.json" + mergeKeys: + - path.basename + template: + metadata: + # Utilise path.basename qui vient du générateur git (plus fiable que environment du JSON) + name: 'cert-manager-{{path.basename}}' + spec: + # Utilise path.basename pour le projet (ou {{environment}} si disponible dans le JSON) + project: '{{path.basename}}' + source: + repoURL: '{{repository}}' + targetRevision: '{{targetRevision}}' + # Construit explicitement le chemin Helm à partir du basename + path: '{{helmPath}}/cert-manager/{{path.basename}}' + helm: + valueFiles: + - values.yaml + destination: + # Les variables {{name}} et {{server}} viennent du fichier config.json + # (deuxième générateur du merge) + name: '{{name}}' + # server: '{{server}}' + namespace: 'cert-manager' + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + diff --git a/docs/cert-manager-letsencrypt.md b/docs/cert-manager-letsencrypt.md new file mode 100644 index 0000000..6b6c68d --- /dev/null +++ b/docs/cert-manager-letsencrypt.md @@ -0,0 +1,226 @@ +# Configuration Let's Encrypt avec cert-manager + +Ce document explique comment générer et utiliser des certificats Let's Encrypt avec cert-manager dans votre cluster Kubernetes. + +## Architecture + +- **cert-manager** : Opérateur Kubernetes qui gère automatiquement les certificats TLS +- **ClusterIssuer** : Ressource qui définit comment obtenir des certificats (Let's Encrypt Production ou Staging) +- **Certificate** : Ressource Kubernetes qui demande un certificat pour un domaine spécifique +- **Traefik** : Ingress Controller qui utilise les certificats générés + +## Installation + +### 1. Déployer cert-manager + +cert-manager est déployé via ArgoCD via l'ApplicationSet `cert-manager-apps`. + +Le chart inclut : +- cert-manager (controller, webhook, cainjector) +- ClusterIssuer pour Let's Encrypt Production (`letsencrypt-prod`) +- ClusterIssuer pour Let's Encrypt Staging (`letsencrypt-staging`) + +### 2. Vérifier l'installation + +```bash +# Vérifier que cert-manager est déployé +kubectl get pods -n cert-manager + +# Vérifier les ClusterIssuers +kubectl get clusterissuers + +# Vérifier le statut d'un ClusterIssuer +kubectl describe clusterissuer letsencrypt-prod +``` + +## Configuration + +### ClusterIssuers + +Deux ClusterIssuers sont créés : + +1. **letsencrypt-prod** : Pour les certificats de production + - Serveur : `https://acme-v02.api.letsencrypt.org/directory` + - Limite de taux : 50 certificats par semaine par domaine + +2. **letsencrypt-staging** : Pour les tests + - Serveur : `https://acme-staging-v02.api.letsencrypt.org/directory` + - Limite de taux : 300 certificats par semaine par domaine + - ⚠️ Les certificats staging ne sont pas fiables par les navigateurs + +### Modifier l'email + +L'email utilisé pour l'enregistrement ACME est défini dans : +- `helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-prod.yaml` +- `helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-staging.yaml` + +Modifiez la ligne `email: admin@gkdomaine.fr` avec votre email. + +## Utilisation + +### Méthode 1 : Via annotations Ingress (Recommandé) + +Ajoutez les annotations suivantes à votre Ingress : + +```yaml +ingress: + enabled: true + className: traefik + hosts: + - host: monapp.dev.gkdomaine.fr + paths: + - path: / + tls: + - secretName: monapp-dev-tls + hosts: + - monapp.dev.gkdomaine.fr + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" # ou "letsencrypt-staging" pour les tests +``` + +### Méthode 2 : Via ressource Certificate (Pour plus de contrôle) + +Créez une ressource Certificate : + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: monapp-dev-tls + namespace: monapp-dev +spec: + secretName: monapp-dev-tls + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - monapp.dev.gkdomaine.fr +``` + +Puis référencez le secret dans votre Ingress : + +```yaml +ingress: + tls: + - secretName: monapp-dev-tls + hosts: + - monapp.dev.gkdomaine.fr +``` + +## Validation HTTP-01 + +cert-manager utilise la méthode HTTP-01 pour valider la propriété du domaine : + +1. cert-manager crée un challenge HTTP +2. Traefik expose le challenge sur `/.well-known/acme-challenge/` +3. Let's Encrypt vérifie que le challenge est accessible +4. Le certificat est émis et stocké dans un Secret Kubernetes + +### Prérequis + +- Le domaine doit pointer vers l'IP publique de Traefik (LoadBalancer) +- Le port 80 doit être accessible depuis Internet +- Traefik doit être configuré pour gérer les ingress avec la classe `traefik` + +## Vérification + +### Vérifier le statut d'un certificat + +```bash +# Lister les certificats +kubectl get certificates --all-namespaces + +# Détails d'un certificat +kubectl describe certificate monapp-dev-tls -n monapp-dev + +# Vérifier les challenges ACME +kubectl get challenges --all-namespaces +``` + +### Vérifier le secret TLS + +```bash +# Le secret est créé automatiquement quand le certificat est émis +kubectl get secret monapp-dev-tls -n monapp-dev + +# Voir les détails du certificat +kubectl get secret monapp-dev-tls -n monapp-dev -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout +``` + +## Renouvellement automatique + +cert-manager renouvelle automatiquement les certificats avant expiration (30 jours avant la date d'expiration). + +Les certificats Let's Encrypt sont valides pendant 90 jours. + +## Dépannage + +### Le certificat n'est pas émis + +1. Vérifier les logs de cert-manager : + ```bash + kubectl logs -n cert-manager deployment/cert-manager + ``` + +2. Vérifier les challenges : + ```bash + kubectl describe challenge -n monapp-dev + ``` + +3. Vérifier que le domaine est accessible : + ```bash + curl http://monapp.dev.gkdomaine.fr/.well-known/acme-challenge/test + ``` + +### Erreur "rate limit exceeded" + +Let's Encrypt a des limites de taux : +- Production : 50 certificats par semaine par domaine +- Staging : 300 certificats par semaine par domaine + +Solution : Utilisez `letsencrypt-staging` pour les tests, ou attendez la fin de la période de limitation. + +### Le certificat n'est pas utilisé par Traefik + +Vérifiez que : +1. Le secret TLS existe dans le même namespace que l'Ingress +2. L'Ingress référence correctement le secret dans `spec.tls[].secretName` +3. Traefik peut accéder au secret (même namespace ou RBAC approprié) + +## Exemples de configuration + +### Homarr + +Voir `helm/homarr/dev/values.yaml` pour un exemple complet avec annotations cert-manager. + +### Traefik Dashboard + +Pour sécuriser le dashboard Traefik, ajoutez TLS à l'IngressRoute : + +```yaml +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: traefik-dashboard + namespace: traefik-dev + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" +spec: + entryPoints: + - websecure + routes: + - match: Host(`traefik.dev.gkdomaine.fr`) + kind: Rule + services: + - name: api@internal + kind: TraefikService + tls: + secretName: traefik-dashboard-tls +``` + +## Références + +- [cert-manager Documentation](https://cert-manager.io/docs/) +- [Let's Encrypt Documentation](https://letsencrypt.org/docs/) +- [Traefik ACME Documentation](https://doc.traefik.io/traefik/https/acme/) + diff --git a/helm/cert-manager/dev/Chart.lock b/helm/cert-manager/dev/Chart.lock new file mode 100644 index 0000000..164dad7 --- /dev/null +++ b/helm/cert-manager/dev/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: cert-manager + repository: https://charts.jetstack.io + version: v1.16.0 +digest: sha256:59590787a7a7a4b4e15c20af04b03933ad00feff48bc38a8cdbf17a5f058e020 +generated: "2026-01-18T19:50:49.317276+01:00" diff --git a/helm/cert-manager/dev/Chart.yaml b/helm/cert-manager/dev/Chart.yaml new file mode 100644 index 0000000..1e655d7 --- /dev/null +++ b/helm/cert-manager/dev/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: cert-manager-wrapper +description: Wrapper pour cert-manager avec ClusterIssuer Let's Encrypt +type: application +version: 1.0.0 + +dependencies: + - name: cert-manager + version: v1.19.2 + repository: https://charts.jetstack.io + diff --git a/helm/cert-manager/dev/charts/cert-manager-v1.16.0.tgz b/helm/cert-manager/dev/charts/cert-manager-v1.16.0.tgz new file mode 100644 index 0000000..14c01e2 Binary files /dev/null and b/helm/cert-manager/dev/charts/cert-manager-v1.16.0.tgz differ diff --git a/helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-prod.yaml b/helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-prod.yaml new file mode 100644 index 0000000..dcc6f84 --- /dev/null +++ b/helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-prod.yaml @@ -0,0 +1,19 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + # URL du serveur Let's Encrypt Production + server: https://acme-v02.api.letsencrypt.org/directory + # Email utilisé pour l'enregistrement et les notifications de renouvellement + email: admin@gkdomaine.fr # ⚠️ À MODIFIER avec votre email + # Secret pour stocker la clé privée du compte ACME + privateKeySecretRef: + name: letsencrypt-prod + # Méthode de validation HTTP-01 (via Traefik) + solvers: + - http01: + ingress: + class: traefik + diff --git a/helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-staging.yaml b/helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-staging.yaml new file mode 100644 index 0000000..2f4a924 --- /dev/null +++ b/helm/cert-manager/dev/templates/cluster-issuer-letsencrypt-staging.yaml @@ -0,0 +1,19 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging +spec: + acme: + # URL du serveur Let's Encrypt Staging (pour les tests) + server: https://acme-staging-v02.api.letsencrypt.org/directory + # Email utilisé pour l'enregistrement et les notifications de renouvellement + email: admin@gkdomaine.fr # ⚠️ À MODIFIER avec votre email + # Secret pour stocker la clé privée du compte ACME + privateKeySecretRef: + name: letsencrypt-staging + # Méthode de validation HTTP-01 (via Traefik) + solvers: + - http01: + ingress: + class: traefik + diff --git a/helm/cert-manager/dev/values.yaml b/helm/cert-manager/dev/values.yaml new file mode 100644 index 0000000..43f013f --- /dev/null +++ b/helm/cert-manager/dev/values.yaml @@ -0,0 +1,33 @@ +# Configuration pour cert-manager +cert-manager: + # Installation de cert-manager + installCRDs: true + + # Configuration des images depuis Harbor + image: + registry: harbor.gkdomaine.local + repository: images/cert-manager-controller + tag: v1.19.2 + + webhook: + image: + registry: harbor.gkdomaine.local + repository: images/cert-manager-webhook + tag: v1.19.2 + + cainjector: + image: + registry: harbor.gkdomaine.local + repository: images/cert-manager-cainjector + tag: v1.19.2 + + # Configuration de sécurité + securityContext: + enabled: true + + # Prometheus metrics + prometheus: + enabled: true + servicemonitor: + enabled: true + diff --git a/helm/homarr/dev/values.yaml b/helm/homarr/dev/values.yaml index f268811..706448d 100644 --- a/helm/homarr/dev/values.yaml +++ b/helm/homarr/dev/values.yaml @@ -19,6 +19,14 @@ homarr: - host: homarr.dev.gkdomaine.fr paths: - path: / + # Configuration TLS avec cert-manager pour Let's Encrypt + tls: + - secretName: homarr-dev-tls + hosts: + - homarr.dev.gkdomaine.fr + # Annotations pour cert-manager + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-staging" # Utilisez "letsencrypt-staging" pour les tests persistence: homarrDatabase: