Avancé
⭐ Article vedette

Sécuriser Kubernetes en Production : Best Practices 2024

Guide complet pour durcir la sécurité de vos clusters K8s : RBAC, Network Policies, Pod Security Standards.

Publié le
5 novembre 2024
Lecture
18 min
Vues
2.1k
Auteur
Florian Courouge
Kubernetes
Sécurité
RBAC
Network Policies
Production

Table des matières

📋 Vue d'ensemble rapide des sujets traités dans cet article

Cliquez sur les sections ci-dessous pour naviguer rapidement

Sécuriser Kubernetes en Production : Best Practices 2024

La sécurité Kubernetes est un défi majeur en production. Avec l'adoption massive des conteneurs et l'orchestration, les surfaces d'attaque se multiplient. Ce guide présente les stratégies essentielles pour durcir vos clusters contre les menaces modernes et établir une posture de sécurité robuste.

Kubernetes Security Architecture

💡Comprendre le modèle de sécurité Kubernetes

Les 4 C de la sécurité Cloud Native

La sécurité Kubernetes s'articule autour de quatre couches interdépendantes :

  1. Cloud/Cluster : Infrastructure et configuration du cluster
  2. Cluster : Composants Kubernetes (API Server, etcd, kubelet)
  3. Container : Images et runtime de conteneurs
  4. Code : Application et dépendances

4C Security Model

Principe de défense en profondeur

Chaque couche doit être sécurisée indépendamment, créant plusieurs barrières contre les attaquants. Une compromission à un niveau ne doit pas permettre l'accès aux autres couches.

💡Les Piliers de la Sécurité K8s

1. Authentification et Autorisation (RBAC)

RBAC Architecture

Configuration RBAC granulaire

# ServiceAccount pour une application
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-service-account
  namespace: production
  annotations:
    description: "Service account for production app with minimal permissions"

---
# Role avec permissions minimales (principe du moindre privilège)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: app-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get"]
  resourceNames: ["app-config"] # Restriction sur des ressources spécifiques
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
  resourceNames: ["app-secrets"]

---
# RoleBinding pour lier le ServiceAccount au Role
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: app-role-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: app-service-account
  namespace: production
roleRef:
  kind: Role
  name: app-role
  apiGroup: rbac.authorization.k8s.io

ClusterRole pour permissions cross-namespace

# ClusterRole pour monitoring (lecture seule)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-reader
rules:
- apiGroups: [""]
  resources: ["nodes", "nodes/metrics", "services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["extensions", "apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics", "/metrics/cadvisor"]
  verbs: ["get"]

---
# ClusterRoleBinding pour Prometheus
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-monitoring
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: monitoring-reader
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: monitoring

2. Pod Security Standards

Pod Security Standards

Configuration des niveaux de sécurité

# Namespace avec Pod Security Standards stricts
apiVersion: v1
kind: Namespace
metadata:
  name: secure-production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/enforce-version: latest

Pod sécurisé avec SecurityContext

apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: secure-production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      serviceAccountName: app-service-account
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        fsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: app
        image: myapp:v1.2.3
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 10001
          capabilities:
            drop:
            - ALL
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"
          requests:
            memory: "256Mi"
            cpu: "250m"
        volumeMounts:
        - name: tmp-volume
          mountPath: /tmp
        - name: cache-volume
          mountPath: /app/cache
      volumes:
      - name: tmp-volume
        emptyDir: {}
      - name: cache-volume
        emptyDir: {}

💡Network Policies avancées

Network Policies

Politique de déni par défaut

# Deny all ingress and egress by default
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Politique granulaire pour microservices

# Allow specific communication between microservices
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-to-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

---
# Allow backend to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-to-database
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432
  # Allow DNS resolution
  - to: []
    ports:
    - protocol: UDP
      port: 53

Politique pour accès externe contrôlé

# Allow egress to specific external services
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-apis
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-client
  policyTypes:
  - Egress
  egress:
  # Allow HTTPS to external APIs
  - to: []
    ports:
    - protocol: TCP
      port: 443
  # Allow DNS
  - to: []
    ports:
    - protocol: UDP
      port: 53
  # Block all other egress

💡Gestion des Secrets et chiffrement

Secrets Management

External Secrets Operator avec HashiCorp Vault

# SecretStore configuration for Vault
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: production
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "external-secrets"
          serviceAccountRef:
            name: external-secrets-sa

---
# ExternalSecret to sync from Vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: app-secrets
    creationPolicy: Owner
  data:
  - secretKey: database-password
    remoteRef:
      key: myapp/database
      property: password
  - secretKey: api-key
    remoteRef:
      key: myapp/external-api
      property: key

Chiffrement des données au repos (etcd)

# EncryptionConfiguration for etcd
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  - configmaps
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <base64-encoded-32-byte-key>
  - identity: {}

💡Scanning de Sécurité et Monitoring

Security Scanning

Trivy pour scanner les vulnérabilités

# Trivy Operator configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: trivy-operator
  namespace: trivy-system
data:
  trivy.repository: "ghcr.io/aquasecurity/trivy"
  trivy.tag: "latest"
  trivy.severity: "CRITICAL,HIGH,MEDIUM"
  trivy.ignoreUnfixed: "false"
  trivy.timeout: "5m"

---
# VulnerabilityReport CRD example
apiVersion: aquasecurity.github.io/v1alpha1
kind: VulnerabilityReport
metadata:
  name: deployment-nginx
  namespace: default
spec:
  artifact:
    repository: nginx
    tag: "1.21"

Falco pour la détection d'anomalies runtime

# Falco configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: falco-config
  namespace: falco
data:
  falco.yaml: |
    rules_file:
      - /etc/falco/falco_rules.yaml
      - /etc/falco/k8s_audit_rules.yaml
    
    json_output: true
    json_include_output_property: true
    
    # Alerting channels
    http_output:
      enabled: true
      url: "http://webhook-service:8080/alerts"
    
    # Custom rules
    custom_rules.yaml: |
      - rule: Suspicious Network Activity
        desc: Detect suspicious network connections
        condition: >
          spawned_process and
          proc.name in (nc, ncat, netcat, socat) and
          not container.image.repository in (debug-tools)
        output: >
          Suspicious network tool executed
          (user=%user.name command=%proc.cmdline container=%container.name)
        priority: WARNING

OPA Gatekeeper pour les politiques

# Gatekeeper ConstraintTemplate
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredsecuritycontext
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredSecurityContext
      validation:
        properties:
          runAsNonRoot:
            type: boolean
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredsecuritycontext
        
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.securityContext.runAsNonRoot
          msg := "Container must run as non-root user"
        }

