L'ABC de la sécurité dans Kubernetes : authentification, autorisation, audit

L'ABC de la sécurité dans Kubernetes : authentification, autorisation, audit

Tôt ou tard, dans le fonctionnement de tout système, la question de la sécurité se pose : assurer l'authentification, la séparation des droits, l'audit et d'autres tâches. Déjà créé pour Kubernetes de nombreuses solutions, qui vous permettent d'être conforme aux normes même dans des environnements très exigeants... Le même matériel est consacré aux aspects de base de la sécurité mis en œuvre dans les mécanismes intégrés des K8. Tout d'abord, il sera utile à ceux qui commencent à se familiariser avec Kubernetes - comme point de départ pour étudier les questions liées à la sécurité.

Authentification

Il existe deux types d'utilisateurs dans Kubernetes :

  • les Comptes de service — comptes gérés par l'API Kubernetes ;
  • Utilisateurs — des utilisateurs « normaux » gérés par des services externes indépendants.

La principale différence entre ces types est que pour les comptes de service, il existe des objets spéciaux dans l'API Kubernetes (ils sont appelés ainsi : ServiceAccounts), qui sont liés à un espace de noms et à un ensemble de données d'autorisation stockées dans le cluster dans des objets de type Secrets. Ces utilisateurs (comptes de service) sont principalement destinés à gérer les droits d'accès à l'API Kubernetes des processus exécutés dans le cluster Kubernetes.

Les utilisateurs ordinaires n'ont pas d'entrées dans l'API Kubernetes : ils doivent être gérés par des mécanismes externes. Ils sont destinés aux personnes ou processus vivant en dehors du cluster.

Chaque demande d'API est associée soit à un compte de service, soit à un utilisateur, ou est considérée comme anonyme.

Les données d'authentification de l'utilisateur comprennent :

  • Nom d'utilisateur — nom d'utilisateur (sensible à la casse !) ;
  • UID - une chaîne d'identification de l'utilisateur lisible par machine qui est « plus cohérente et unique que le nom d'utilisateur » ;
  • Groupes — liste des groupes auxquels appartient l'utilisateur ;
  • Extra — des champs supplémentaires pouvant être utilisés par le mécanisme d'autorisation.

Kubernetes peut utiliser un grand nombre de mécanismes d'authentification : certificats X509, jetons Bearer, proxy d'authentification, HTTP Basic Auth. Grâce à ces mécanismes, vous pouvez implémenter un grand nombre de schémas d'autorisation : d'un fichier statique avec des mots de passe à OpenID OAuth2.

De plus, il est possible d'utiliser plusieurs régimes d'autorisation simultanément. Par défaut, le cluster utilise :

  • jetons de compte de service - pour les comptes de service ;
  • X509 - pour les utilisateurs.

La question de la gestion des ServiceAccounts dépasse le cadre de cet article, mais pour ceux qui souhaitent se familiariser plus en détail avec cette question, je recommande de commencer par pages de documentation officielle. Nous examinerons de plus près la question du fonctionnement des certificats X509.

Certificats pour les utilisateurs (X.509)

La manière classique de travailler avec des certificats implique :

  • génération de clé :
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • générer une demande de certificat :
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • traiter une demande de certificat à l'aide des clés CA du cluster Kubernetes, obtenir un certificat utilisateur (pour obtenir un certificat, vous devez utiliser un compte ayant accès à la clé CA du cluster Kubernetes, qui se trouve par défaut dans /etc/kubernetes/pki/ca.key):
    openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
  • création d'un fichier de configuration :
    • description du cluster (spécifiez l'adresse et l'emplacement du fichier de certificat CA pour une installation de cluster spécifique) :
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • ou comment aucunoption recommandée - vous n'avez pas besoin de spécifier le certificat racine (dans ce cas, kubectl ne vérifiera pas l'exactitude du serveur API du cluster) :
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • ajouter un utilisateur au fichier de configuration :
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • ajout de contexte :
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • affectation de contexte par défaut :
      kubectl config use-context mynewuser-context

Après les manipulations ci-dessus, dans le fichier .kube/config une configuration comme celle-ci sera créée :

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: https://192.168.100.200:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: target-namespace
    user: mynewuser
  name: mynewuser-context
current-context: mynewuser-context
kind: Config
preferences: {}
users:
- name: mynewuser
  user:
    client-certificate: /home/mynewuser/.certs/mynewuser.crt
    client-key: /home/mynewuser/.certs/mynewuser.key

