@@ -4,26 +4,258 @@
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Initialisation du Control Plane Kubernetes ==="
|
||||
echo "=== Initialisation du Control Plane Kubernetes (hardened) ==="
|
||||
|
||||
# Définir le réseau pod (utilisé par Flannel)
|
||||
POD_NETWORK_CIDR="10.244.0.0/16"
|
||||
APISERVER_IP=$(hostname -I | awk '{print $1}')
|
||||
POD_CIDR="10.244.0.0/16"
|
||||
SERVICE_CIDR="10.96.0.0/12"
|
||||
|
||||
echo "Initialisation de kubeadm avec le réseau pod $POD_NETWORK_CIDR..."
|
||||
sudo kubeadm init --pod-network-cidr=$POD_NETWORK_CIDR --apiserver-advertise-address=$(hostname -I | awk '{print $1}')
|
||||
echo "IP API server : $APISERVER_IP"
|
||||
echo "Pod CIDR : $POD_CIDR"
|
||||
echo "Service CIDR : $SERVICE_CIDR"
|
||||
echo ""
|
||||
|
||||
# --- Audit logging ---
|
||||
echo "Création de la politique d'audit..."
|
||||
sudo mkdir -p /var/log/kubernetes/audit
|
||||
sudo mkdir -p /etc/kubernetes/audit
|
||||
|
||||
sudo tee /etc/kubernetes/audit/audit-policy.yaml > /dev/null <<'EOF'
|
||||
apiVersion: audit.k8s.io/v1
|
||||
kind: Policy
|
||||
omitStages:
|
||||
- RequestReceived
|
||||
rules:
|
||||
# Tracer tous les accès aux secrets et configmaps (données sensibles)
|
||||
- level: RequestResponse
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["secrets", "configmaps"]
|
||||
|
||||
# Tracer les modifications RBAC (vecteur d'escalade de privilèges)
|
||||
- level: RequestResponse
|
||||
resources:
|
||||
- group: "rbac.authorization.k8s.io"
|
||||
resources: ["clusterroles", "clusterrolebindings", "roles", "rolebindings"]
|
||||
|
||||
# Tracer exec/portforward/attach (accès interactif aux pods — vecteur d'attaque courant)
|
||||
- level: RequestResponse
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["pods/exec", "pods/portforward", "pods/attach"]
|
||||
|
||||
# Tracer toutes les créations/suppressions/modifications (niveau Metadata pour réduire le volume)
|
||||
- level: Metadata
|
||||
verbs: ["create", "delete", "patch", "update"]
|
||||
|
||||
# Ignorer le bruit des health checks et composants systèmes
|
||||
- level: None
|
||||
users: ["system:kube-proxy"]
|
||||
verbs: ["watch"]
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["endpoints", "services", "services/status"]
|
||||
- level: None
|
||||
users: ["system:apiserver"]
|
||||
verbs: ["get"]
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["namespaces"]
|
||||
- level: None
|
||||
nonResourceURLs: ["/healthz*", "/readyz*", "/livez*", "/metrics"]
|
||||
|
||||
# Défaut : niveau Metadata pour tout le reste
|
||||
- level: Metadata
|
||||
EOF
|
||||
|
||||
# --- Chiffrement etcd at-rest ---
|
||||
echo "Génération de la clé de chiffrement etcd..."
|
||||
sudo mkdir -p /etc/kubernetes/encryption
|
||||
|
||||
ENCRYPTION_KEY=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)
|
||||
|
||||
sudo tee /etc/kubernetes/encryption/encryption-config.yaml > /dev/null <<EOF
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: EncryptionConfiguration
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
providers:
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: key1
|
||||
secret: ${ENCRYPTION_KEY}
|
||||
- identity: {}
|
||||
EOF
|
||||
sudo chmod 600 /etc/kubernetes/encryption/encryption-config.yaml
|
||||
echo " ✓ Clé AES-CBC générée (32 bytes, base64)"
|
||||
|
||||
# --- Config admission controllers ---
|
||||
echo "Création de la configuration des admission controllers..."
|
||||
sudo mkdir -p /etc/kubernetes/admission
|
||||
|
||||
sudo tee /etc/kubernetes/admission/admission-config.yaml > /dev/null <<'EOF'
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: AdmissionConfiguration
|
||||
plugins:
|
||||
- name: EventRateLimit
|
||||
configuration:
|
||||
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
|
||||
kind: Configuration
|
||||
limits:
|
||||
- type: Namespace
|
||||
qps: 50
|
||||
burst: 100
|
||||
cacheSize: 2000
|
||||
- type: User
|
||||
qps: 10
|
||||
burst: 50
|
||||
- name: PodSecurity
|
||||
configuration:
|
||||
apiVersion: pod-security.admission.config.k8s.io/v1
|
||||
kind: PodSecurityConfiguration
|
||||
defaults:
|
||||
enforce: "baseline"
|
||||
enforce-version: "latest"
|
||||
audit: "restricted"
|
||||
audit-version: "latest"
|
||||
warn: "restricted"
|
||||
warn-version: "latest"
|
||||
exemptions:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- kubearmor
|
||||
- kyverno
|
||||
- cilium-system
|
||||
usernames: []
|
||||
runtimeClasses: []
|
||||
EOF
|
||||
|
||||
# --- kubeadm config ---
|
||||
echo "Création de la configuration kubeadm..."
|
||||
|
||||
cat > /tmp/kubeadm-config.yaml <<EOF
|
||||
apiVersion: kubeadm.k8s.io/v1beta4
|
||||
kind: InitConfiguration
|
||||
localAPIEndpoint:
|
||||
advertiseAddress: ${APISERVER_IP}
|
||||
bindPort: 6443
|
||||
nodeRegistration:
|
||||
criSocket: unix:///run/containerd/containerd.sock
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta4
|
||||
kind: ClusterConfiguration
|
||||
kubernetesVersion: v1.34.0
|
||||
networking:
|
||||
podSubnet: "${POD_CIDR}"
|
||||
serviceSubnet: "${SERVICE_CIDR}"
|
||||
dnsDomain: "cluster.local"
|
||||
apiServer:
|
||||
extraArgs:
|
||||
- name: audit-log-path
|
||||
value: /var/log/kubernetes/audit/audit.log
|
||||
- name: audit-policy-file
|
||||
value: /etc/kubernetes/audit/audit-policy.yaml
|
||||
- name: audit-log-maxage
|
||||
value: "30"
|
||||
- name: audit-log-maxbackup
|
||||
value: "10"
|
||||
- name: audit-log-maxsize
|
||||
value: "100"
|
||||
- name: encryption-provider-config
|
||||
value: /etc/kubernetes/encryption/encryption-config.yaml
|
||||
- name: enable-admission-plugins
|
||||
value: NodeRestriction,PodSecurity,EventRateLimit
|
||||
- name: admission-control-config-file
|
||||
value: /etc/kubernetes/admission/admission-config.yaml
|
||||
- name: anonymous-auth
|
||||
value: "false"
|
||||
- name: tls-min-version
|
||||
value: VersionTLS12
|
||||
- name: tls-cipher-suites
|
||||
value: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- name: request-timeout
|
||||
value: "300s"
|
||||
extraVolumes:
|
||||
- name: audit-log
|
||||
hostPath: /var/log/kubernetes/audit
|
||||
mountPath: /var/log/kubernetes/audit
|
||||
pathType: DirectoryOrCreate
|
||||
- name: audit-policy
|
||||
hostPath: /etc/kubernetes/audit/audit-policy.yaml
|
||||
mountPath: /etc/kubernetes/audit/audit-policy.yaml
|
||||
readOnly: true
|
||||
pathType: File
|
||||
- name: encryption-config
|
||||
hostPath: /etc/kubernetes/encryption/encryption-config.yaml
|
||||
mountPath: /etc/kubernetes/encryption/encryption-config.yaml
|
||||
readOnly: true
|
||||
pathType: File
|
||||
- name: admission-config
|
||||
hostPath: /etc/kubernetes/admission/admission-config.yaml
|
||||
mountPath: /etc/kubernetes/admission/admission-config.yaml
|
||||
readOnly: true
|
||||
pathType: File
|
||||
controllerManager:
|
||||
extraArgs:
|
||||
- name: terminated-pod-gc-threshold
|
||||
value: "50"
|
||||
- name: use-service-account-credentials
|
||||
value: "true"
|
||||
---
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
cgroupDriver: systemd
|
||||
protectKernelDefaults: true
|
||||
readOnlyPort: 0
|
||||
EOF
|
||||
|
||||
# --- Initialisation du cluster ---
|
||||
echo ""
|
||||
echo "Initialisation de kubeadm..."
|
||||
echo " Paramètres : audit logs + etcd chiffré AES + admission controllers"
|
||||
echo " --skip-phases=addon/kube-proxy : Cilium remplacera kube-proxy (eBPF natif)"
|
||||
echo ""
|
||||
|
||||
sudo kubeadm init \
|
||||
--config=/tmp/kubeadm-config.yaml \
|
||||
--skip-phases=addon/kube-proxy
|
||||
|
||||
# Configuration kubectl
|
||||
echo ""
|
||||
echo "Configuration de kubectl pour l'utilisateur courant..."
|
||||
mkdir -p $HOME/.kube
|
||||
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
|
||||
sudo chown $(id -u):$(id -g) $HOME/.kube/config
|
||||
mkdir -p "$HOME/.kube"
|
||||
sudo cp -i /etc/kubernetes/admin.conf "$HOME/.kube/config"
|
||||
sudo chown "$(id -u):$(id -g)" "$HOME/.kube/config"
|
||||
chmod 600 "$HOME/.kube/config"
|
||||
|
||||
# Nettoyer les fichiers temporaires sensibles
|
||||
rm -f /tmp/kubeadm-config.yaml
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||
echo "║ AVERTISSEMENT SÉCURITÉ ║"
|
||||
echo "║ admin.conf = system:masters = bypass RBAC complet ║"
|
||||
echo "║ Usage : bootstrap initial uniquement ║"
|
||||
echo "║ Utiliser 08-generate-restricted-kubeconfig.sh pour ║"
|
||||
echo "║ générer un accès limité pour l'équipe externe ║"
|
||||
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "✓ Control plane initialisé avec succès!"
|
||||
echo ""
|
||||
echo "Pour joindre des workers au cluster, récupérez la commande 'kubeadm join' ci-dessus"
|
||||
echo "ou régénérez-la avec: kubeadm token create --print-join-command"
|
||||
echo "Sécurité activée:"
|
||||
echo " ✓ Audit logs → /var/log/kubernetes/audit/audit.log"
|
||||
echo " ✓ etcd chiffré → AES-CBC 256 bits at-rest"
|
||||
echo " ✓ Admission → NodeRestriction + PodSecurity + EventRateLimit"
|
||||
echo " ✓ Auth anonyme → désactivée"
|
||||
echo " ✓ TLS min → 1.2"
|
||||
echo ""
|
||||
echo "Statut des composants du control plane:"
|
||||
echo "Prochaines étapes:"
|
||||
echo " 1. Joindre les workers : 03-join-workers.sh"
|
||||
echo " 2. Installer Cilium : 04-install-cilium.sh"
|
||||
echo " (commande join à récupérer ci-dessus ou via: kubeadm token create --print-join-command)"
|
||||
echo ""
|
||||
echo "Statut du cluster:"
|
||||
kubectl get nodes
|
||||
kubectl get pods -n kube-system
|
||||
|
||||
Reference in New Issue
Block a user