object.title
En route vers la certification CKS (Certified Kubernetes Security Specialist)

Par Mickaël D., Expert DevOps

Au lieu d'un seul article global sur la préparation d'une certification, comme j'ai pu vous le proposer par le passé, je vais initier une série d'articles qui vous aideront à mieux comprendre les différents sujets sur lesquels vous serez interrogés (si vous souhaitez la passer). 

Dans ce dossier, nous aborderons :

  1. Le Cluster Setup, 
  2. Le Cluster Hardening, 
  3. Le System Hardening, 
  4. Les Microservices Vulnerabilities, 
  5. Le Supply Chain Security, 
  6. Le Monitoring, Logging and Runtime Security. 

Network Security Policies

Ce premier article se focalisera sur le premier aspect, à savoir Cluster Setup, et traitera de plusieurs points tels que : 

  • Les Network Security Policies
  • CIS Benchmark afin de vérifier le niveau de sécurité de configuration de chaque composant de Kubernetes, 
  • La sécurisation des Ingress Controllers
  • La protection métadonnées des Nodes
  • L'usage de l'UI de Kubernetes et sa sécurisation, 
  • La vérification des binaires avant déploiement.

Que sont les Network Security Policies ? 

Il s'agit d'instructions destinées à spécifier comment un Pod peut communiquer avec des entités du réseau selon une combinaison d'identifiants : 

  • Les autres pods (à l'exception de lui-même), 
  • Les Namespaces avec lesquels il peut communiquer, 
  • Les blocs d'IP. Attention, dans ce cas, un Pod peut accéder à n'importe quel autre Pod situé sur le même Node

Lorsque l'on définit une Security Policy relative à un Pod ou à un Namespace, on fait appel à un Selector pour spécifier quel trafic est permis depuis ou vers le Pod/Namespace en rapport avec le selector

À SAVOIR : 

  • Par défaut, les Pods acceptent du trafic de n'importe quelle source. 
  • Les NetworkPolicies s'additionnent et n'entrent pas en conflit entre eux.
  • Un seul prérequis : un plugin Network ou CNI qui prends en charge les Network Policy !

Quelques exemples :

1. Limiter le trafic vers une application

yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: api-allow
spec:
  podSelector:
    matchLabels:
      app: bookstore
      role: api
  ingress:
  - from:
      - podSelector:
          matchLabels:
            app: bookstore

2. Refuser le trafic vers l'extérieur du cluster Kubernetes

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: foo-deny-external-egress
spec:
  podSelector:
    matchLabels:
      app: foo
  policyTypes:
  - Egress
  egress:
  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP
  - to:
    - namespaceSelector: {}

3. Refuser tout trafic non whitelisté vers un namespace

yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  ingress: []

CIS Benchmarks

Le CIS (Center for Internet Security) est un consortium à but non lucratif mettant à disposition des guides et outils pour sécuriser les environnements informatiques. C'est un peu comme l'ANSSI en France.

Par défaut, un système peut être vulnérable à de nombreux types d'attaques et il est important de pouvoir le sécuriser un maximum. On parle d'hardening quand on sécurise la configuration et le fonctionnement d'un système.

Deux exemples :

  1. Dans le cas d'un serveur sur lequel des ports USB sont disponibles et que leurs utilisations n’ont pas été prévues, ceux-ci doivent être désactivés afin de prévenir tout types d'attaques par ce vecteur. 
  2. Quels utilisateurs ont accès au système et peuvent se connecter en tant que root ? Si ceux-ci effectuent des changements impactant le fonctionnement des services, il pourrait être impossible de connaître l'auteur des modifications. 

C'est pour cela que les best practices recommandent de désactiver le compte root et de se connecter avec son propre compte puis d'élever ses propres privilèges (à l'aide de sudo). 

Autres exemples, seuls les services et/ou filesystems utiles au fonctionnement du server devront être activés...Tout comme seuls les ports vraiment nécessaires doivent être ouverts et donc configurer le firewall de manière la plus fine possible. 

Le site CIS propose de nombreux benchmark et Framework d'hardening pour : 

  • Les Systèmes d'Exploitation Linux, Windows, OSX ainsi que mobile iOS et Android, 
  • Les plateformes Cloud AWS, Azure, Google
  • Les matériels réseau provenant de CheckPoint, Cisco, Juniper et Palo Alto
  • Ainsi que des middlewares tels que Tomcat, Docker ou encore Kubernetes.

CIS Benchmark appliqué à Kubernetes : kube-bench

Kube-bench est une application développée en GO, s'appuyant un maximum sur les recommandations de sécurité de CIS avec une configuration très évolutive grâce à l'utilisation de fichier en yaml et pouvant être utilisé de plusieurs manières différentes : 

  • En l'installation depuis un conteneur
  • En l'installation grâce au binaire téléchargé
  • En compilant les sources
  • En l'exécutant depuis un conteneur, que ce soit un conteneur isolé ou dans un cluster Kubernetes ou Openshift.

Kube-bench exécute les contrôles défini dans un fichier yaml nommé control.yaml et peut s'appliquer tout type de nodes de type master ou worker (peu importe la version).

id: 1.2
  text: Scheduler
  checks:
    - id: 1.2.1
      text: "Ensure that the --profiling argument is set to false (Scored)"
      audit: "ps -ef | grep kube-scheduler | grep -v grep"
      tests:
        bin_op: or
        test_items:
          - flag: "--profiling"
            set: true
          - flag: "--some-other-flag"
            set: false
      remediation: "Edit the /etc/kubernetes/config file on the master node and
        set the KUBE_ALLOW_PRIV parameter to '--allow-privileged=false'"
      scored: true

Une fois les tests effectués par kube-bench, les résultats sont enregistrés dans un fichier et chaque contrôle indique un état en fonction des quatre suivants : 

  • PASS, Le contrôle a été effectué avec succès. 
  • FAIL, le contrôle est un échec, mais la remédiation décrit comment corriger la configuration afin que, lors du prochain contrôle, celui soit OK. 
  • WARN, le test nécessite une attention particulière, vérifier la remédiation pour plus d'informations. Il ne s'agit pas forcément d'un rapport d'erreur. 
  • INFO

L'usage de l'UI de Kubernetes et sa sécurisation

Il s'agit ici de savoir comment installer le Dashboard de Kubernetes et de le sécuriser le mieux possible.  

Le Dashboard Kubernetes se déploie à l'aide de la commande suivante :

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml` et pour y accéder : `kubectl proxy --address 0.0.0.0.   

Il faut savoir que : 

  • Kubernetes supporte quatre modes d'authentification
  • Ceux-ci sont gérés par l'API de Kubernetes
  • Le Dashboard ne sert que de proxy et fait office de passe-plat vers Kubernetes pour toutes les informations relatives à l'authentification. 

Les attaques par le Front-end de Kubernetes sont nombreuses et ont été pendant longtemps le premier vecteur d'attaque.

L'authentification

Comme évoqué plus tôt, Kubernetes supporte quatre modes d'authentification parmi les suivants : 

  • Bearer Token, 
  • Username/Password, 
  • Kubeconfig,
  • Authorization Header (supporté depuis le version 1.6 et dispose de la priorité la plus élevée).

Les Bearer Tokens

Pour les configurer le plus efficacement possible, il est nécessaire d'être extrêmement familier avec les concepts de Service Account, Role, Cluster Role, et les permissions qui peuvent leur être attribuées.

ServiceAccount 

yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
EOF

ClusterRoleBinding

yaml
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard

Une fois les deux objets précédemment créés, on peut obtenir le Bearer Token grâce à la commande suivante :
kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"

Username/Password

Désactivé par défaut, car l'API de Kubernetes a besoin d'une configuration au niveau des attributs et non au niveau des rôles.

Kubeconfig

Avec ce mode d'authentification, seules les options spécifiées par le flag authentication-mode sont prise en charge dans le fichier sus-nommé. Dans le cas contraire, une erreur s’affiche dans le Dashboard.

Authorization Header

Pour ce type de méthode d'authentification, le Bearer Token sera nécessaire car vous en aurez besoin lors de chaque requête vers le Dashboard.

La vérification des binaires pré-installation

Il s'agit ni plus ni moins que de vérifier la valeur du hash des binaires relatifs à Kubernetes et de les comparer avec ceux que vous téléchargez sur votre serveur...au cas où votre action se ferait intercepter par un hacker. 

Même si le dit « hacker » modifie un fichier de l'archive, il faut savoir que toute modification d'une archive modifie également la valeur de son hash

Pour cela, une fois le téléchargement terminé, vous pouvez exécuter la commande suivante : shasum -a 512 kubernetes.tar.gz et comparer la valeur obtenue avec ce qui est affichée sur la page de téléchargement.

Par exemple, en téléchargeant :

kubeadm en version 1.21.0 dont la valeur de hash est 7bdaf0d58f0d286538376bc40b50d7e3ab60a3fe7a0709194f53f1605129550f

Je vais obtenir la même valeur de hash, une fois l'archive téléchargée (cette fois-ci avec la commande shasum -a 256 kubeadm

La sécurisation des Ingress Controllers

Tout d'abord : qu'est-ce qu'un Ingress Controller ? 

Il s'agit d'un objet Kubernetes qui gère l'accès externe aux services dans un cluster, généralement du trafic HTTP et peut également fournir des fonctionnalités de type équilibrage de charge. 

Les sujets traités dans cette partie seront : 

  • La création de certificats TLS
  • La création de secrets (intégrant les certificats TLS) dans Kubernetes,
  • La configuration d'Ingress Controllers intégrant les secrets.

Création d'un certificat TLS

Partant du principe que vous avez déjà créé votre Ingress Controller et qu'il est accessible en HTTP, la prochaine étape est de sécuriser son contenu à l'aide de HTTPS...et par conséquent de créer un certificat TLS auto-signé :

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

Création du secret

Une fois la paire clé/certificat créé, et à moins d'avoir déjà déployé cert manager dans Kubernetes, il faut créer un secret afin de pouvoir intégrer, par la suite, le certificat TLS à l'Ingress controller :

kubectl create secret tls-secure-ingress --cert=cert.pem --key=key.pem

Configuration de l'Ingress Controller

Le certificat TLS et le secret créés, la dernière étape est d'intégrer le secret dans l'Ingress Controller.

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
  - hosts:
      - test-secure-ingress.com
    secretName: tls-secure-ingress
  rules:
  - host: test-secure-ingress.com
    http:
      paths:
      - path: /service1
        pathType: Prefix
        backend:
          service: 
            name: service1
            port:
              number: 80
      - path: /service2
        pathType: Prefix
        backend:
          service: 
            name: service2
            port:
              number: 80

La protection meta-données des Nodes

Les Nodes Metadatas... De quoi s'agit-il ?

Toutes les machines virtuelles (nœuds) hébergées dans le Cloud devraient accéder au Endpoints des Nodes Metadata pour diverses raisons. Cependant, permettre l'accès à toutes les ressources n'est pas recommandé.

Pour améliorer la sécurité à ce niveau, il faut appliquer des Network Policies, de sorte que seules les ressources désignées au sein des Clusters Kubernetes pourraient avoir la capacité de contacter les Endpoints des Nodes Metadata

Toutes les informations dont vous pourriez avoir besoin sur le sujet se trouvent ici : 

Network Policies

Le principe des Network Policies est de gérer la communication Pod-to-Pod, Pod-to-Service et External-to-Service, de la même manière qu'un Firewall. L'identification des ressources impactées restant à la charge des administrateurs via des labels, des namespaces ou des adresses IP

La documentation officielle donne, par exemple, ceci : 

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Ici, ce qui nous intéresse, c'est principalement la possibilité de bloquer l'accès aux Metadata Endpoint à l'aide des Network Policies à un ou plusieurs Pods (cf. ci-dessous) : 

Deny trafic to metadata

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: cloud-metadata-deny
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
          - <POD_IP_ADDRESS>

Allow trafic to metadata

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: cloud-metadata-allow
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: metadata-accessor
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
          - <POD_IP_ADDRESS>

Le prochain article traitera de toutes les problématiques relatives au cluster hardening, à savoir :

  • Les restrictions d'accès à l'API de Kubernetes, 
  • L'usage des Role Based Access Control dans le but de minimiser l'exposition, 
  • Le fine tuning des ServiceAccounts, 
  • La fréquence des mises à jour de Kubernetes.