Utiliser la fonctionnalité de journalisation des règles de réseau


Cette page explique comment utiliser la journalisation des règles de réseau pour Google Kubernetes Engine (GKE).

Présentation

Les règles de réseau spécifient le trafic réseau que les pods sont autorisés à envoyer et à recevoir. La journalisation des règles de réseau vous permet de créer un enregistrement lorsqu'une connexion est autorisée ou refusée par une règle de réseau. Grâce à la journalisation des règles de réseau, vous pouvez :

  • Vérifier que vos règles de réseau fonctionnent comme prévu.
  • Identifier les pods de votre cluster qui communiquent avec Internet.
  • Identifier les espaces de noms qui communiquent entre eux.
  • Reconnaître une attaque par déni de service.

Les journaux des règles de réseau sont importés dans Cloud Logging pour le stockage, la recherche, l'analyse et les alertes si Cloud Logging est activé. Cloud Logging est activé par défaut dans les nouveaux clusters. Pour en savoir plus, consultez la page Installer l'assistance de la suite d'opérations Cloud pour GKE.

Exigences

  • La journalisation des règles de réseau n'est disponible que pour les clusters qui utilisent Dataplane V2.
  • La journalisation des règles de réseau nécessite le SDK Cloud 303.0.0 ou une version ultérieure.
  • La journalisation des règles de réseau n'est pas compatible avec les pools de nœuds Windows Server.

Tarifs

  • Aucuns frais de génération de journaux ne sont facturés pour la journalisation des règles de réseau.
  • Si vous stockez vos journaux dans Cloud Logging, les tarifs standards de Cloud Logging s'appliquent.
  • Les journaux peuvent également être exportés vers Cloud Pub/Sub, Cloud Storage ou BigQuery. Des frais liés à Pub/Sub, Cloud Storage ou BigQuery peuvent s'appliquer. Pour en savoir plus sur l'exportation des journaux, consultez la page Présentation des exportations de journaux.

Configurer la journalisation des règles de réseau

Pour configurer les paramètres de journalisation des règles de réseau, modifiez l'objet NetworkLogging dans votre cluster. GKE crée automatiquement un objet NetworkLogging nommé default dans les nouveaux clusters Dataplane V2. Il ne peut y avoir qu'un seul objet NetworkLogging par cluster et il ne peut pas être renommé.

Vous pouvez configurer la journalisation des connexions autorisées et celle des connexions refusées séparément. Vous pouvez également activer de manière sélective la journalisation pour certaines règles de réseau. Voici un exemple de spécification NetworkLogging, les paramètres étant spécifiés pour enregistrer toutes les connexions autorisées et refusées :

kind: NetworkLogging
apiVersion: networking.gke.io/v1alpha1
metadata:
  name: default
spec:
  cluster:
    allow:
      log: true
      delegate: false
    deny:
      log: true
      delegate: false

Modifiez votre configuration à l'aide de kubectl :

kubectl edit networklogging default

Spécification NetworkLogging

La spécification d'objet NetworkLogging est au format YAML. Ce format est décrit dans le tableau suivant :

ChampTypeDescription
cluster.allowstruct Paramètres de journalisation des connexions autorisées.
ChampTypeDescription
log bool

Si la valeur est définie sur true, les connexions autorisées dans le cluster sont consignées. Dans le cas contraire, les connexions autorisées ne sont pas consignées.

Les règles de réseau qui sélectionnent le pod et qui possèdent une règle correspondant à la connexion sont répertoriées dans le message de journal.

delegate bool

Si la valeur est false, toutes les connexions autorisées sont consignées. Si plusieurs règles de réseau autorisent une connexion, toutes les règles correspondantes sont répertoriées dans le message du journal.

Si la valeur est définie sur true, les connexions autorisées ne sont consignées que si elles sont autorisées par une règle de réseau avec l'annotation de journalisation policy.network.gke.io/enable-logging: "true". Si plusieurs règles de réseau autorisent une connexion, toutes les règles de correspondance avec l'annotation enable-logging sont répertoriées dans le message de journal.

Une erreur de configuration survient si vous définissez spec.cluster.allow.delegate sur true et spec.cluster.allow.log sur false.

cluster.deny struct Paramètres de journalisation des connexions refusées.
ChampTypeDescription
log bool

Si la valeur est définie sur true, les connexions refusées dans le cluster sont consignées. Dans le cas contraire, les connexions refusées ne sont pas consignées.

delegate bool

Si la valeur est définie sur false, toutes les connexions refusées sont consignées.

Si la valeur est définie sur true, les connexions refusées ne sont consignées que si le pod dans lequel la connexion a été refusée se trouve dans un espace de noms comportant l'annotation policy.network.gke.io/enable-deny-logging: "true".