Pour faciliter le transfert de la config entre comptes et serveurs, il est utile d'éditer les valeurs des clés suivantes :

  • certificate-authority
  • client-certificate
  • client-key

Pour ce faire, vous pouvez encoder les fichiers qui y sont spécifiés en base64 et les enregistrer dans la configuration, en ajoutant le suffixe au nom des clés -data, c'est à dire. avoir reçu certificate-authority-data etc

Certificats avec kubeadm

Avec la sortie Kubernetes 1.15 travailler avec des certificats est devenu beaucoup plus facile grâce à la version alpha de son support dans utilitaire Kubeadm. Par exemple, voici à quoi pourrait désormais ressembler la génération d'un fichier de configuration avec des clés utilisateur :

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: Requis adresse publicitaire peut être trouvé dans la configuration du serveur API, qui se trouve par défaut dans /etc/kubernetes/manifests/kube-apiserver.yaml.

La configuration résultante sera sortie sur la sortie standard. Il doit être enregistré dans ~/.kube/config compte utilisateur ou vers un fichier spécifié dans une variable d'environnement KUBECONFIG.

Creusez plus profondément

Pour ceux qui souhaitent mieux comprendre les problèmes décrits :

AUTORISATION

Le compte autorisé par défaut n'a pas le droit d'opérer sur le cluster. Pour accorder des autorisations, Kubernetes implémente un mécanisme d'autorisation.

Avant la version 1.6, Kubernetes utilisait un type d'autorisation appelé ABAC (Contrôle d'accès basé sur les attributs). Des détails à ce sujet peuvent être trouvés dans documents officiels. Cette approche est actuellement considérée comme héritée, mais vous pouvez toujours l'utiliser avec d'autres types d'authentification.

La manière actuelle (et plus flexible) de diviser les droits d'accès à un cluster s'appelle RBAC (Contrôle d'accès basé sur le rôle) (Contrôle d'accès basé sur les rôles). Il a été déclaré stable depuis la version Kubernetes 1.8. RBAC met en œuvre un modèle de droits dans lequel tout ce qui n'est pas explicitement autorisé est interdit.
Pour activer RBAC, vous devez démarrer le serveur API Kubernetes avec le paramètre --authorization-mode=RBAC. Les paramètres sont définis dans le manifeste avec la configuration du serveur API, qui se trouve par défaut le long du chemin /etc/kubernetes/manifests/kube-apiserver.yaml, dans la section command. Cependant, RBAC est déjà activé par défaut, vous ne devriez donc probablement pas vous en soucier : vous pouvez le vérifier par la valeur authorization-mode (dans le déjà mentionné kube-apiserver.yaml). À propos, parmi ses significations, il peut y avoir d'autres types d'autorisation (node, webhook, always allow), mais nous laisserons leur considération en dehors du cadre du matériel.

D'ailleurs, nous avons déjà publié статью avec une description assez détaillée des principes et des caractéristiques du travail avec RBAC, je me limiterai donc davantage à une brève liste des bases et des exemples.

