From 9affd7959c1d5e857aed68a71bb33a75e2a4b44b Mon Sep 17 00:00:00 2001 From: Melvin GABALI Date: Wed, 21 Jan 2026 22:55:38 +0100 Subject: [PATCH] add webhook ovh --- ...plicationset-cert-manager-webhook-ovh.yaml | 44 ++++++ helm/cert-manager-webhook-ovh/ops/Chart.yaml | 6 + .../ops/templates/deployment.yaml | 57 ++++++++ .../ops/templates/mutating-webhook.yaml | 22 +++ .../ops/templates/rbac.yaml | 28 ++++ .../ops/templates/service.yaml | 17 +++ .../ops/templates/serviceaccount.yaml | 8 + .../ops/templates/validating-webhook.yaml | 22 +++ helm/cert-manager-webhook-ovh/ops/values.yaml | 39 +++++ helm/certificates/ops/docs/README.md | 138 ++++++++++++++++++ .../cluster-issuer-letsencrypt-dns01.yaml | 36 +++++ .../templates/headlamp/certificate-dev.yaml | 13 ++ .../ops/templates/secret-ovh-credentials.yaml | 27 ++++ .../wildcard/certificate-wildcard-dev.yaml | 14 ++ .../wildcard/certificate-wildcard-prd.yaml | 14 ++ .../wildcard/certificate-wildcard-rct.yaml | 14 ++ 16 files changed, 499 insertions(+) create mode 100644 apps/applicationset-cert-manager-webhook-ovh.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/Chart.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/templates/deployment.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/templates/mutating-webhook.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/templates/rbac.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/templates/service.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/templates/serviceaccount.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/templates/validating-webhook.yaml create mode 100644 helm/cert-manager-webhook-ovh/ops/values.yaml create mode 100644 helm/certificates/ops/docs/README.md create mode 100644 helm/certificates/ops/templates/cluster-issuer-letsencrypt-dns01.yaml create mode 100644 helm/certificates/ops/templates/headlamp/certificate-dev.yaml create mode 100644 helm/certificates/ops/templates/secret-ovh-credentials.yaml create mode 100644 helm/certificates/ops/templates/wildcard/certificate-wildcard-dev.yaml create mode 100644 helm/certificates/ops/templates/wildcard/certificate-wildcard-prd.yaml create mode 100644 helm/certificates/ops/templates/wildcard/certificate-wildcard-rct.yaml diff --git a/apps/applicationset-cert-manager-webhook-ovh.yaml b/apps/applicationset-cert-manager-webhook-ovh.yaml new file mode 100644 index 0000000..acb7cdd --- /dev/null +++ b/apps/applicationset-cert-manager-webhook-ovh.yaml @@ -0,0 +1,44 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: cert-manager-webhook-ovh + namespace: argocd-ops +spec: + generators: + # Le webhook OVH est déployé UNIQUEMENT sur le cluster OPS + - merge: + generators: + # Premier générateur : scanne les répertoires Helm pour le webhook OVH + - git: + repoURL: https://git.gkdomaine.fr/kubernetes/argocd.git + revision: main + directories: + - path: "helm/cert-manager-webhook-ovh/*" + # Deuxième générateur : lit la config OPS uniquement + - git: + repoURL: https://git.gkdomaine.fr/kubernetes/argocd.git + revision: main + files: + - path: "configs/ops/config.json" + mergeKeys: + - path.basename + template: + metadata: + name: 'cert-manager-webhook-ovh-{{path.basename}}' + spec: + project: default + source: + repoURL: '{{repository}}' + targetRevision: '{{targetRevision}}' + path: '{{helmPath}}/cert-manager-webhook-ovh/{{path.basename}}' + destination: + # Déploie uniquement sur le cluster OPS + name: '{{name}}' + namespace: cert-manager-{{path.basename}} + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + diff --git a/helm/cert-manager-webhook-ovh/ops/Chart.yaml b/helm/cert-manager-webhook-ovh/ops/Chart.yaml new file mode 100644 index 0000000..f08deb5 --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: cert-manager-webhook-ovh +description: Webhook OVH pour cert-manager (DNS-01 challenge) +type: application +version: 1.0.0 + diff --git a/helm/cert-manager-webhook-ovh/ops/templates/deployment.yaml b/helm/cert-manager-webhook-ovh/ops/templates/deployment.yaml new file mode 100644 index 0000000..2d7b2ee --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/templates/deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cert-manager-webhook-ovh + namespace: cert-manager-ops + labels: + app: cert-manager-webhook-ovh + app.kubernetes.io/name: cert-manager-webhook-ovh + app.kubernetes.io/instance: cert-manager-webhook-ovh +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: cert-manager-webhook-ovh + template: + metadata: + labels: + app: cert-manager-webhook-ovh + annotations: + {{- toYaml .Values.podAnnotations | nindent 8 }} + spec: + serviceAccountName: {{ .Values.serviceAccount.name }} + containers: + - name: webhook + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - --v=2 + - --group-name={{ .Values.groupName }} + - --secure-port=10250 + - --cert-dir=/tmp/cert-manager-webhook-ovh + ports: + - name: https + containerPort: 10250 + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: certs + mountPath: /tmp/cert-manager-webhook-ovh + readOnly: false + volumes: + - name: certs + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + diff --git a/helm/cert-manager-webhook-ovh/ops/templates/mutating-webhook.yaml b/helm/cert-manager-webhook-ovh/ops/templates/mutating-webhook.yaml new file mode 100644 index 0000000..eb9c250 --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/templates/mutating-webhook.yaml @@ -0,0 +1,22 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: cert-manager-webhook-ovh + labels: + app: cert-manager-webhook-ovh +webhooks: + - name: webhook.cert-manager.io + admissionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: cert-manager-webhook-ovh + namespace: cert-manager-ops + path: "/mutate" + rules: + - apiGroups: ["acme.cert-manager.io"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["challenges"] + sideEffects: None + failurePolicy: Fail + diff --git a/helm/cert-manager-webhook-ovh/ops/templates/rbac.yaml b/helm/cert-manager-webhook-ovh/ops/templates/rbac.yaml new file mode 100644 index 0000000..0333175 --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/templates/rbac.yaml @@ -0,0 +1,28 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cert-manager-webhook-ovh + namespace: cert-manager-ops + labels: + app: cert-manager-webhook-ovh +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cert-manager-webhook-ovh + namespace: cert-manager-ops + labels: + app: cert-manager-webhook-ovh +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cert-manager-webhook-ovh +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.name }} + namespace: cert-manager-ops + diff --git a/helm/cert-manager-webhook-ovh/ops/templates/service.yaml b/helm/cert-manager-webhook-ovh/ops/templates/service.yaml new file mode 100644 index 0000000..ba8701c --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: cert-manager-webhook-ovh + namespace: cert-manager-ops + labels: + app: cert-manager-webhook-ovh +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: https + protocol: TCP + name: https + selector: + app: cert-manager-webhook-ovh + diff --git a/helm/cert-manager-webhook-ovh/ops/templates/serviceaccount.yaml b/helm/cert-manager-webhook-ovh/ops/templates/serviceaccount.yaml new file mode 100644 index 0000000..f15a3dd --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.name }} + namespace: cert-manager-ops + labels: + app: cert-manager-webhook-ovh + diff --git a/helm/cert-manager-webhook-ovh/ops/templates/validating-webhook.yaml b/helm/cert-manager-webhook-ovh/ops/templates/validating-webhook.yaml new file mode 100644 index 0000000..6dc26dc --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/templates/validating-webhook.yaml @@ -0,0 +1,22 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: cert-manager-webhook-ovh + labels: + app: cert-manager-webhook-ovh +webhooks: + - name: webhook.cert-manager.io + admissionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: cert-manager-webhook-ovh + namespace: cert-manager-ops + path: "/validate" + rules: + - apiGroups: ["acme.cert-manager.io"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["challenges"] + sideEffects: None + failurePolicy: Fail + diff --git a/helm/cert-manager-webhook-ovh/ops/values.yaml b/helm/cert-manager-webhook-ovh/ops/values.yaml new file mode 100644 index 0000000..1031557 --- /dev/null +++ b/helm/cert-manager-webhook-ovh/ops/values.yaml @@ -0,0 +1,39 @@ +# Configuration pour cert-manager-webhook-ovh +# Ce webhook permet à cert-manager d'utiliser OVH DNS-01 challenge pour les certificats wildcard + +image: + repository: harbor.gkdomaine.local/images/cert-manager-webhook-ovh + tag: "v0.6.1" + pullPolicy: IfNotPresent + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + +# Configuration du webhook +groupName: acme.gkdomaine.fr + +# RBAC +serviceAccount: + create: true + name: cert-manager-webhook-ovh + +# Service +service: + type: ClusterIP + port: 443 + +# Pod annotations +podAnnotations: {} + +# Node selector, tolerations, etc. +nodeSelector: {} +tolerations: [] +affinity: {} + diff --git a/helm/certificates/ops/docs/README.md b/helm/certificates/ops/docs/README.md new file mode 100644 index 0000000..f9f72a5 --- /dev/null +++ b/helm/certificates/ops/docs/README.md @@ -0,0 +1,138 @@ +# Gestion des Certificats Let's Encrypt pour le cluster OPS + +Ce chart gère les certificats TLS générés par cert-manager dans le cluster OPS via Let's Encrypt. + +## Stratégie de certificats + +- **Sites publics** (accessibles depuis Internet) → **Certificats individuels** avec `letsencrypt-prod` (HTTP-01) + - Exemples : `homarr.dev.gkdomaine.fr`, `longhorn.dev.gkdomaine.fr` + - Validation via HTTP-01 challenge (nécessite accès HTTP public) + +- **Sites internes** (accessibles uniquement en interne) → **Certificats wildcard** avec `letsencrypt-dns01-prod` (DNS-01) + - Exemples : `*.dev.gkdomaine.fr`, `*.rct.gkdomaine.fr`, `*.prd.gkdomaine.fr` + - Validation via DNS-01 challenge (nécessite le webhook OVH) + - Un seul certificat wildcard couvre tous les sous-domaines d'un environnement + +## Structure + +- `Chart.yaml` : Définition du chart Helm +- `templates/` : Dossiers organisés par application + - `homarr/` : Certificats pour l'application Homarr (sites publics) + - `longhorn/` : Certificats pour Longhorn (sites publics) + - `headlamp/` : Certificats pour Headlamp (sites internes) + - `wildcard/` : Certificats wildcard pour les environnements (dev, rct, prd) + +## ClusterIssuers + +### letsencrypt-prod (HTTP-01) +- Utilisé pour les certificats individuels des sites publics +- Challenge HTTP-01 via Traefik +- Pas besoin de configuration DNS supplémentaire + +### letsencrypt-dns01-prod (DNS-01) +- Utilisé pour les certificats wildcard des sites internes +- Challenge DNS-01 via webhook OVH +- Nécessite le secret `ovh-credentials` avec les credentials OVH API + +## Ajout d'un nouveau certificat + +### Pour un site public (certificat individuel) + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: --tls + namespace: certificates-ops +spec: + secretName: --tls + issuerRef: + name: letsencrypt-prod # HTTP-01 pour sites publics + kind: ClusterIssuer + dnsNames: + - ..gkdomaine.fr +``` + +### Pour un site interne (utiliser le wildcard) + +**Option 1 : Utiliser le certificat wildcard existant (recommandé)** + +Pas besoin de créer un Certificate ! Utilisez directement le secret wildcard dans votre Ingress : + +```yaml +# Dans votre values.yaml ou Ingress +ingress: + tls: + - secretName: wildcard-dev-tls # Utilise le wildcard + hosts: + - headlamp.dev.gkdomaine.fr +``` + +**Option 2 : Créer un certificat individuel avec DNS-01** + +Si vous avez besoin d'un certificat spécifique (par exemple pour un domaine différent) : + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: --tls + namespace: certificates-ops +spec: + secretName: --tls + issuerRef: + name: letsencrypt-dns01-prod # DNS-01 pour sites internes + kind: ClusterIssuer + dnsNames: + - ..gkdomaine.fr +``` + +## Déploiement + +Les certificats sont déployés automatiquement via l'ApplicationSet `certificates-apps` dans ArgoCD. + +## Prérequis + +### Pour les certificats wildcard (DNS-01) + +1. **Webhook OVH installé** : Le webhook `cert-manager-webhook-ovh` doit être installé +2. **Secret OVH credentials** : Le secret `ovh-credentials` doit exister dans le namespace `certificates-ops` + - Voir `templates/secret-ovh-credentials.yaml` pour le template + - Créez le secret avec vos vraies credentials OVH API + +### Pour les certificats individuels (HTTP-01) + +- Aucun prérequis supplémentaire +- Le cluster OPS doit avoir accès Internet +- Les domaines doivent être accessibles publiquement via HTTP + +## Vérification + +```bash +# Vérifier les certificats +kubectl get certificates -n certificates-ops --context=cluster-ops + +# Vérifier un certificat spécifique +kubectl describe certificate wildcard-dev-tls -n certificates-ops --context=cluster-ops + +# Vérifier les secrets TLS créés +kubectl get secrets -n certificates-ops --context=cluster-ops | grep tls + +# Vérifier les ClusterIssuers +kubectl get clusterissuers --context=cluster-ops +``` + +## Synchronisation vers les autres clusters + +Les secrets TLS générés dans OPS doivent être synchronisés vers les clusters DEV/RCT/PRD où les applications sont déployées. + +Utilisez le script `scripts/sync-all-certificates.sh` pour synchroniser automatiquement tous les secrets TLS. + +## Notes importantes + +- Les certificats sont créés dans le cluster OPS où cert-manager est installé +- Le namespace du Certificate doit être `certificates-ops` +- Pour utiliser le certificat dans d'autres clusters (DEV, RCT, PRD), le secret TLS doit être synchronisé depuis OPS +- Les certificats wildcard couvrent tous les sous-domaines d'un environnement (ex: `*.dev.gkdomaine.fr`) +- Les certificats individuels sont spécifiques à un domaine (ex: `homarr.dev.gkdomaine.fr`) + diff --git a/helm/certificates/ops/templates/cluster-issuer-letsencrypt-dns01.yaml b/helm/certificates/ops/templates/cluster-issuer-letsencrypt-dns01.yaml new file mode 100644 index 0000000..5bb539f --- /dev/null +++ b/helm/certificates/ops/templates/cluster-issuer-letsencrypt-dns01.yaml @@ -0,0 +1,36 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-dns01-prod +spec: + acme: + # Serveur Let's Encrypt production + server: https://acme-v02.api.letsencrypt.org/directory + # Email pour les notifications Let's Encrypt + email: gkpoubelle78@gmail.com + # Secret pour stocker la clé privée de l'account ACME + privateKeySecretRef: + name: letsencrypt-dns01-prod + # Challenge DNS-01 pour les certificats wildcard (sites internes) + solvers: + - dns01: + webhook: + groupName: acme.gkdomaine.fr + solverName: ovh + config: + # Les credentials OVH sont dans le secret ovh-credentials + # Voir helm/certificates/ops/templates/secret-ovh-credentials.yaml + applicationKey: "1d1a85ccc3a5bcc9" + applicationSecretRef: + name: ovh-credentials + key: application-secret + consumerKeyRef: + name: ovh-credentials + key: consumer-key + # Ce solver s'applique uniquement aux domaines internes + selector: + dnsZones: + - "dev.gkdomaine.fr" + - "rct.gkdomaine.fr" + - "prd.gkdomaine.fr" + diff --git a/helm/certificates/ops/templates/headlamp/certificate-dev.yaml b/helm/certificates/ops/templates/headlamp/certificate-dev.yaml new file mode 100644 index 0000000..9cdf6fb --- /dev/null +++ b/helm/certificates/ops/templates/headlamp/certificate-dev.yaml @@ -0,0 +1,13 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: headlamp-dev-tls + namespace: certificates-ops +spec: + secretName: headlamp-dev-tls + issuerRef: + name: letsencrypt-dns01-prod # Utilise le wildcard pour site interne + kind: ClusterIssuer + dnsNames: + - headlamp.dev.gkdomaine.fr # Site interne accessible via .fr + diff --git a/helm/certificates/ops/templates/secret-ovh-credentials.yaml b/helm/certificates/ops/templates/secret-ovh-credentials.yaml new file mode 100644 index 0000000..307b40c --- /dev/null +++ b/helm/certificates/ops/templates/secret-ovh-credentials.yaml @@ -0,0 +1,27 @@ +# Secret pour les credentials OVH (DNS-01 challenge) +# IMPORTANT: Remplacez les valeurs base64 par vos vraies credentials OVH +# +# Pour créer le Secret manuellement avec vos vraies valeurs : +# kubectl create secret generic ovh-credentials \ +# --from-literal=application-secret=VOTRE_APPLICATION_SECRET \ +# --from-literal=consumer-key=VOTRE_CONSUMER_KEY \ +# -n certificates-ops \ +# --context=cluster-ops +# +# OU utilisez ce template en remplaçant les valeurs base64 ci-dessous : +# echo -n 'VOTRE_APPLICATION_SECRET' | base64 +# echo -n 'VOTRE_CONSUMER_KEY' | base64 + +apiVersion: v1 +kind: Secret +metadata: + name: ovh-credentials + namespace: certificates-ops +type: Opaque +data: + # Encodez vos credentials en base64 : + # echo -n 'VOTRE_APPLICATION_SECRET' | base64 + # echo -n 'VOTRE_CONSUMER_KEY' | base64 + application-secret: N2RiNWM3ZTdmNWE5MTM2Y2I5YmE4YmRmNjRjYTNmYTI= + consumer-key: M2VjOWM5ZTdmNjgzZWI0NDkyY2IwYjhhZTg1NWU0YWM= + diff --git a/helm/certificates/ops/templates/wildcard/certificate-wildcard-dev.yaml b/helm/certificates/ops/templates/wildcard/certificate-wildcard-dev.yaml new file mode 100644 index 0000000..461adfa --- /dev/null +++ b/helm/certificates/ops/templates/wildcard/certificate-wildcard-dev.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: wildcard-dev-tls + namespace: certificates-ops +spec: + secretName: wildcard-dev-tls + issuerRef: + name: letsencrypt-dns01-prod + kind: ClusterIssuer + dnsNames: + - "*.dev.gkdomaine.fr" + - "dev.gkdomaine.fr" + diff --git a/helm/certificates/ops/templates/wildcard/certificate-wildcard-prd.yaml b/helm/certificates/ops/templates/wildcard/certificate-wildcard-prd.yaml new file mode 100644 index 0000000..af7dfde --- /dev/null +++ b/helm/certificates/ops/templates/wildcard/certificate-wildcard-prd.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: wildcard-prd-tls + namespace: certificates-ops +spec: + secretName: wildcard-prd-tls + issuerRef: + name: letsencrypt-dns01-prod + kind: ClusterIssuer + dnsNames: + - "*.prd.gkdomaine.fr" + - "prd.gkdomaine.fr" + diff --git a/helm/certificates/ops/templates/wildcard/certificate-wildcard-rct.yaml b/helm/certificates/ops/templates/wildcard/certificate-wildcard-rct.yaml new file mode 100644 index 0000000..e13b595 --- /dev/null +++ b/helm/certificates/ops/templates/wildcard/certificate-wildcard-rct.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: wildcard-rct-tls + namespace: certificates-ops +spec: + secretName: wildcard-rct-tls + issuerRef: + name: letsencrypt-dns01-prod + kind: ClusterIssuer + dnsNames: + - "*.rct.gkdomaine.fr" + - "rct.gkdomaine.fr" +