---
# Constraint using the template
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredSecurityContext
metadata:
  name: must-run-as-non-root
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
    namespaces: ["production", "staging"]
  parameters:
    runAsNonRoot: true

💡Sécurisation de l'API Server

API Server Security

Configuration sécurisée de l'API Server

# kube-apiserver configuration (via kubeadm)
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
apiServer:
  extraArgs:
    # Audit logging
    audit-log-path: /var/log/audit.log
    audit-log-maxage: "30"
    audit-log-maxbackup: "10"
    audit-log-maxsize: "100"
    audit-policy-file: /etc/kubernetes/audit-policy.yaml
    
    # Security settings
    enable-admission-plugins: "NodeRestriction,PodSecurityPolicy,ResourceQuota,LimitRanger"
    disable-admission-plugins: ""
    
    # Encryption at rest
    encryption-provider-config: /etc/kubernetes/encryption-config.yaml
    
    # Anonymous access
    anonymous-auth: "false"
    
    # RBAC
    authorization-mode: "Node,RBAC"
    
    # Secure communication
    tls-cipher-suites: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
    tls-min-version: "VersionTLS12"

Politique d'audit complète

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log all requests at RequestResponse level
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets", "configmaps"]
  
# Log all authentication failures
- level: Request
  users: ["system:anonymous"]
  
# Log all privilege escalation attempts
- level: RequestResponse
  verbs: ["create", "update", "patch"]
  resources:
  - group: "rbac.authorization.k8s.io"
    resources: ["clusterroles", "clusterrolebindings", "roles", "rolebindings"]
  
# Log exec and portforward requests
- level: Request
  verbs: ["create"]
  resources:
  - group: ""
    resources: ["pods/exec", "pods/portforward"]

💡Sécurisation des Nodes

Node Security

Configuration sécurisée du kubelet

# kubelet-config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
authorization:
  mode: Webhook
serverTLSBootstrap: true
protectKernelDefaults: true
makeIPTablesUtilChains: true
eventRecordQPS: 0
readOnlyPort: 0
streamingConnectionIdleTimeout: 4h

Hardening du système d'exploitation

#!/bin/bash
# node-hardening.sh - Script de durcissement des nodes

# Désactiver les services non nécessaires
systemctl disable cups
systemctl disable avahi-daemon
systemctl disable bluetooth

# Configuration du firewall
ufw --force enable
ufw default deny incoming
ufw default allow outgoing

# Autoriser seulement les ports nécessaires
ufw allow 22/tcp    # SSH
ufw allow 6443/tcp  # Kubernetes API
ufw allow 10250/tcp # kubelet
ufw allow 10251/tcp # kube-scheduler
ufw allow 10252/tcp # kube-controller-manager
ufw allow 2379:2380/tcp # etcd

# Durcissement du kernel
cat >> /etc/sysctl.d/99-kubernetes-security.conf << EOF
# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1

# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Ignore ping requests
net.ipv4.icmp_echo_ignore_all = 1
EOF

sysctl -p /etc/sysctl.d/99-kubernetes-security.conf

