@@ -39,6 +39,68 @@ kubectl label namespace "$NAMESPACE" \
|
||||
|
||||
echo " ✓ Namespace créé avec PodSecurity=restricted"
|
||||
|
||||
# --- ResourceQuota : empêche le DoS par création massive de ressources ---
|
||||
# POURQUOI: Sans quota, l'équipe externe peut créer 10 000 pods, des centaines de PVC,
|
||||
# ou allouer des dizaines de Go de RAM. Cela peut saturer le scheduler,
|
||||
# remplir le disque etcd ou faire OOM le nœud.
|
||||
echo ""
|
||||
echo "1bis. ResourceQuota anti-DoS dans ${NAMESPACE}..."
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: external-app-quota
|
||||
namespace: ${NAMESPACE}
|
||||
spec:
|
||||
hard:
|
||||
pods: "20"
|
||||
requests.cpu: "4"
|
||||
requests.memory: "8Gi"
|
||||
limits.cpu: "8"
|
||||
limits.memory: "16Gi"
|
||||
persistentvolumeclaims: "5"
|
||||
requests.storage: "20Gi"
|
||||
services: "10"
|
||||
services.nodeports: "0"
|
||||
services.loadbalancers: "0"
|
||||
secrets: "20"
|
||||
configmaps: "20"
|
||||
EOF
|
||||
echo " ✓ ResourceQuota créé (max 20 pods, 8 CPU, 16 Gi RAM)"
|
||||
|
||||
# --- LimitRange : valeurs par défaut + max par container ---
|
||||
# POURQUOI: Sans LimitRange, un pod peut consommer tout le CPU/RAM du nœud.
|
||||
# Cela force des valeurs raisonnables même si l'équipe externe oublie
|
||||
# de définir resources.requests/limits dans ses manifests.
|
||||
echo ""
|
||||
echo "1ter. LimitRange dans ${NAMESPACE}..."
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: external-app-limits
|
||||
namespace: ${NAMESPACE}
|
||||
spec:
|
||||
limits:
|
||||
- type: Container
|
||||
default:
|
||||
cpu: "500m"
|
||||
memory: "512Mi"
|
||||
ephemeral-storage: "1Gi"
|
||||
defaultRequest:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
ephemeral-storage: "256Mi"
|
||||
max:
|
||||
cpu: "2"
|
||||
memory: "2Gi"
|
||||
ephemeral-storage: "4Gi"
|
||||
min:
|
||||
cpu: "10m"
|
||||
memory: "16Mi"
|
||||
EOF
|
||||
echo " ✓ LimitRange créé (max 2 CPU / 2 Gi par container)"
|
||||
|
||||
# --- ServiceAccount ---
|
||||
echo ""
|
||||
echo "2. Création du ServiceAccount ${SA_NAME}..."
|
||||
@@ -128,10 +190,12 @@ kind: ClusterPolicy
|
||||
metadata:
|
||||
name: restrict-external-deployer-escalation
|
||||
annotations:
|
||||
policies.kyverno.io/description: "Interdit au SA ${SA_NAME} de créer des ressources cluster-scoped."
|
||||
policies.kyverno.io/description: "Interdit au SA ${SA_NAME} d'escalader ses privilèges via RBAC."
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
rules:
|
||||
# Interdire toute création de ressources cluster-scoped (déjà bloqué par RBAC,
|
||||
# mais defense in depth — si un bug RBAC laisse passer, Kyverno bloque)
|
||||
- name: deny-clusterrole-creation
|
||||
match:
|
||||
any:
|
||||
@@ -144,8 +208,67 @@ spec:
|
||||
validate:
|
||||
message: "Le compte ${SA_NAME} ne peut pas créer de ressources cluster-scoped."
|
||||
deny: {}
|
||||
# Interdire la création de Role/RoleBinding qui font référence à un ClusterRole privilégié
|
||||
# POURQUOI: Le RBAC standard permet de créer un RoleBinding qui lie un SA à un
|
||||
# ClusterRole comme "cluster-admin" (escalade par référence). On bloque
|
||||
# explicitement cette voie d'escalade.
|
||||
- name: deny-rolebinding-to-clusteradmin
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds: [RoleBinding]
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: ${SA_NAME}
|
||||
namespace: ${NAMESPACE}
|
||||
validate:
|
||||
message: "Le compte ${SA_NAME} ne peut pas binder un ClusterRole privilégié."
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ request.object.roleRef.name }}"
|
||||
operator: AnyIn
|
||||
value:
|
||||
- cluster-admin
|
||||
- admin
|
||||
- edit
|
||||
- system:masters
|
||||
- key: "{{ request.object.roleRef.kind }}"
|
||||
operator: Equals
|
||||
value: ClusterRole
|
||||
# Interdire les Roles avec verbes/ressources wildcards (couvert par block-rbac-wildcards
|
||||
# global, mais ciblé spécifiquement sur ce SA pour les messages d'erreur)
|
||||
- name: deny-wildcard-role-creation
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds: [Role]
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: ${SA_NAME}
|
||||
namespace: ${NAMESPACE}
|
||||
validate:
|
||||
message: "Le compte ${SA_NAME} ne peut pas créer de Role avec wildcards (*) ou verbes d'escalade."
|
||||
deny:
|
||||
conditions:
|
||||
any:
|
||||
- key: "{{ request.object.rules[].verbs[] | contains(@, '*') }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
- key: "{{ request.object.rules[].resources[] | contains(@, '*') }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
- key: "{{ request.object.rules[].verbs[] | contains(@, 'escalate') }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
- key: "{{ request.object.rules[].verbs[] | contains(@, 'bind') }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
- key: "{{ request.object.rules[].verbs[] | contains(@, 'impersonate') }}"
|
||||
operator: Equals
|
||||
value: true
|
||||
EOF
|
||||
echo " ✓ Policy anti-escalade Kyverno créée"
|
||||
echo " ✓ Policy anti-escalade Kyverno créée (3 règles)"
|
||||
|
||||
# --- Génération du token ---
|
||||
echo ""
|
||||
@@ -215,11 +338,22 @@ echo ""
|
||||
echo " IMPORTANT : Ce token expire dans ${TOKEN_DURATION}."
|
||||
echo " Pour régénérer : kubectl create token ${SA_NAME} -n ${NAMESPACE} --duration=${TOKEN_DURATION}"
|
||||
echo ""
|
||||
echo " Vecteurs d'attaque que l'équipe PEUT tenter :"
|
||||
echo " - Escape via les NetworkPolicies (tenter de contacter d'autres namespaces)"
|
||||
echo " - Escalade RBAC (tenter de créer des ClusterRoles/ClusterRoleBindings)"
|
||||
echo " - Container breakout (pod privileged → refusé par Kyverno)"
|
||||
echo " - Shell dans container (bloqué par KubeArmor)"
|
||||
echo " - Lecture secrets (interdit par RBAC)"
|
||||
echo " - Déploiement d'image malveillante avec :latest (refusé par Kyverno)"
|
||||
echo " Vecteurs d'attaque que l'équipe PEUT tenter (et qui sont bloqués) :"
|
||||
echo " - Container breakout (pod privileged) → refusé par Kyverno + PSA"
|
||||
echo " - Évasion namespace (hostNetwork/PID/IPC) → refusé par Kyverno"
|
||||
echo " - Mount hostPath → refusé par Kyverno"
|
||||
echo " - Shell dans container → bloqué par KubeArmor"
|
||||
echo " - Outils d'évasion (nsenter, unshare) → bloqués par KubeArmor"
|
||||
echo " - Accès socket containerd → bloqué par KubeArmor"
|
||||
echo " - Écriture /etc, /usr, /bin → bloquée par KubeArmor"
|
||||
echo " - Lecture secrets existants → interdit par RBAC"
|
||||
echo " - Création ClusterRole/Binding → interdit par RBAC + Kyverno"
|
||||
echo " - RoleBinding vers cluster-admin → bloqué par Kyverno"
|
||||
echo " - Service NodePort/LoadBalancer → bloqué par Kyverno"
|
||||
echo " - hostPort → bloqué par Kyverno"
|
||||
echo " - Image :latest ou registry inconnu → refusé par Kyverno"
|
||||
echo " - DoS par création massive de pods → bloqué par ResourceQuota (max 20 pods)"
|
||||
echo " - DoS RAM/CPU → bloqué par LimitRange (max 2 CPU / 2 Gi par container)"
|
||||
echo " - Communication inter-namespace → bloquée par NetworkPolicy default-deny"
|
||||
echo " - Énumération nodes/namespaces → interdit par RBAC"
|
||||
echo "============================================="
|
||||
|
||||
Reference in New Issue
Block a user