Collecter les journaux du proxy OAuth2

Compatible avec :

Ce document explique comment ingérer des journaux OAuth2 Proxy dans Google Security Operations à l'aide de Google Cloud Storage V2.

OAuth2 Proxy est un proxy inverse CNCF Sandbox qui permet l'authentification à l'aide de fournisseurs OAuth2/OIDC (Google, GitHub, Keycloak, Azure AD et autres) pour valider les comptes par e-mail, domaine ou groupe. Il génère des journaux d'authentification (connexion réussie/échouée), des journaux de requêtes (requêtes HTTP proxyfiées avec l'identité de l'utilisateur) et des journaux d'application standards. Comme OAuth2 Proxy s'exécute en tant que conteneur dans Kubernetes et écrit tous les journaux dans stdout, un collecteur de journaux natif de Kubernetes (Fluentd) est utilisé pour transférer les journaux vers un bucket GCS pour l'ingestion Google SecOps.

Avant de commencer

Assurez-vous de remplir les conditions suivantes :

  • Une instance Google SecOps
  • Un projet GCP avec l'API Cloud Storage activée
  • Autorisations pour créer et gérer des buckets GCS
  • Autorisations permettant de gérer les stratégies IAM sur les buckets GCS
  • Un cluster Kubernetes en cours d'exécution avec OAuth2 Proxy déployé (via un chart Helm ou un déploiement manuel)
  • Accès kubectl au cluster Kubernetes avec les autorisations nécessaires pour créer des DaemonSets, des ConfigMaps, des secrets et des espaces de noms
  • Clé JSON d'un compte de service GCP avec l'autorisation storage.objects.create sur le bucket GCS cible

Créer un bucket Google Cloud Storage

  1. Accédez à la console Google Cloud.
  2. Sélectionnez votre projet ou créez-en un.
  3. Dans le menu de navigation, accédez à Cloud Storage > Buckets.
  4. Cliquez sur Créer un bucket.
  5. Fournissez les informations de configuration suivantes :

    Paramètre Valeur
    Nommer votre bucket Saisissez un nom unique (par exemple, oauth2-proxy-logs-bucket).
    Type d'emplacement Choisissez en fonction de vos besoins (région, birégion ou multirégion).
    Emplacement Sélectionnez l'emplacement (par exemple, us-central1).
    Classe de stockage Standard (recommandé pour les journaux auxquels vous accédez fréquemment)
    Access control (Contrôle des accès) Uniforme (recommandé)
    Outils de protection Facultatif : Activez la gestion des versions des objets ou une règle de conservation.
  6. Cliquez sur Créer.

Configurer la journalisation du proxy OAuth2

OAuth2 Proxy écrit trois types de journaux dans stdout : les journaux standards, les journaux d'authentification et les journaux de requêtes. Les trois sont activés par défaut. Pour vous assurer que les journaux contiennent le maximum de détails liés à la sécurité, configurez OAuth2 Proxy avec les indicateurs de journalisation suivants.

Option 1 : Configurer via les valeurs du chart Helm

  • Si OAuth2 Proxy est déployé à l'aide du chart Helm officiel, ajoutez les éléments suivants à votre fichier values.yaml :

    config:
      configFile: |-
        standard_logging = true
        auth_logging = true
        request_logging = true
        silence_ping_logging = true
            standard_logging_format = "[{{.Timestamp}}] [{{.File}}] {{.Message}}"
        auth_logging_format = "{{.Client}} - {{.RequestID}} - {{.Username}} [{{.Timestamp}}] [{{.Status}}] {{.Message}}"
        request_logging_format = "{{.Client}} - {{.RequestID}} - {{.Username}} [{{.Timestamp}}] {{.Host}} {{.RequestMethod}} {{.Upstream}} {{.RequestURI}} {{.Protocol}} {{.UserAgent}} {{.StatusCode}} {{.ResponseSize}} {{.RequestDuration}}"
    
  • Appliquez les valeurs Helm mises à jour :

    helm upgrade oauth2-proxy oauth2-proxy/oauth2-proxy -f values.yaml -n <your-namespace>
    