💡Monitoring et alerting de sécurité

Security Monitoring

Métriques de sécurité avec Prometheus

# ServiceMonitor for security metrics
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: security-metrics
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: security-exporter
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

---
# PrometheusRule for security alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: kubernetes-security-alerts
  namespace: monitoring
spec:
  groups:
  - name: kubernetes.security
    rules:
    - alert: PodSecurityViolation
      expr: increase(gatekeeper_violations_total[5m]) > 0
      for: 0m
      labels:
        severity: warning
      annotations:
        summary: "Pod security policy violation detected"
        description: "Gatekeeper detected {{ $value }} policy violations in the last 5 minutes"
    
    - alert: PrivilegedPodCreated
      expr: increase(kube_pod_container_status_running{container=~".*privileged.*"}[5m]) > 0
      for: 0m
      labels:
        severity: critical
      annotations:
        summary: "Privileged pod created"
        description: "A privileged pod has been created in namespace {{ $labels.namespace }}"
    
    - alert: RootUserInContainer
      expr: kube_pod_container_info{container_id!="",image!~".*debug.*"} * on(pod,namespace) group_left() kube_pod_container_status_running == 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Container running as root user"
        description: "Container {{ $labels.container }} in pod {{ $labels.pod }} is running as root"

💡Incident Response et forensics

Playbook de réponse aux incidents

# Incident response ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: incident-response-playbook
  namespace: security
data:
  playbook.yaml: |
    incident_types:
      - name: "Suspicious Pod Activity"
        steps:
          - "Isolate the affected pod using NetworkPolicy"
          - "Capture pod logs and events"
          - "Create memory dump if needed"
          - "Analyze container image for malware"
          - "Check for lateral movement"
      
      - name: "Privilege Escalation"
        steps:
          - "Immediately revoke elevated permissions"
          - "Audit all recent RBAC changes"
          - "Check for unauthorized ServiceAccount usage"
          - "Review admission controller logs"
    
    tools:
      - name: "kubectl"
        commands:
          - "kubectl get events --sort-by=.metadata.creationTimestamp"
          - "kubectl logs -f <pod-name> --previous"
          - "kubectl describe pod <pod-name>"
      
      - name: "crictl"
        commands:
          - "crictl ps -a"
          - "crictl logs <container-id>"
          - "crictl inspect <container-id>"

Script d'isolation automatique

#!/bin/bash
# isolate-pod.sh - Script d'isolation d'urgence

POD_NAME=$1
NAMESPACE=$2

if [[ -z "$POD_NAME" || -z "$NAMESPACE" ]]; then
    echo "Usage: $0 <pod-name> <namespace>"
    exit 1
fi

echo "🚨 Isolating pod $POD_NAME in namespace $NAMESPACE"

# Créer une NetworkPolicy d'isolation
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-$POD_NAME
  namespace: $NAMESPACE
spec:
  podSelector:
    matchLabels:
      app: $(kubectl get pod $POD_NAME -n $NAMESPACE -o jsonpath='{.metadata.labels.app}')
  policyTypes:
  - Ingress
  - Egress
  # Deny all traffic
EOF

# Capturer les logs
kubectl logs $POD_NAME -n $NAMESPACE --previous > /tmp/${POD_NAME}-previous.log
kubectl logs $POD_NAME -n $NAMESPACE > /tmp/${POD_NAME}-current.log

# Capturer les événements
kubectl get events -n $NAMESPACE --field-selector involvedObject.name=$POD_NAME > /tmp/${POD_NAME}-events.log

echo "✅ Pod isolated and logs captured in /tmp/"
echo "📋 Next steps:"
echo "   1. Analyze logs in /tmp/"
echo "   2. Check for indicators of compromise"
echo "   3. Consider scaling down the deployment"
echo "   4. Update incident response ticket"

💡Checklist de sécurité pour la production

Pré-déploiement

Post-déploiement

Maintenance continue

💡Outils essentiels pour la sécurité K8s

Scanner de vulnérabilités

Runtime Security

Policy Management

Secrets Management

💡Conclusion

La sécurité Kubernetes nécessite une approche multicouche et proactive :

Principes fondamentaux :

Surveillance continue :

Évolution permanente :

La sécurité n'est pas un état final mais un processus continu d'amélioration. Avec ces pratiques et outils, vous disposez d'une base solide pour sécuriser vos clusters Kubernetes en production.

Pour approfondir ces concepts et obtenir une formation pratique, consultez mes sessions spécialisées en sécurité Kubernetes et DevSecOps.

À propos de l'auteur

Florian Courouge - Expert DevOps et Apache Kafka avec plus de 5 ans d'expérience dans l'architecture de systèmes distribués et l'automatisation d'infrastructures.

Cet article vous a été utile ?

Découvrez mes autres articles techniques ou contactez-moi pour discuter de vos projets DevOps et Kafka.