Files
argocd/helm/tls-sync-wildcard/ops/scripts/sync-all-certificates.sh
2026-01-22 02:28:10 +01:00

388 lines
15 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Script pour synchroniser automatiquement tous les secrets TLS depuis les certificats dans OPS
# Usage: ./sync-all-certificates.sh [--sourceCluster "cluster-name"] [--sourceNS "certificates-ops"]
set -e
# Valeurs par défaut
SOURCE_CLUSTER="${SOURCE_CLUSTER:-}"
SOURCE_NS="${SOURCE_NS:-certificates-ops}"
# Parsing des arguments
while [[ $# -gt 0 ]]; do
case $1 in
--sourceCluster)
SOURCE_CLUSTER="$2"
shift 2
;;
--sourceNS)
SOURCE_NS="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --sourceCluster NAME Nom du cluster source (défaut: contexte actuel)"
echo " --sourceNS NAME Namespace source (défaut: certificates-ops)"
echo " --help, -h Afficher cette aide"
echo ""
echo "Ce script récupère automatiquement tous les certificats depuis OPS"
echo "et synchronise les secrets TLS vers les clusters appropriés."
exit 0
;;
*)
echo "❌ Option inconnue: $1"
echo "Utilisez --help pour voir l'aide"
exit 1
;;
esac
done
echo "=== Synchronisation automatique des secrets TLS ==="
echo "Source: $SOURCE_CLUSTER (namespace: $SOURCE_NS)"
echo ""
# Fonction pour déterminer les namespaces cibles pour un certificat wildcard
# Les certificats wildcard doivent être copiés dans tous les namespaces qui les utilisent
get_wildcard_target_namespaces() {
local cert_name=$1
local env=""
# Extraire l'environnement depuis le nom du certificat
if [[ $cert_name =~ wildcard-dev-tls ]]; then
env="dev"
elif [[ $cert_name =~ wildcard-rct-tls ]]; then
env="rct"
elif [[ $cert_name =~ wildcard-prd-tls ]]; then
env="prd"
else
return 1
fi
# Liste des namespaces qui utilisent le certificat wildcard pour cet environnement
# Ajoutez ici tous les namespaces qui référencent ce secret dans leurs Ingress
case "$env" in
dev)
WILDCARD_TARGET_NAMESPACES=("headlamp-dev" "homarr-dev" "longhorn-dev")
;;
rct)
WILDCARD_TARGET_NAMESPACES=("headlamp-rct" "homarr-rct" "longhorn-rct")
;;
prd)
WILDCARD_TARGET_NAMESPACES=("headlamp-prd" "homarr-prd" "longhorn-prd")
;;
*)
return 1
;;
esac
return 0
}
# Fonction pour déterminer le cluster et namespace cible à partir du nom du certificat
# Format attendu: <app>-<env>-tls
# Exemple: homarr-dev-tls -> cluster-dev, namespace homarr-dev
# Pour les certificats wildcard, cette fonction détermine seulement le cluster
determine_target() {
local cert_name=$1
# Détecter les certificats wildcard
if [[ $cert_name =~ ^wildcard- ]]; then
# Pour les certificats wildcard, on détermine seulement le cluster
# Les namespaces seront déterminés par get_wildcard_target_namespaces
if [[ $cert_name =~ -dev-tls$ ]]; then
TARGET_CLUSTER="cluster-dev"
TARGET_NS="" # Sera rempli par get_wildcard_target_namespaces
IS_WILDCARD=true
elif [[ $cert_name =~ -rct-tls$ ]]; then
TARGET_CLUSTER="cluster-rct"
TARGET_NS=""
IS_WILDCARD=true
elif [[ $cert_name =~ -prd-tls$ ]]; then
TARGET_CLUSTER="cluster-prd"
TARGET_NS=""
IS_WILDCARD=true
else
echo "⚠️ Impossible de déterminer le cluster cible pour $cert_name"
return 1
fi
else
# Certificats normaux (non-wildcard)
IS_WILDCARD=false
# Extraire l'environnement (dev, rct, prd)
if [[ $cert_name =~ -dev-tls$ ]]; then
TARGET_CLUSTER="cluster-dev"
TARGET_NS="${cert_name%-tls}" # Garde le suffixe -dev
elif [[ $cert_name =~ -rct-tls$ ]]; then
TARGET_CLUSTER="cluster-rct"
TARGET_NS="${cert_name%-tls}" # Garde le suffixe -rct
elif [[ $cert_name =~ -prd-tls$ ]]; then
TARGET_CLUSTER="cluster-prd"
TARGET_NS="${cert_name%-tls}" # Garde le suffixe -prd
else
# Par défaut, essayer de deviner depuis le nom
# Si le nom contient "dev", utiliser cluster-dev
if [[ $cert_name == *"dev"* ]]; then
TARGET_CLUSTER="cluster-dev"
TARGET_NS="${cert_name%-tls}"
else
echo "⚠️ Impossible de déterminer le cluster cible pour $cert_name"
return 1
fi
fi
fi
return 0
}
# Déterminer le contexte à utiliser
echo "1. Détermination du contexte kubectl..."
if [ -z "$SOURCE_CLUSTER" ] || [ "$SOURCE_CLUSTER" == "in-cluster" ]; then
# Utiliser le contexte actuel
SOURCE_CLUSTER=$(kubectl config current-context 2>/dev/null)
if [ -z "$SOURCE_CLUSTER" ]; then
echo "❌ Erreur: Aucun contexte kubectl actuel trouvé"
echo " Contextes disponibles:"
kubectl config get-contexts -o name 2>/dev/null || echo " (aucun contexte trouvé)"
exit 1
fi
echo " Utilisation du contexte actuel: $SOURCE_CLUSTER"
else
# Vérifier que le contexte spécifié existe
if ! kubectl config get-contexts "$SOURCE_CLUSTER" &>/dev/null; then
echo "❌ Erreur: Le contexte kubectl '$SOURCE_CLUSTER' n'existe pas"
echo " Contextes disponibles:"
kubectl config get-contexts -o name 2>/dev/null || echo " (aucun contexte trouvé)"
exit 1
fi
echo " Utilisation du contexte: $SOURCE_CLUSTER"
fi
# Vérifier l'accès au cluster
echo "2. Vérification de l'accès au cluster..."
if [ -z "$SOURCE_CLUSTER" ]; then
# Pas de contexte spécifié, utiliser le contexte actuel
if ! kubectl get nodes &>/dev/null; then
echo "❌ Erreur: Impossible d'accéder au cluster"
echo " Vérifiez votre configuration kubectl et votre connexion réseau"
exit 1
fi
else
# Utiliser le contexte spécifié
if ! kubectl get nodes --context="$SOURCE_CLUSTER" &>/dev/null; then
echo "❌ Erreur: Impossible d'accéder au cluster $SOURCE_CLUSTER"
echo " Vérifiez votre configuration kubectl et votre connexion réseau"
exit 1
fi
fi
# Récupérer tous les certificats
echo "3. Récupération des certificats depuis $SOURCE_CLUSTER..."
if [ -z "$SOURCE_CLUSTER" ]; then
CERTIFICATES=$(kubectl get certificates -n "$SOURCE_NS" -o json 2>&1)
else
CERTIFICATES=$(kubectl get certificates -n "$SOURCE_NS" --context="$SOURCE_CLUSTER" -o json 2>&1)
fi
KUBECTL_EXIT_CODE=$?
if [ $KUBECTL_EXIT_CODE -ne 0 ]; then
echo "❌ Erreur lors de la récupération des certificats:"
echo "$CERTIFICATES" | head -5
exit 1
fi
if [ -z "$CERTIFICATES" ] || [ "$CERTIFICATES" == "null" ] || [ "$(echo "$CERTIFICATES" | jq -r '.items // empty')" == "" ]; then
echo "⚠️ Aucun certificat trouvé dans $SOURCE_NS sur $SOURCE_CLUSTER"
echo " Vérifiez que les certificats existent avec:"
if [ -z "$SOURCE_CLUSTER" ]; then
echo " kubectl get certificates -n $SOURCE_NS"
else
echo " kubectl get certificates -n $SOURCE_NS --context=$SOURCE_CLUSTER"
fi
exit 0
fi
# Vérifier que jq est installé
if ! command -v jq &> /dev/null; then
echo "❌ Erreur: jq n'est pas installé"
echo " Installez jq avec: sudo apt-get install jq (Ubuntu/Debian) ou brew install jq (macOS)"
exit 1
fi
# Extraire les certificats et leurs informations
CERT_COUNT=$(echo "$CERTIFICATES" | jq -r '.items | length' 2>/dev/null)
if [ -z "$CERT_COUNT" ] || [ "$CERT_COUNT" == "null" ] || [ "$CERT_COUNT" == "0" ]; then
echo "⚠️ Aucun certificat trouvé dans $SOURCE_NS sur $SOURCE_CLUSTER"
exit 0
fi
echo " Trouvé $CERT_COUNT certificat(s)"
echo ""
# Traiter chaque certificat
SUCCESS_COUNT=0
SKIP_COUNT=0
ERROR_COUNT=0
for i in $(seq 0 $((CERT_COUNT - 1))); do
CERT_NAME=$(echo "$CERTIFICATES" | jq -r ".items[$i].metadata.name")
SECRET_NAME=$(echo "$CERTIFICATES" | jq -r ".items[$i].spec.secretName")
CERT_NAMESPACE=$(echo "$CERTIFICATES" | jq -r ".items[$i].metadata.namespace")
IS_WILDCARD=false # Initialisation par défaut
# Si secretName n'est pas défini, utiliser le nom du certificat
if [ "$SECRET_NAME" == "null" ] || [ -z "$SECRET_NAME" ]; then
SECRET_NAME="$CERT_NAME"
fi
echo "📋 Traitement du certificat: $CERT_NAME"
echo " Secret: $SECRET_NAME"
# Déterminer le cluster et namespace cible
if ! determine_target "$CERT_NAME"; then
echo " ⚠️ Ignoré (impossible de déterminer la destination)"
SKIP_COUNT=$((SKIP_COUNT + 1))
echo ""
continue
fi
# Vérifier que le secret existe dans la source
if [ -z "$SOURCE_CLUSTER" ]; then
SECRET_CHECK_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\""
else
SECRET_CHECK_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\" --context=\"$SOURCE_CLUSTER\""
fi
if ! eval "$SECRET_CHECK_CMD" &>/dev/null; then
echo " ⚠️ Le secret $SECRET_NAME n'existe pas encore (certificat peut-être en cours de génération)"
SKIP_COUNT=$((SKIP_COUNT + 1))
echo ""
continue
fi
# Récupérer le secret une seule fois
TEMP_FILE=$(mktemp)
if [ -z "$SOURCE_CLUSTER" ]; then
SECRET_GET_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\" -o yaml"
else
SECRET_GET_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\" --context=\"$SOURCE_CLUSTER\" -o yaml"
fi
if ! eval "$SECRET_GET_CMD" > "$TEMP_FILE" 2>/dev/null; then
echo " ❌ Erreur: Impossible de récupérer le secret"
rm -f "$TEMP_FILE"
ERROR_COUNT=$((ERROR_COUNT + 1))
echo ""
continue
fi
# Traitement spécial pour les certificats wildcard
if [ "$IS_WILDCARD" = true ]; then
echo " 🌐 Certificat wildcard détecté"
# Obtenir la liste des namespaces cibles
if ! get_wildcard_target_namespaces "$CERT_NAME"; then
echo " ⚠️ Impossible de déterminer les namespaces cibles pour le wildcard"
rm -f "$TEMP_FILE"
SKIP_COUNT=$((SKIP_COUNT + 1))
echo ""
continue
fi
echo " Destination: $TARGET_CLUSTER (namespaces: ${WILDCARD_TARGET_NAMESPACES[*]})"
# Copier le secret dans chaque namespace cible
for TARGET_NS in "${WILDCARD_TARGET_NAMESPACES[@]}"; do
echo " → Synchronisation vers namespace: $TARGET_NS"
# Créer une copie temporaire du fichier pour ce namespace
TEMP_FILE_NS=$(mktemp)
cp "$TEMP_FILE" "$TEMP_FILE_NS"
# Modifier les métadonnées pour ce namespace
sed -i.bak '/^ uid:/d' "$TEMP_FILE_NS" 2>/dev/null || true
sed -i.bak '/^ resourceVersion:/d' "$TEMP_FILE_NS" 2>/dev/null || true
sed -i.bak '/^ selfLink:/d' "$TEMP_FILE_NS" 2>/dev/null || true
sed -i.bak '/^ creationTimestamp:/d' "$TEMP_FILE_NS" 2>/dev/null || true
sed -i.bak "s/namespace: $SOURCE_NS/namespace: $TARGET_NS/" "$TEMP_FILE_NS" 2>/dev/null || true
rm -f "${TEMP_FILE_NS}.bak" 2>/dev/null || true
# Créer le namespace s'il n'existe pas
kubectl create namespace "$TARGET_NS" --context="$TARGET_CLUSTER" --dry-run=client -o yaml | kubectl apply --context="$TARGET_CLUSTER" -f - >/dev/null 2>&1 || true
# Appliquer le secret
if kubectl apply -f "$TEMP_FILE_NS" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
# Vérifier que le secret existe maintenant
if kubectl get secret "$SECRET_NAME" -n "$TARGET_NS" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
echo " ✅ Synchronisé avec succès dans $TARGET_NS"
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
else
echo " ❌ Erreur: Le secret n'a pas été créé dans $TARGET_NS"
ERROR_COUNT=$((ERROR_COUNT + 1))
fi
else
echo " ❌ Erreur lors de l'application du secret dans $TARGET_NS"
ERROR_COUNT=$((ERROR_COUNT + 1))
fi
# Nettoyage
rm -f "$TEMP_FILE_NS" "${TEMP_FILE_NS}.bak" 2>/dev/null || true
done
else
# Certificats normaux (non-wildcard) - comportement original
echo " Destination: $TARGET_CLUSTER (namespace: $TARGET_NS)"
echo " Synchronisation en cours..."
# Modifier les métadonnées
sed -i.bak '/^ uid:/d' "$TEMP_FILE" 2>/dev/null || true
sed -i.bak '/^ resourceVersion:/d' "$TEMP_FILE" 2>/dev/null || true
sed -i.bak '/^ selfLink:/d' "$TEMP_FILE" 2>/dev/null || true
sed -i.bak '/^ creationTimestamp:/d' "$TEMP_FILE" 2>/dev/null || true
sed -i.bak "s/namespace: $SOURCE_NS/namespace: $TARGET_NS/" "$TEMP_FILE" 2>/dev/null || true
rm -f "${TEMP_FILE}.bak" 2>/dev/null || true
# Créer le namespace s'il n'existe pas
kubectl create namespace "$TARGET_NS" --context="$TARGET_CLUSTER" --dry-run=client -o yaml | kubectl apply --context="$TARGET_CLUSTER" -f - >/dev/null 2>&1 || true
# Appliquer le secret
if kubectl apply -f "$TEMP_FILE" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
# Vérifier que le secret existe maintenant
if kubectl get secret "$SECRET_NAME" -n "$TARGET_NS" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
echo " ✅ Synchronisé avec succès"
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
else
echo " ❌ Erreur: Le secret n'a pas été créé"
ERROR_COUNT=$((ERROR_COUNT + 1))
fi
else
echo " ❌ Erreur lors de l'application du secret"
ERROR_COUNT=$((ERROR_COUNT + 1))
fi
fi
# Nettoyage
rm -f "$TEMP_FILE" "${TEMP_FILE}.bak" 2>/dev/null || true
echo ""
done
# Résumé
echo "=== Résumé ==="
echo "✅ Synchronisés avec succès: $SUCCESS_COUNT"
echo "⚠️ Ignorés: $SKIP_COUNT"
echo "❌ Erreurs: $ERROR_COUNT"
echo ""
if [ $ERROR_COUNT -eq 0 ] && [ $SUCCESS_COUNT -gt 0 ]; then
echo "🎉 Toutes les synchronisations réussies !"
exit 0
elif [ $ERROR_COUNT -gt 0 ]; then
echo "⚠️ Certaines synchronisations ont échoué"
exit 1
else
echo " Aucune synchronisation effectuée"
exit 0
fi