Option 2 : Configurer à l'aide d'options de ligne de commande

  • Si OAuth2 Proxy est déployé à l'aide d'un fichier manifeste de déploiement Kubernetes, ajoutez les arguments suivants à la spécification du conteneur :

    args:
      - --standard-logging=true
      - --auth-logging=true
      - --request-logging=true
      - --silence-ping-logging=true
    

Option 3 : Configurer à l'aide de variables d'environnement

  • Définissez les variables d'environnement suivantes sur le conteneur OAuth2 Proxy :

    env:
      - name: OAUTH2_PROXY_STANDARD_LOGGING
        value: "true"
      - name: OAUTH2_PROXY_AUTH_LOGGING
        value: "true"
      - name: OAUTH2_PROXY_REQUEST_LOGGING
        value: "true"
      - name: OAUTH2_PROXY_SILENCE_PING_LOGGING
        value: "true"
    

Vérifier la journalisation du proxy OAuth2

  • Après avoir appliqué la configuration, vérifiez qu'OAuth2 Proxy génère des journaux :

    kubectl logs -l app=oauth2-proxy -n <your-namespace> --tail=20
    
  • Le résultat inclut des lignes semblables à celles-ci :

    10.0.0.1 - abc123 - user@example.com [2024/01/15 10:30:00] [AuthSuccess] Authenticated via OAuth2
    10.0.0.1 - abc123 - user@example.com [2024/01/15 10:30:01] example.com GET 10.0.0.5:8080 "/dashboard" HTTP/1.1 "Mozilla/5.0" 200 1234 0.005
    

Créer un compte de service GCP pour Fluentd

Fluentd nécessite un compte de service GCP avec accès en écriture au bucket GCS.

  1. Dans la console GCP, accédez à IAM et administration > Comptes de service.
  2. Cliquez sur Créer un compte de service.
  3. Fournissez les informations de configuration suivantes :
    • Nom du compte de service : saisissez fluentd-gcs-writer.
    • Description du compte de service : saisissez Service account for Fluentd to write OAuth2 Proxy logs to GCS.
  4. Cliquez sur Créer et continuer.
  5. Dans la section Autoriser ce compte de service à accéder au projet :
    1. Cliquez sur Sélectionner un rôle.
    2. Recherchez et sélectionnez Administrateur des objets de l'espace de stockage.
  6. Cliquez sur Continuer.
  7. Cliquez sur OK.

Créer et télécharger une clé de compte de service

  1. Dans la liste Comptes de service, cliquez sur le compte de service fluentd-gcs-writer.
  2. Accédez à l'onglet Clés.
  3. Cliquez sur Ajouter une clé > Créer une clé.
  4. Sélectionnez JSON comme type de clé.
  5. Cliquez sur Créer.
  6. Enregistrez le fichier de clé JSON téléchargé de manière sécurisée. Ce fichier sera utilisé à l'étape suivante.

Créer un secret Kubernetes pour la clé du compte de service

  • Créez un secret Kubernetes contenant la clé du compte de service GCP dans l'espace de noms où Fluentd sera déployé :

    kubectl create namespace logging
    kubectl create secret generic fluentd-gcs-key \
      --from-file=service-account-key.json=<path-to-downloaded-key>.json \
      -n logging
    

Déployer le DaemonSet Fluentd pour collecter les journaux du proxy OAuth2

Déployez Fluentd en tant que DaemonSet dans le cluster Kubernetes pour collecter les journaux de conteneurs à partir des pods OAuth2 Proxy et les transférer vers le bucket GCS.

Créer un ConfigMap Fluentd

  • Créez un fichier nommé fluentd-configmap.yaml avec le contenu suivant :

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: fluentd-gcs-config
      namespace: logging
    data:
      fluent.conf: |
        <source>
          @type tail
          read_from_head true
          tag kubernetes.*
          path /var/log/containers/*oauth2-proxy*.log
          pos_file /var/log/fluentd-oauth2-proxy.log.pos
          <parse>
            @type regexp
            expression /^(?<time>[^ ]+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
            time_format %Y-%m-%dT%H:%M:%S.%N%z
          </parse>
        </source>
    
        <filter kubernetes.**>
          @type kubernetes_metadata
          @id filter_kube_metadata
        </filter>
    
        <match kubernetes.**>
          @type gcs
          project YOUR_GCP_PROJECT_ID
          keyfile /etc/secrets/service-account-key.json
          bucket oauth2-proxy-logs-bucket
          path oauth2-proxy-logs/%Y/%m/%d/
          object_key_format %{path}%{time_slice}_%{hostname}_%{index}.%{file_extension}
          <buffer tag,time>
            @type file
            path /var/log/fluentd/gcs
            timekey 300
            timekey_wait 60
            timekey_use_utc true
            chunk_limit_size 10MB
          </buffer>
          <format>
            @type json
          </format>
        </match>
    

Remplacez les valeurs suivantes :

  • YOUR_GCP_PROJECT_ID : ID de votre projet GCP (par exemple, my-project-123456)
  • oauth2-proxy-logs-bucket : nom du bucket GCS créé précédemment

  • Appliquez le ConfigMap :

    kubectl apply -f fluentd-configmap.yaml
    

Créer un DaemonSet Fluentd

  • Créez un fichier nommé fluentd-daemonset.yaml avec le contenu suivant :

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: fluentd-gcs
      namespace: logging
      labels:
        k8s-app: fluentd-gcs
    spec:
      selector:
        matchLabels:
          k8s-app: fluentd-gcs
      template:
        metadata:
          labels:
            k8s-app: fluentd-gcs
        spec:
          tolerations:
            - key: node-role.kubernetes.io/control-plane
              effect: NoSchedule
            - key: node-role.kubernetes.io/master
              effect: NoSchedule
          containers:
            - name: fluentd-gcs
              image: fluent/fluentd-kubernetes-daemonset:v1-debian-gcs
              resources:
                limits:
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 200Mi
              volumeMounts:
                - name: fluentd-gcs-config-volume
                  mountPath: /fluentd/etc/fluent.conf
                  subPath: fluent.conf
                  readOnly: true
                - name: fluentd-gcs-secrets-volume
                  mountPath: /etc/secrets/service-account-key.json
                  subPath: service-account-key.json
                  readOnly: true
                - name: varlog
                  mountPath: /var/log
                - name: dockercontainerlogdirectory
                  mountPath: /var/log/pods
                  readOnly: true
                - name: fluentd-buffer
                  mountPath: /var/log/fluentd
          terminationGracePeriodSeconds: 30
          volumes:
            - name: fluentd-gcs-config-volume
              configMap:
                name: fluentd-gcs-config
            - name: fluentd-gcs-secrets-volume
              secret:
                secretName: fluentd-gcs-key
            - name: varlog
              hostPath:
                path: /var/log
            - name: dockercontainerlogdirectory
              hostPath:
                path: /var/log/pods
            - name: fluentd-buffer
              emptyDir: {}
    
  • Appliquez le DaemonSet :

    kubectl apply -f fluentd-daemonset.yaml
    

Vérifier le déploiement de Fluentd

  1. Vérifiez que les pods Fluentd sont en cours d'exécution sur chaque nœud :

    kubectl get pods -n logging -l k8s-app=fluentd-gcs
    
  2. Consultez les journaux Fluentd pour vérifier que les écritures GCS ont réussi :

    kubectl logs -l k8s-app=fluentd-gcs -n logging --tail=20
    
  3. Vérifiez que les fichiers journaux apparaissent dans le bucket GCS :

    1. Accédez à Cloud Storage > Buckets dans la console GCP.
    2. Cliquez sur le bucket (par exemple, oauth2-proxy-logs-bucket).
    3. Accédez au dossier oauth2-proxy-logs/.
    4. Vérifiez que les fichiers .json sont présents et que leurs codes temporels sont récents.

Récupérer le compte de service Google SecOps

Google SecOps utilise un compte de service unique pour lire les données de votre bucket GCS. Vous devez accorder à ce compte de service l'accès à votre bucket.

Obtenir l'adresse e-mail du compte de service

  1. Accédez à Paramètres SIEM> Flux.
  2. Cliquez sur Add New Feed (Ajouter un flux).
  3. Cliquez sur Configurer un flux unique.
  4. Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, OAuth2 Proxy Logs).
  5. Sélectionnez Google Cloud Storage V2 comme Type de source.
  6. Sélectionnez Proxy d'authentification Kubernetes comme Type de journal.
  7. Cliquez sur Obtenir un compte de service. Une adresse e-mail unique pour le compte de service s'affiche, par exemple :

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Copiez cette adresse e-mail pour l'utiliser à l'étape suivante.

  9. Cliquez sur Suivant.

  10. Spécifiez les valeurs des paramètres d'entrée suivants :

    • URL du bucket de stockage : saisissez l'URI du bucket GCS avec le chemin d'accès au préfixe :

      gs://oauth2-proxy-logs-bucket/oauth2-proxy-logs/
      
    • Remplacez oauth2-proxy-logs-bucket par le nom de votre bucket GCS.

    • Option de suppression de la source : sélectionnez l'option de suppression de votre choix :

      • Jamais : ne supprime jamais aucun fichier après les transferts (recommandé pour les tests).
      • Supprimer les fichiers transférés : supprime les fichiers une fois le transfert réussi.
      • Supprimer les fichiers transférés et les répertoires vides : supprime les fichiers et les répertoires vides après un transfert réussi.

    • Âge maximal des fichiers : incluez les fichiers modifiés au cours des derniers jours (180 jours par défaut).

    • Espace de noms de l'élément : espace de noms de l'élément

    • Libellés d'ingestion : libellé à appliquer aux événements de ce flux

  11. Cliquez sur Suivant.

  12. Vérifiez la configuration de votre nouveau flux sur l'écran Finaliser, puis cliquez sur Envoyer.

Accorder des autorisations IAM au compte de service Google SecOps

Le compte de service Google SecOps a besoin du rôle Lecteur des objets Storage sur votre bucket GCS.

  1. Accédez à Cloud Storage > Buckets.
  2. Cliquez sur le nom de votre bucket (par exemple, oauth2-proxy-logs-bucket).
  3. Accédez à l'onglet Autorisations.
  4. Cliquez sur Accorder l'accès.
  5. Fournissez les informations de configuration suivantes :
    • Ajouter des comptes principaux : collez l'adresse e-mail du compte de service Google SecOps (par exemple, chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com).
    • Attribuer des rôles : sélectionnez Lecteur des objets de l'espace de stockage.
  6. Cliquez sur Enregistrer.

Documentation de référence sur les journaux de proxy OAuth2

Le tableau suivant décrit les champs de journaux générés par OAuth2 Proxy et leur pertinence en termes de sécurité :

Champs du journal d'authentification

Champ Exemple Description
Client 10.0.0.1 Adresse IP du client/à distance (utilise l'en-tête X-Real-IP si --reverse-proxy=true)
RequestID 00010203-0405-4607-8809-0a0b0c0d0e0f ID de la requête provenant de l'en-tête X-Request-Id (UUID aléatoire si vide)
Nom d'utilisateur user@example.com Adresse e-mail ou nom d'utilisateur de la demande d'authentification
Horodatage 2024/01/15 10:30:00 Date et heure de l'événement d'authentification
État AuthSuccess Résultat de l'authentification : AuthSuccess, AuthFailure ou AuthError
Message Authenticated via OAuth2 Détails de la tentative d'authentification

Champs du journal des requêtes

Champ Exemple Description
Client 10.0.0.1 Adresse IP du client/de l'hôte distant
RequestID 00010203-0405-4607-8809-0a0b0c0d0e0f Identifiant de la demande
Nom d'utilisateur user@example.com Adresse e-mail de l'utilisateur authentifié
Horodatage 2024/01/15 10:30:01 Date et heure de la demande
Hôte app.example.com Valeur de l'en-tête d'hôte
RequestMethod GET Méthode de requête HTTP
En amont 10.0.0.5:8080 Serveur en amont qui a traité la requête
RequestURI /dashboard Chemin d'URI de la requête
Protocole HTTP/1.1 Protocole de requête
UserAgent Mozilla/5.0 Chaîne user-agent complète
StatusCode 200 Code d'état de réponse HTTP
ResponseSize 1234 Taille de la réponse en octets
RequestDuration 0.005 Temps de traitement des requêtes en secondes

Table de mappage UDM

Champ de journal Mappage UDM Logique
à propos de à propos de Informations sur l'événement
http_req_id_field additional.fields Champs supplémentaires non couverts par le schéma UDM standard
http_req_path_field additional.fields
k8s_pod_app_field additional.fields
k8s_pod_template_hash_field additional.fields
k8s_pod_tls_mode_field additional.fields
k8s_pod_canonical_revision_field additional.fields
k8s_pod_canonical_name_field additional.fields
pod_name additional.fields
cntnr_name additional.fields
destination_canonical_revision additional.fields
requested_server additional.fields
nodename_label additional.fields
componentName_label additional.fields
componentVersion_label additional.fields
azureResourceID_label additional.fields
producer_label additional.fields
first_label additional.fields
last_label additional.fields
meta_name additional.fields
resource_version_label additional.fields
request_apiVersion additional.fields
request_kind_label additional.fields
request_type_label additional.fields
response_apiVersion additional.fields
response_kind_label additional.fields
response_type_label additional.fields
jsonPayload.message metadata.description Description de l'événement
event_type metadata.event_type Type d'événement
labels.request_id metadata.product_log_id Identifiant de journal spécifique au produit
insertId metadata.product_log_id
jsonPayload.chartVersion metadata.product_version Version du produit
httpRequest.protocol network.application_protocol Protocole d'application utilisé dans la connexion réseau
network.direction network.direction Sens du trafic réseau
httpRequest.requestMethod network.http.method Méthode HTTP
http_method network.http.method
httpRequest.status network.http.response_code Code de réponse HTTP
httpRequest.userAgent network.http.user_agent User-agent HTTP
requestMetadata.callerSuppliedUserAgent network.http.user_agent
labels.protocol network.ip_protocol Protocole IP
httpRequest.responseSize network.received_bytes Nombre d'octets reçus
labels.total_received_bytes network.received_bytes
httpRequest.requestSize network.sent_bytes Nombre d'octets envoyés
labels.total_sent_bytes network.sent_bytes
jsonPayload.session network.session_id Identifiant de session
labels.service_authentication_policy network.tls.cipher Suite de chiffrement TLS
principal principal Entité principale impliquée dans l'événement
principal_hostname principal.hostname Nom d'hôte du principal
prin_userid principal.user.userid ID utilisateur du principal
security_result security_result Résultat de l'évaluation de sécurité
cible cible Entité cible impliquée dans l'événement
target_hostname target.hostname Nom d'hôte de la cible
resource_sub_type target.resource.resource_subtype Sous-type de la ressource cible
target_userid target.user.userid ID utilisateur de la cible
metadata.product_name metadata.product_name Nom du produit
metadata.vendor_name metadata.vendor_name Nom du fournisseur

Journal des modifications

Afficher le journal des modifications pour ce parseur

Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.