Une erreur de configuration survient si vous définissez spec.cluster.deny.delegate sur true et spec.cluster.deny.log sur false.

Accès aux journaux

Les journaux des règles de réseau générés sur chaque nœud de cluster sont disponibles localement à l'emplacement suivant : /var/log/network/policy_action.log*. Un fichier journal numéroté est créé lorsque le fichier journal actuel atteint 10 Mo. Vous pouvez stocker jusqu'à cinq fichiers journaux précédents.

Les journaux des règles de réseau sont automatiquement importés dans Cloud Logging. Vous pouvez accéder aux journaux via l'explorateur de journaux ou avec l'outil de ligne de commande gcloud. Vous pouvez également exporter les journaux depuis Cloud Logging vers le récepteur de votre choix.

gcloud

gcloud logging read --project "PROJECT_NAME" 'resource.type="k8s_node" \
    resource.labels.location="CLUSTER_LOCATION" \
    resource.labels.cluster_name="CLUSTER_NAME" \
    logName="projects/PROJECT_NAME/logs/policy-action"'

Remplacez les éléments suivants :

  • PROJECT_NAME : le nom de votre projet Google Cloud
  • CLUSTER_LOCATION : la zone dans laquelle se trouve le cluster
  • CLUSTER_NAME : le nom du cluster

Cloud Logging

  1. Accédez à la page Explorateur de journaux dans Cloud Console.

    Accéder à l'explorateur de journaux

  2. Cliquez sur Générateur de requêtes.

  3. Utilisez la requête suivante pour rechercher tous les enregistrements du journal des règles de réseau :

    resource.type="k8s_node"
    resource.labels.location="CLUSTER_LOCATION"
    resource.labels.cluster_name="CLUSTER_NAME"
    logName="projects/PROJECT_NAME/logs/policy-action"
    

    Remplacez l'élément suivant :

    • CLUSTER_LOCATION : la zone dans laquelle se trouve le cluster
    • CLUSTER_NAME : le nom du cluster
    • PROJECT_NAME : le nom de votre projet Google Cloud

Consultez la page Utiliser l'explorateur de journaux pour apprendre à l'utiliser.

Vous pouvez également créer une requête à l'aide du Générateur de requêtes. Pour créer une requête pour les journaux des règles de réseau, sélectionnez policy-action dans la liste déroulante Nom du journal. Si aucun journal n'est disponible, policy-action ne s'affiche pas dans la liste déroulante.

Vous pouvez ajouter des conditions supplémentaires pour filtrer les résultats. Exemple :

  • Afficher les journaux sur une période spécifique :

    timestamp>="2020-06-22T06:30:51.128Z"
    timestamp<="2020-06-23T06:30:51.128Z"
    
  • Afficher les journaux liés aux connexions refusées :

    jsonPayload.disposition="deny"
    
  • Afficher les journaux dans un déploiement nommé "redis" :

    jsonPayload.dest.pod_name=~"redis"
    jsonPayload.dest.pod_namespace="default"
    
  • Afficher les journaux des connexions externes au cluster :

    jsonPayload.dest.instance != ""
    
  • Afficher les journaux correspondant à une règle de réseau spécifique ("allow-frontend-to-db", dans ce cas) :

    jsonPayload.policies.name="allow-frontend-to-db"
    jsonPayload.policies.namespace="default"
    

Format du journal

Les enregistrements du journal des règles de réseau sont au format JSON. Ce format est décrit dans le tableau suivant :

ChampTypeDescription
connectionstruct Informations de connexion
ChampTypeDescription
src_ipstringAdresse IP source de la connexion.
src_portintPort source de la connexion.
dest_ipstringAdresse IP de destination de la connexion.
dest_portintPort de destination de la connexion.
protocolstringProtocole de la connexion, qui peut être tcp, udp ou icmp.
directionstringSens de la connexion, qui peut être ingress ou egress.
srcstruct Informations sur le point de terminaison de la source :
ChampTypeDescription
pod_namestringNom du pod, si la source est un pod.
pod_namespace (deprecated)stringEspace de noms du pod, si la source est un pod. pod_namespace est obsolète (utilisez plutôt namespace).
namespacestringEspace de noms du pod, si la source est un pod.
workload_namestringNom de la charge de travail, si la charge de travail source est disponible.
workload_kindstringGenre de la charge de travail, si la charge de travail source est disponible.
instancestringAdresse IP de la source, si celle-ci n'est pas un pod.
deststruct Informations sur le point de terminaison de la destination :
ChampTypeDescription
pod_namestringNom du pod, si la destination est un pod.
pod_namespace (deprecated)stringEspace de noms du pod, si la destination est un pod. pod_namespace est obsolète (utilisez plutôt namespace).
namespacestringEspace de noms du pod, si la destination est un pod.
workload_namestringNom de la charge de travail, si la charge de travail de destination est disponible
workload_kindstringGenre de la charge de travail, si la charge de travail de destination est disponible
instancestringAdresse IP de la source, si la destination n'est pas un pod.
dispositionstringDisposition de la connexion, qui peut être allow ou deny.
policieslist of structs

