Coletar registros do proxy OAuth2

Compatível com:

Este documento explica como ingerir registros do OAuth2 Proxy no Google Security Operations usando o Google Cloud Storage V2.

O OAuth2 Proxy é um proxy reverso do Sandbox da CNCF que fornece autenticação usando provedores OAuth2/OIDC (Google, GitHub, Keycloak, Azure AD e outros) para validar contas por e-mail, domínio ou grupo. Ele gera registros de autenticação (sucesso/falha de login), registros de solicitação (solicitações HTTP proxy com identidade do usuário) e registros de aplicativo padrão. Como o OAuth2 Proxy é executado como um contêiner no Kubernetes e grava todos os registros em stdout, um coletor de registros nativo do Kubernetes (Fluentd) é usado para encaminhar registros a um bucket do GCS para ingestão do Google SecOps.

Antes de começar

Verifique se você tem os pré-requisitos a seguir:

  • Uma instância do Google SecOps
  • Um projeto do GCP com a API Storage do Cloud ativada
  • Permissões para criar e gerenciar intervalos do GCS
  • Permissões para gerenciar políticas do IAM em buckets do GCS
  • Um cluster do Kubernetes em execução com o OAuth2 Proxy implantado (usando um gráfico do Helm ou implantação manual)
  • Acesso de kubectl ao cluster do Kubernetes com permissões para criar DaemonSets, ConfigMaps, Secrets e Namespaces
  • Uma chave JSON de conta de serviço do GCP com permissão storage.objects.create no bucket de destino do GCS

Criar um bucket do Google Cloud Storage

  1. Acesse o Console do Google Cloud.
  2. Selecione ou crie um projeto.
  3. No menu de navegação, acesse Cloud Storage > Buckets.
  4. Clique em Criar bucket.
  5. Informe os seguintes detalhes de configuração:

    Configuração Valor
    Nomeie seu bucket Insira um nome globalmente exclusivo, por exemplo, oauth2-proxy-logs-bucket.
    Tipo de local Escolha de acordo com suas necessidades (região, birregional, multirregional)
    Local Selecione o local (por exemplo, us-central1).
    Classe de armazenamento Padrão (recomendado para registros acessados com frequência)
    Controle de acesso Uniforme (recomendado)
    Ferramentas de proteção Opcional: ativar o controle de versões de objetos ou a política de retenção
  6. Clique em Criar.

Configurar o registro do proxy OAuth2

O OAuth2 Proxy grava três tipos de registros em stdout: registros padrão, de autenticação e de solicitação. Todas as três estão ativadas por padrão. Para garantir que os registros contenham o máximo de detalhes relevantes para a segurança, configure o proxy OAuth2 com as seguintes flags de geração de registros.

Opção 1: configurar usando valores de gráfico do Helm

  • Se o OAuth2 Proxy for implantado usando o gráfico oficial do Helm, adicione o seguinte ao arquivo 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}}"
    
  • Aplique os valores atualizados do Helm:

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

Opção 2: configurar usando flags da linha de comando

  • Se o OAuth2 Proxy for implantado usando um manifesto de implantação do Kubernetes, adicione os seguintes argumentos à especificação do contêiner:

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

Opção 3: configurar usando variáveis de ambiente

  • Defina as seguintes variáveis de ambiente no contêiner do proxy OAuth2:

    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"
    

Verificar o registro do proxy OAuth2

  • Depois de aplicar a configuração, verifique se o proxy OAuth2 está gerando registros:

    kubectl logs -l app=oauth2-proxy -n <your-namespace> --tail=20
    
  • A saída inclui linhas semelhantes a estas:

    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
    

Criar uma conta de serviço do GCP para o Fluentd

O Fluentd exige uma conta de serviço do GCP com acesso de gravação ao bucket do GCS.

  1. No console do GCP, acesse IAM e administrador > Contas de serviço.
  2. Clique em Criar conta de serviço.
  3. Informe os seguintes detalhes de configuração:
    • Nome da conta de serviço: insira fluentd-gcs-writer
    • Descrição da conta de serviço: insira Service account for Fluentd to write OAuth2 Proxy logs to GCS
  4. Clique em Criar e continuar.
  5. Na seção Conceder a essa conta de serviço acesso ao projeto:
    1. Clique em Selecionar papel.
    2. Pesquise e selecione Administrador de objetos do Storage.
  6. Clique em Continuar.
  7. Clique em Concluído.