Les entités API suivantes sont utilisées pour contrôler l'accès dans Kubernetes via RBAC :

  • Role и ClusterRole — les rôles qui servent à décrire les droits d'accès :
  • Role vous permet de décrire les droits au sein d'un espace de noms ;
  • ClusterRole - au sein du cluster, y compris vers des objets spécifiques au cluster tels que des nœuds, des URL non liées aux ressources (c'est-à-dire non liées aux ressources Kubernetes - par exemple, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - utilisé pour la reliure Role и ClusterRole à un utilisateur, un groupe d'utilisateurs ou un ServiceAccount.

Les entités Role et RoleBinding sont limitées par l'espace de noms, c'est-à-dire doit être dans le même espace de noms. Cependant, un RoleBinding peut référencer un ClusterRole, ce qui vous permet de créer un ensemble d'autorisations génériques et de contrôler l'accès à l'aide de celles-ci.

Les rôles décrivent les droits à l'aide d'ensembles de règles contenant :

  • Groupes API - voir documentation officielle par apiGroups et sortie kubectl api-resources;
  • ressources (numériques: pod, namespace, deployment et ainsi de suite.);
  • Verbes (verbes: set, update etc).
  • noms de ressources (resourceNames) - pour le cas où vous devez donner accès à une ressource spécifique, et non à toutes les ressources de ce type.

Une analyse plus détaillée de l'autorisation dans Kubernetes peut être trouvée sur la page documents officiels. A la place (ou plutôt en plus de cela), je donnerai des exemples qui illustrent son travail.

Exemples d'entités RBAC

Simple Role, qui vous permet d'obtenir une liste et l'état des pods et de les surveiller dans l'espace de noms target-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: target-namespace
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Exemple ClusterRole, qui vous permet d'obtenir une liste et l'état des pods et de les surveiller dans tout le cluster :

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Exemple RoleBinding, ce qui permet à l'utilisateur mynewuser "lire" les pods dans l'espace de noms my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

Audit d'événement

Schématiquement, l'architecture Kubernetes peut être représentée comme suit :

L'ABC de la sécurité dans Kubernetes : authentification, autorisation, audit

Le composant clé de Kubernetes responsable du traitement des requêtes est serveur api. Toutes les opérations sur le cluster passent par là. Vous pouvez en savoir plus sur ces mécanismes internes dans l'article «Que se passe-t-il dans Kubernetes lorsque vous exécutez kubectl run ?».

L'audit système est une fonctionnalité intéressante de Kubernetes, qui est désactivée par défaut. Il vous permet de consigner tous les appels à l'API Kubernetes. Comme vous pouvez le deviner, toutes les actions liées à la surveillance et à la modification de l'état du cluster sont effectuées via cette API. Une bonne description de ses capacités peut (comme d'habitude) être trouvée dans documents officiels K8. Ensuite, j'essaierai de présenter le sujet dans un langage plus simple.

ainsi, pour permettre l'audit, nous devons transmettre trois paramètres requis au conteneur dans le serveur API, qui sont décrits plus en détail ci-dessous :

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

En plus de ces trois paramètres nécessaires, il existe de nombreux paramètres supplémentaires liés à l'audit : de la rotation des journaux aux descriptions des webhooks. Exemple de paramètres de rotation des journaux :

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

Mais nous ne nous y attarderons pas plus en détail - vous pouvez retrouver tous les détails dans documentation du serveur Kube-Api.

Comme déjà mentionné, tous les paramètres sont définis dans le manifeste avec la configuration du serveur API (par défaut /etc/kubernetes/manifests/kube-apiserver.yaml), dans la rubrique command. Revenons sur les 3 paramètres requis et analysons-les :

  1. audit-policy-file — chemin d'accès au fichier YAML décrivant la politique d'audit. Nous reviendrons sur son contenu plus tard, mais pour l'instant je noterai que le fichier doit être lisible par le processus api-server. Par conséquent, il est nécessaire de le monter à l'intérieur du conteneur, pour lequel vous pouvez ajouter le code suivant aux sections appropriées de la configuration :
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path - chemin d'accès au fichier journal. Le chemin doit également être accessible au processus api-server, nous décrivons donc son montage de la même manière :
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — format du journal d'audit. La valeur par défaut est json, mais l'ancien format de texte est également disponible (legacy).

Politique d'audit

Parlons maintenant du fichier mentionné décrivant la politique de journalisation. Le premier concept de politique d’audit est level, niveau de journalisation. Ils sont les suivants :

  • None - ne vous connectez pas ;
  • Metadata — métadonnées de la demande de journalisation : utilisateur, heure de la demande, ressource cible (pod, espace de noms, etc.), type d'action (verbe), etc. ;
  • Request — enregistrer les métadonnées et le corps de la demande ;
  • RequestResponse - enregistrer les métadonnées, le corps de la demande et le corps de la réponse.

Les deux derniers niveaux (Request и RequestResponse) n'enregistre pas les requêtes qui n'ont pas accédé aux ressources (accès aux URL dites non-ressources).

De plus, toutes les demandes passent plusieurs étapes:

  • RequestReceived — l'étape au cours de laquelle la demande est reçue par le processeur et n'a pas encore été transmise plus loin dans la chaîne des processeurs ;
  • ResponseStarted — les en-têtes de réponse sont envoyés, mais avant l'envoi du corps de la réponse. Généré pour les requêtes de longue durée (par exemple, watch);
  • ResponseComplete — le corps de la réponse a été envoyé, aucune autre information ne sera envoyée ;
  • Panic — des événements sont générés lorsqu'une situation anormale est détectée.

Pour ignorer toutes les étapes que vous pouvez utiliser omitStages.