Règles de correspondance pour les connexions autorisées à partir de la vue du pod mis en œuvre. Pour une connexion d'entrée, le pod mis en œuvre est le pod de destination. Pour une connexion de sortie, le pod mis en œuvre est le pod source. Plusieurs règles peuvent être consignées si la connexion correspond à l'intégralité de ces règles.

Ce champ n'est inclus que dans les journaux des connexions autorisées.

ChampTypeDescription
namestringNom de la règle de réseau correspondante.
namespacestringEspace de noms de la règle de réseau correspondante.
countintUtilisé pour l'agrégation de journaux des requêtes refusées. La valeur est toujours égale à 1 pour les connexions autorisées.
node_namestringNœud qui exécute le pod ayant généré ce message de journal.
timestampstringHeure de la tentative de connexion.

Définition de la connexion

Pour les protocoles orientés connexion tels que TCP, un journal est créé pour chaque connexion autorisée ou refusée. Pour les protocoles tels que UDP et ICMP, qui ne sont pas orientés connexion, les paquets sont regroupés en connexions basées sur une fenêtre de temps.

Journaux de règle pour les connexions refusées

Les enregistrements du journal des connexions refusées n'incluent pas le champ policies, car l'API des règles de réseau Kubernetes ne dispose pas de règles de refus explicites. Une connexion est refusée si un pod est couvert par une ou plusieurs règles réseau, mais qu'aucune de ces règles n'autorise la connexion. Cela signifie qu'aucune règle n'est seule responsable d'une connexion bloquée.

Agrégation de journaux pour les connexions refusées

Il arrive souvent qu'un client tente à nouveau d'établir une connexion refusée. Pour éviter toute journalisation excessive, les connexions refusées répétées pendant une période de cinq secondes sont regroupées dans un seul message de journal utilisant le champ count.

Les connexions refusées suivantes sont agrégées avec un précédent message de journal si les valeurs src_ip, dest_ip, dest_port, protocol, et direction de la connexion correspondent à la première connexion refusée. Notez que le champ src_port des connexions suivantes ne doit pas nécessairement correspondre, car les nouvelles tentatives de connexion peuvent provenir d'un port différent. Le message de journal agrégé inclut la valeur src_prt de la première connexion refusée au début de la fenêtre d'agrégation.

Exemples d'enregistrements de journal

L'exemple de règle réseau suivant, appelé allow-green et appliqué à test-service, autorise les connexions à test-service depuis un pod nommé client-green. Implicitement, cette règle refuse tout autre trafic entrant vers test-service, y compris à partir du pod client-red.

  apiVersion: networking.k8s.io/v1
  kind: NetworkPolicy
  metadata:
    name: allow-green
    namespace: default
    annotations:
      policy.network.gke.io/enable-logging: "true"
  spec:
    podSelector:
      matchLabels:
        app: test-service
    ingress:
    - from:
      - podSelector:
          matchLabels:
            app: client-green
    policyTypes:
    - Ingress

Le schéma suivant montre l'effet de la règle allow-green sur deux connexions à test-service. La règle allow-green autorise la connexion depuis client-green. Comme aucune règle ne permet d'établir la connexion depuis client-red, la connexion est refusée.

L'entrée de journal de la connexion autorisée depuis client-green ressemble à ce qui suit :

{
   "connection":{
      "src_ip":"10.84.0.252",
      "dest_ip":"10.84.0.165",
      "src_port":52648,
      "dest_port":8080,
      "protocol":"tcp",
      "direction":"ingress"
   },
   "disposition":"allow",
   "policies":[
      {
         "name":"allow-green",
         "namespace":"default"
      }
   ],
   "src":{
      "pod_name":"client-green-7b78d7c957-68mv4",
      "pod_namespace":"default",
      "namespace":"default",
      "workload_name":"client-green-7b78d7c957",
      "workload_kind":"ReplicaSet"
   },
   "dest":{
      "pod_name":"test-service-745c798fc9-sfd9h",
      "pod_namespace":"default",
      "namespace":"default",
      "workload_name":"test-service-745c798fc9",
      "workload_kind":"ReplicaSet"
   },
   "count":1,
   "node_name":"gke-demo-default-pool-5dad52ed-k0h1",
   "timestamp":"2020-06-16T03:10:37.993712906Z"
}

L'entrée de journal de la connexion refusée depuis client-red ressemble à ce qui suit :

{
   "connection":{
      "src_ip":"10.84.0.180",
      "dest_ip":"10.84.0.165",
      "src_port":39610,
      "dest_port":8080,
      "protocol":"tcp",
      "direction":"ingress"
   },
   "disposition":"deny",
   "src":{
      "pod_name":"client-red-5689846f5b-b5ccx",
      "pod_namespace":"default",
      "namespace":"default",
      "workload_name":"client-red-5689846f5b",
      "workload_kind":"ReplicaSet"
   },
   "dest":{
      "pod_name":"test-service-745c798fc9-sfd9h",
      "pod_namespace":"default",
      "namespace":"default",
      "workload_name":"test-service-745c798fc9",
      "workload_kind":"ReplicaSet"
   },
   "count":3,
   "node_name":"gke-demo-default-pool-5dad52ed-k0h1",
   "timestamp":"2020-06-15T22:38:32.189649531Z"
}

Notez que le journal des connexions refusées n'inclut pas le champ policies. Cette procédure est décrite dans la section précédente, Journaux de règle pour les connexions refusées.

Le journal des connexions refusées comprend un champ count permettant d'agréger les connexions refusées.

Dépannage

  1. Recherchez les événements associés à des erreurs dans l'objet NetworkLogging :

    kubectl describe networklogging default
    

    Si la configuration de journalisation n'est pas valide, elle ne sera pas appliquée et une erreur sera signalée dans la section des événements :

    Name:         default
    Namespace:
    Labels:       addonmanager.kubernetes.io/mode=EnsureExists
    Annotations:  API Version:  networking.gke.io/v1alpha1
    Kind:         NetworkLogging
    Metadata:
      Creation Timestamp:  2020-06-20T05:54:08Z
      Generation:          8
      Resource Version:    187864
      Self Link:           /apis/networking.gke.io/v1alpha1/networkloggings/default
      UID:                 0f1ddd6e-4193-4295-9172-baa6a52aa6e6
    Spec:
      Cluster:
        Allow:
          Delegate:  true
          Log:       false
        Deny:
          Delegate:  false
          Log:       false
    Events:
      Type     Reason                 Age                From                                                               Message
      ----     ------                 ----               ----                                                               -------
      Warning  InvalidNetworkLogging  16s (x3 over 11h)  network-logging-controller, gke-anthos-default-pool-cee49209-0t09  cluster allow log action is invalid: delegate cannot be true when log is false
      Warning  InvalidNetworkLogging  16s (x3 over 11h)  network-logging-controller, gke-anthos-default-pool-cee49209-80fx  cluster allow log action is invalid: delegate cannot be true when log is false
    
  2. Pour limiter l'utilisation du processeur par la journalisation, un nœud peut consigner jusqu'à 500 connexions par seconde avant de commencer à supprimer des journaux. Les règles de réseau sur le nœud sont toujours appliquées. Vous pouvez vérifier s'il existe des journaux de stratégie supprimés en vérifiant si les compteurs d'erreurs sont incrémentés :

    kubectl exec ANETD_XYZ -n kube-system -- curl -s http://localhost:9990/metrics |grep policy_logging
    

    Remplacez ANETD_XYZ par le nom d'un pod anetd. Vérifiez chaque nœud. netd est le contrôleur réseau pour Dataplane V2.

Les journaux sans nom apparaissent pour les pods utilisant des règles de refus par défaut

Les vérifications d'activité, d'aptitude et de démarrage exigent que le pod accepte les connexions d'entrée associées aux vérifications provenant de kubelet. Pour garantir le bon fonctionnement de ces vérifications, GKE autorise automatiquement le trafic de vérification vers le pod sélectionné, tel que configuré pour le podet indifféremment des règles de réseau appliquées au pod. Vous ne pouvez pas modifier ce comportement.

Les journaux des connexions de vérification sont semblables à ceux-ci :

{
   "connection":{
      "src_ip":"10.88.1.1",
      "dest_ip":"10.88.1.4",
      "src_port":35848,
      "dest_port":15021,
      "protocol":"tcp",
      "direction":"ingress"
   },
   "disposition":"allow",
   "src":{
      "instance":"10.88.1.1"
   },
   "dest":{
      "pod_name":"testpod-745c798fc9-sfd9h",
      "pod_namespace":"default",
      "namespace":"default",
      "workload_name":"testpod-745c798fc9",
      "workload_kind":"ReplicaSet"
   },
   "count":1,
   "policies": [
     {
       "name":""
     }
    ],
   "node_name":"gke-demo-default-pool-5dad52ed-k0h1",
   "timestamp":"2021-04-01T12:42:32.1898720941Z"
}

Le journal possède les caractéristiques suivantes :

  • La valeur policies.name est vide, car aucune règle de réseau associée n'autorise la connexion.
  • La valeur de connection.src_ip ne correspond à aucun pod ni nœud.

Étape suivante