Criar e fazer o download da chave da conta de serviço

  1. Na lista Contas de serviço, clique na conta de serviço fluentd-gcs-writer.
  2. Acesse a guia Chaves.
  3. Clique em Adicionar chave > Criar nova chave.
  4. Selecione JSON como o tipo de chave.
  5. Clique em Criar.
  6. Salve o arquivo de chave JSON baixado com segurança. Esse arquivo será usado na próxima etapa.

Criar um secret do Kubernetes para a chave da conta de serviço

  • Crie um secret do Kubernetes que contenha a chave da conta de serviço do GCP no namespace em que o Fluentd será implantado:

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

Implante o DaemonSet do Fluentd para coletar registros do proxy OAuth2

Implante o Fluentd como um DaemonSet no cluster do Kubernetes para coletar registros de contêineres dos pods do proxy OAuth2 e encaminhá-los para o bucket do GCS.

Criar ConfigMap do Fluentd

  • Crie um arquivo chamado fluentd-configmap.yaml com o conteúdo a seguir:

    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>
    

Substitua os seguintes valores:

  • YOUR_GCP_PROJECT_ID: o ID do projeto do GCP (por exemplo, my-project-123456)
  • oauth2-proxy-logs-bucket: o nome do bucket do GCS criado anteriormente

  • Aplique o ConfigMap:

    kubectl apply -f fluentd-configmap.yaml
    

Criar o DaemonSet do Fluentd

  • Crie um arquivo chamado fluentd-daemonset.yaml com o conteúdo a seguir:

    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: {}
    
  • Aplique o DaemonSet:

    kubectl apply -f fluentd-daemonset.yaml
    

Verificar a implantação do Fluentd

  1. Verifique se os pods do Fluentd estão em execução em cada nó:

    kubectl get pods -n logging -l k8s-app=fluentd-gcs
    
  2. Verifique os registros do Fluentd para gravações bem-sucedidas do GCS:

    kubectl logs -l k8s-app=fluentd-gcs -n logging --tail=20
    
  3. Verifique se os arquivos de registro aparecem no bucket do GCS:

    1. Acesse Cloud Storage > Buckets no console do GCP.
    2. Clique no bucket (por exemplo, oauth2-proxy-logs-bucket).
    3. Navegue até a pasta oauth2-proxy-logs/.
    4. Verifique se os arquivos .json estão presentes com carimbos de data/hora recentes.

Recuperar a conta de serviço do Google SecOps

O Google SecOps usa uma conta de serviço exclusiva para ler dados do seu bucket do GCS. Você precisa conceder a essa conta de serviço acesso ao seu bucket.

Receber o e-mail da conta de serviço

  1. Acesse Configurações do SIEM > Feeds.
  2. Clique em Adicionar novo feed.
  3. Clique em Configurar um único feed.
  4. No campo Nome do feed, insira um nome para o feed (por exemplo, OAuth2 Proxy Logs).
  5. Selecione Google Cloud Storage V2 como o Tipo de origem.
  6. Selecione Proxy de autenticação do Kubernetes como o Tipo de registro.
  7. Clique em Receber conta de serviço. Um e-mail exclusivo da conta de serviço será exibido, por exemplo:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Copie esse endereço de e-mail para usar na próxima etapa.

  9. Clique em Próxima.

  10. Especifique valores para os seguintes parâmetros de entrada:

    • URL do bucket de armazenamento: insira o URI do bucket do GCS com o caminho do prefixo:

      gs://oauth2-proxy-logs-bucket/oauth2-proxy-logs/
      
    • Substitua oauth2-proxy-logs-bucket pelo nome do seu bucket do GCS.

    • Opção de exclusão da fonte: selecione a opção de exclusão de acordo com sua preferência:

      • Nunca: nunca exclui arquivos após as transferências (recomendado para testes).
      • Excluir arquivos transferidos: exclui os arquivos após a transferência.
      • Excluir arquivos transferidos e diretórios vazios: exclui arquivos e diretórios vazios após a transferência.

    • Idade máxima do arquivo: inclua arquivos modificados no último número de dias (o padrão é 180 dias).

    • Namespace do recurso: o namespace do recurso

    • Rótulos de ingestão: o rótulo a ser aplicado aos eventos deste feed

  11. Clique em Próxima.

  12. Revise a nova configuração do feed na tela Finalizar e clique em Enviar.

Conceder permissões do IAM à conta de serviço do Google SecOps

A conta de serviço do Google SecOps precisa do papel Leitor de objetos do Storage no seu bucket do GCS.

  1. Acesse Cloud Storage > Buckets.
  2. Clique no nome do bucket (por exemplo, oauth2-proxy-logs-bucket).
  3. Acesse a guia Permissões.
  4. Clique em Conceder acesso.
  5. Informe os seguintes detalhes de configuração:
    • Adicionar participantes: cole o e-mail da conta de serviço do Google SecOps (por exemplo, chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com).
    • Atribuir papéis: selecione Leitor de objetos do Storage.
  6. Clique em Salvar.

Referência de registros do proxy OAuth2

A tabela a seguir descreve os campos de registro gerados pelo proxy OAuth2 e a relevância deles para a segurança:

Campos de registro de autenticação

Campo Exemplo Descrição
Cliente 10.0.0.1 Endereço IP do cliente/remoto (usa o cabeçalho X-Real-IP se --reverse-proxy=true)
RequestID 00010203-0405-4607-8809-0a0b0c0d0e0f ID da solicitação do cabeçalho X-Request-Id (UUID aleatório se estiver vazio)
Nome de usuário user@example.com E-mail ou nome de usuário da solicitação de autenticação
Carimbo de data/hora 2024/01/15 10:30:00 Data e hora do evento de autenticação
Status AuthSuccess Resultado da autenticação: AuthSuccess, AuthFailure ou AuthError
Mensagem Authenticated via OAuth2 Detalhes da tentativa de autenticação

Campos de registros de solicitação

Campo Exemplo Descrição
Cliente 10.0.0.1 Endereço IP do cliente/remoto
RequestID 00010203-0405-4607-8809-0a0b0c0d0e0f ID da solicitação
Nome de usuário user@example.com E-mail do usuário autenticado
Carimbo de data/hora 2024/01/15 10:30:01 Data e hora da solicitação
Host app.example.com Valor do cabeçalho "Host"
RequestMethod GET Método de solicitação HTTP
Upstream 10.0.0.5:8080 Servidor upstream que processou a solicitação
RequestURI /dashboard Caminho do URI da solicitação
Protocolo HTTP/1.1 Protocolo de solicitação
UserAgent Mozilla/5.0 String completa do user agent
StatusCode 200 Código de status da resposta HTTP
ResponseSize 1234 Tamanho da resposta em bytes
RequestDuration 0.005 Tempo de processamento da solicitação em segundos

Tabela de mapeamento de UDM

Campo de registro Mapeamento do UDM Lógica
sobre sobre Informações sobre o evento
http_req_id_field additional.fields Campos adicionais não cobertos pelo esquema UDM padrão
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 A descrição do evento
event_type metadata.event_type Tipo de evento
labels.request_id metadata.product_log_id Identificador de registro específico do produto.
insertId metadata.product_log_id
jsonPayload.chartVersion metadata.product_version Versão do produto
httpRequest.protocol network.application_protocol Protocolo de aplicativo usado na conexão de rede.
network.direction network.direction Direção do tráfego de rede
httpRequest.requestMethod network.http.method Método HTTP
http_method network.http.method
httpRequest.status network.http.response_code Código de resposta HTTP
httpRequest.userAgent network.http.user_agent User agent HTTP
requestMetadata.callerSuppliedUserAgent network.http.user_agent
labels.protocol network.ip_protocol Protocolo IP
httpRequest.responseSize network.received_bytes Número de bytes recebidos
labels.total_received_bytes network.received_bytes
httpRequest.requestSize network.sent_bytes Número de bytes enviados
labels.total_sent_bytes network.sent_bytes
jsonPayload.session network.session_id Identificador de sessão
labels.service_authentication_policy network.tls.cipher Pacote de criptografia TLS
participante participante Entidade principal envolvida no evento
principal_hostname principal.hostname Nome do host do principal
prin_userid principal.user.userid ID do usuário do principal
security_result security_result Resultado da avaliação de segurança
destino destino Entidade de destino envolvida no evento
target_hostname target.hostname Nome do host do destino
resource_sub_type target.resource.resource_subtype Subtipo do recurso de destino
target_userid target.user.userid ID do usuário do destino
metadata.product_name metadata.product_name Nome do produto
metadata.vendor_name metadata.vendor_name Nome do fornecedor

Registro de alterações

Ver o registro de alterações deste analisador

Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.