Dans un fichier de stratégie, nous pouvons décrire plusieurs sections avec différents niveaux de journalisation. La première règle de correspondance trouvée dans la description de la stratégie sera appliquée.

Le démon kubelet surveille les modifications dans le manifeste avec la configuration du serveur API et, le cas échéant, redémarre le conteneur avec le serveur API. Mais il y a un détail important : les modifications dans le fichier de stratégie seront ignorées par celui-ci. Après avoir modifié le fichier de stratégie, vous devrez redémarrer le serveur API manuellement. Puisque le serveur API est démarré en tant que nacelle statique, équipe kubectl delete ne le fera pas redémarrer. Vous devrez le faire manuellement docker stop sur kube-masters, où la politique d'audit a été modifiée :

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

Lors de l'activation de l'audit, il est important de se rappeler que la charge sur kube-apiserver augmente. En particulier, la consommation de mémoire pour stocker le contexte de la requête augmente. La journalisation ne commence qu'après l'envoi de l'en-tête de réponse. La charge dépend également de la configuration de la stratégie d'audit.

Exemples de politiques

Examinons la structure des fichiers de stratégie à l'aide d'exemples.

Voici un fichier simple policypour tout enregistrer au niveau Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

Dans la stratégie, vous pouvez spécifier une liste d'utilisateurs (Users и ServiceAccounts) et les groupes d'utilisateurs. Par exemple, c'est ainsi que nous ignorerons les utilisateurs du système, mais enregistrerons tout le reste au niveau Request:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: None
    userGroups:
      - "system:serviceaccounts"
      - "system:nodes"
    users:
      - "system:anonymous"
      - "system:apiserver"
      - "system:kube-controller-manager"
      - "system:kube-scheduler"
  - level: Request

Il est également possible de décrire les cibles :

  • espaces de noms (namespaces);
  • Verbes (verbes: get, update, delete et d'autres);
  • ressources (numériques, Comme suit: pod, configmaps etc.) et les groupes de ressources (apiGroups).

Faites attention! Les ressources et groupes de ressources (groupes API, c'est-à-dire apiGroups), ainsi que leurs versions installées dans le cluster, peuvent être obtenus à l'aide des commandes :

kubectl api-resources
kubectl api-versions

La politique d'audit suivante est fournie à titre de démonstration des meilleures pratiques en matière de Documentation Alibaba Cloud:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Не логировать стадию RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Не логировать события, считающиеся малозначительными и не опасными:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # это api group с пустым именем, к которому относятся
                  # базовые ресурсы Kubernetes, называемые “core”
        resources: ["endpoints", "services"]
  - level: None
    users: ["system:unsecured"]
    namespaces: ["kube-system"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["configmaps"]
  - level: None
    users: ["kubelet"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    userGroups: ["system:nodes"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    users:
      - system:kube-controller-manager
      - system:kube-scheduler
      - system:serviceaccount:kube-system:endpoint-controller
    verbs: ["get", "update"]
    namespaces: ["kube-system"]
    resources:
      - group: "" # core
        resources: ["endpoints"]
  - level: None
    users: ["system:apiserver"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["namespaces"]
  # Не логировать обращения к read-only URLs:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Не логировать сообщения, относящиеся к типу ресурсов “события”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Ресурсы типа Secret, ConfigMap и TokenReview могут содержать  секретные данные,
  # поэтому логируем только метаданные связанных с ними запросов
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Действия типа get, list и watch могут быть ресурсоёмкими; не логируем их
  - level: Request
    verbs: ["get", "list", "watch"]
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для стандартных ресурсов API
  - level: RequestResponse
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для всех остальных запросов
  - level: Metadata

Un autre bon exemple de politique d’audit est profil utilisé dans GCE.

Pour répondre rapidement aux événements d'audit, il est possible décrire le webhook. Cette question est abordée dans documents officiels, je vais le laisser en dehors du cadre de cet article.

Les résultats de

L'article donne un aperçu des mécanismes de sécurité de base dans les clusters Kubernetes, qui vous permettent de créer des comptes d'utilisateurs personnalisés, de séparer leurs droits et d'enregistrer leurs actions. J'espère qu'il sera utile à ceux qui sont confrontés à de tels problèmes en théorie ou en pratique. Je vous recommande également de lire la liste d'autres documents sur le thème de la sécurité dans Kubernetes, qui est donnée dans "PS" - vous trouverez peut-être parmi eux les détails nécessaires sur les problèmes qui vous concernent.

PS

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire