OAuth2 프록시 로그 수집

다음에서 지원:

이 문서에서는 Google Cloud Storage V2를 사용하여 OAuth2 Proxy 로그를 Google Security Operations로 수집하는 방법을 설명합니다.

OAuth2 Proxy는 CNCF 샌드박스 리버스 프록시로, OAuth2/OIDC 제공업체 (Google, GitHub, Keycloak, Azure AD 등)를 사용하여 이메일, 도메인 또는 그룹별로 계정을 검증하는 인증을 제공합니다. 인증 로그 (로그인 성공/실패), 요청 로그 (사용자 ID가 포함된 프록시 HTTP 요청), 표준 애플리케이션 로그를 생성합니다. OAuth2 Proxy는 Kubernetes에서 컨테이너로 실행되고 모든 로그를 stdout에 쓰기 때문에 Kubernetes 네이티브 로그 수집기 (Fluentd)가 Google SecOps 수집을 위해 로그를 GCS 버킷으로 전달하는 데 사용됩니다.

시작하기 전에

다음 기본 요건이 충족되었는지 확인합니다.

  • Google SecOps 인스턴스
  • Cloud Storage API가 사용 설정된 GCP 프로젝트
  • GCS 버킷을 만들고 관리할 수 있는 권한
  • GCS 버킷의 IAM 정책을 관리할 수 있는 권한
  • OAuth2 프록시가 배포된 실행 중인 Kubernetes 클러스터 (Helm 차트 또는 수동 배포를 통해)
  • DaemonSet, ConfigMap, 보안 비밀, 네임스페이스를 만들 권한이 있는 Kubernetes 클러스터에 대한 kubectl 액세스
  • 타겟 GCS 버킷에 대한 storage.objects.create 권한이 있는 GCP 서비스 계정 JSON 키

Google Cloud Storage 버킷 만들기

  1. Google Cloud 콘솔로 이동합니다.
  2. 프로젝트를 선택하거나 새 프로젝트를 만듭니다.
  3. 탐색 메뉴에서 Cloud Storage> 버킷으로 이동합니다.
  4. 버킷 만들기를 클릭합니다.
  5. 다음 구성 세부정보를 제공합니다.

    설정
    버킷 이름 지정 전역적으로 고유한 이름 (예: oauth2-proxy-logs-bucket)을 입력합니다.
    위치 유형 필요에 따라 선택 (리전, 이중 리전, 멀티 리전)
    위치 위치를 선택합니다 (예: us-central1).
    스토리지 클래스 Standard (자주 액세스하는 로그에 권장)
    액세스 제어 균일 (권장)
    보호 조치 선택사항: 객체 버전 관리 또는 보관 정책 사용 설정
  6. 만들기를 클릭합니다.

OAuth2 프록시 로깅 구성

OAuth2 프록시는 표준 로그, 인증 로그, 요청 로그의 세 가지 유형의 로그를 stdout에 씁니다. 세 가지 모두 기본적으로 사용 설정되어 있습니다. 로그에 보안 관련 세부정보가 최대한 많이 포함되도록 하려면 다음 로깅 플래그를 사용하여 OAuth2 프록시를 구성하세요.

옵션 1: Helm 차트 값을 통해 구성

  • 공식 Helm 차트를 사용하여 OAuth2 프록시를 배포하는 경우 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}}"
    
  • 업데이트된 Helm 값을 적용합니다.

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

옵션 2: 명령줄 플래그를 통해 구성

  • Kubernetes 배포 매니페스트를 사용하여 OAuth2 프록시를 배포하는 경우 컨테이너 사양에 다음 인수를 추가합니다.

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

옵션 3: 환경 변수를 통해 구성

  • 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"
    

OAuth2 프록시 로깅 확인

  • 구성을 적용한 후 OAuth2 프록시가 로그를 생성하는지 확인합니다.

    kubectl logs -l app=oauth2-proxy -n <your-namespace> --tail=20
    
  • 출력에는 다음과 비슷한 줄이 포함됩니다.

    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
    

Fluentd용 GCP 서비스 계정 만들기

Fluentd에는 GCS 버킷에 대한 쓰기 액세스 권한이 있는 GCP 서비스 계정이 필요합니다.

  1. GCP 콘솔에서 IAM 및 관리자 > 서비스 계정으로 이동합니다.
  2. 서비스 계정 만들기를 클릭합니다.
  3. 다음 구성 세부정보를 제공합니다.
    • 서비스 계정 이름: fluentd-gcs-writer을 입력합니다.
    • 서비스 계정 설명: Service account for Fluentd to write OAuth2 Proxy logs to GCS를 입력합니다.
  4. 만들고 계속하기를 클릭합니다.
  5. 이 서비스 계정에 프로젝트에 대한 액세스 권한 부여 섹션에서 다음 단계를 따르세요.
    1. 역할 선택을 클릭합니다.
    2. 스토리지 객체 관리자를 검색하여 선택합니다.
  6. 계속을 클릭합니다.
  7. 완료를 클릭합니다.

서비스 계정 키 만들기 및 다운로드

  1. 서비스 계정 목록에서 fluentd-gcs-writer 서비스 계정을 클릭합니다.
  2. 탭으로 이동합니다.
  3. 키 추가 > 새 키 만들기를 클릭합니다.
  4. 키 유형으로 JSON을 선택합니다.
  5. 만들기를 클릭합니다.
  6. 다운로드한 JSON 키 파일을 안전하게 저장합니다. 이 파일은 다음 단계에서 사용됩니다.

서비스 계정 키의 Kubernetes 보안 비밀 만들기

  • Fluentd가 배포될 네임스페이스에 GCP 서비스 계정 키가 포함된 Kubernetes 보안 비밀을 만듭니다.

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

Fluentd DaemonSet을 배포하여 OAuth2 프록시 로그 수집

Kubernetes 클러스터에 Fluentd를 DaemonSet으로 배포하여 OAuth2 프록시 포드에서 컨테이너 로그를 수집하고 GCS 버킷으로 전달합니다.

Fluentd ConfigMap 만들기

  • 다음 콘텐츠로 fluentd-configmap.yaml이라는 파일을 만듭니다.

    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>
    

다음 값을 바꿉니다.

  • YOUR_GCP_PROJECT_ID: GCP 프로젝트 ID (예: my-project-123456)
  • oauth2-proxy-logs-bucket: 이전에 만든 GCS 버킷의 이름

  • ConfigMap을 적용합니다.

    kubectl apply -f fluentd-configmap.yaml
    

Fluentd DaemonSet 만들기

  • 다음 콘텐츠로 fluentd-daemonset.yaml이라는 파일을 만듭니다.

    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: {}
    
  • DaemonSet를 적용합니다.

    kubectl apply -f fluentd-daemonset.yaml
    

Fluentd 배포 확인

  1. Fluentd 포드가 각 노드에서 실행 중인지 확인합니다.

    kubectl get pods -n logging -l k8s-app=fluentd-gcs
    
  2. Fluentd 로그에서 GCS 쓰기가 성공했는지 확인합니다.

    kubectl logs -l k8s-app=fluentd-gcs -n logging --tail=20
    
  3. 로그 파일이 GCS 버킷에 표시되는지 확인합니다.

    1. GCP 콘솔에서 Cloud Storage> 버킷으로 이동합니다.
    2. 버킷 (예: oauth2-proxy-logs-bucket)을 클릭합니다.
    3. oauth2-proxy-logs/ 폴더로 이동합니다.
    4. .json 파일이 최신 타임스탬프와 함께 있는지 확인합니다.

Google SecOps 서비스 계정 가져오기

Google SecOps는 고유한 서비스 계정을 사용하여 GCS 버킷에서 데이터를 읽습니다. 이 서비스 계정에 버킷 액세스 권한을 부여해야 합니다.

서비스 계정 이메일 가져오기

  1. SIEM 설정> 피드로 이동합니다.
  2. 새 피드 추가를 클릭합니다.
  3. 단일 피드 구성을 클릭합니다.
  4. 피드 이름 필드에 피드 이름을 입력합니다(예: OAuth2 Proxy Logs).
  5. 소스 유형으로 Google Cloud Storage V2를 선택합니다.
  6. 로그 유형으로 Kubernetes Auth Proxy를 선택합니다.
  7. 서비스 계정 가져오기를 클릭합니다. 고유한 서비스 계정 이메일이 표시됩니다(예:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. 다음 단계에서 사용할 수 있도록 이 이메일 주소를 복사합니다.

  9. 다음을 클릭합니다.

  10. 다음 입력 매개변수의 값을 지정합니다.

    • 스토리지 버킷 URL: 다음 접두사 경로를 사용하여 GCS 버킷 URI를 입력합니다.

      gs://oauth2-proxy-logs-bucket/oauth2-proxy-logs/
      
    • oauth2-proxy-logs-bucket을 GCS 버킷 이름으로 바꿉니다.

    • 소스 삭제 옵션: 환경설정에 따라 삭제 옵션을 선택합니다.

      • 삭제 안함: 전송 후 파일을 삭제하지 않습니다 (테스트에 권장).
      • 전송된 파일 삭제: 전송이 완료되면 파일을 삭제합니다.
      • 전송된 파일 및 빈 디렉터리 삭제: 전송이 완료되면 파일과 빈 디렉터리를 삭제합니다.

    • 최대 파일 기간: 지난 일수 동안 수정된 파일을 포함합니다 (기본값은 180일).

    • 애셋 네임스페이스: 애셋 네임스페이스

    • 수집 라벨: 이 피드의 이벤트에 적용할 라벨입니다.

  11. 다음을 클릭합니다.

  12. 확정 화면에서 새 피드 구성을 검토한 다음 제출을 클릭합니다.

Google SecOps 서비스 계정에 IAM 권한 부여

Google SecOps 서비스 계정에는 GCS 버킷에 대한 스토리지 객체 뷰어 역할이 필요합니다.

  1. Cloud Storage> 버킷으로 이동합니다.
  2. 버킷 이름 (예: oauth2-proxy-logs-bucket)을 클릭합니다.
  3. 권한 탭으로 이동합니다.
  4. 액세스 권한 부여를 클릭합니다.
  5. 다음 구성 세부정보를 제공합니다.
    • 주 구성원 추가: Google SecOps 서비스 계정 이메일 (예: chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com)을 붙여넣습니다.
    • 역할 할당: 스토리지 객체 뷰어를 선택합니다.
  6. 저장을 클릭합니다.

OAuth2 프록시 로그 참조

다음 표에서는 OAuth2 Proxy에서 생성된 로그 필드와 보안 관련성을 설명합니다.

인증 로그 필드

필드 설명
클라이언트 10.0.0.1 클라이언트/원격 IP 주소 (--reverse-proxy=true인 경우 X-Real-IP 헤더 사용)
RequestID 00010203-0405-4607-8809-0a0b0c0d0e0f X-Request-Id 헤더의 요청 ID (비어 있는 경우 임의 UUID)
사용자 이름 user@example.com 인증 요청의 이메일 또는 사용자 이름
타임스탬프 2024/01/15 10:30:00 인증 이벤트의 날짜 및 시간
상태 AuthSuccess 인증 결과: AuthSuccess, AuthFailure 또는 AuthError
메시지 Authenticated via OAuth2 인증 시도 세부정보

요청 로그 필드

필드 설명
클라이언트 10.0.0.1 클라이언트/원격 IP 주소
RequestID 00010203-0405-4607-8809-0a0b0c0d0e0f 요청 ID
사용자 이름 user@example.com 인증된 사용자 이메일
타임스탬프 2024/01/15 10:30:01 요청 날짜 및 시간
호스트 app.example.com 호스트 헤더의 값
RequestMethod GET HTTP 요청 메서드
업스트림 10.0.0.5:8080 요청을 처리한 업스트림 서버
RequestURI /dashboard 요청의 URI 경로
프로토콜 HTTP/1.1 요청 프로토콜
UserAgent Mozilla/5.0 전체 사용자 에이전트 문자열
StatusCode 200 HTTP 응답 상태 코드
ResponseSize 1234 응답 크기(바이트)
RequestDuration 0.005 요청 처리 시간(초)

UDM 매핑 테이블

로그 필드 UDM 매핑 논리
정보 정보 이벤트에 관한 정보
http_req_id_field additional.fields 표준 UDM 스키마에 포함되지 않은 추가 필드
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 이벤트의 설명
event_type metadata.event_type 이벤트 유형
labels.request_id metadata.product_log_id 제품별 로그 식별자
insertId metadata.product_log_id
jsonPayload.chartVersion metadata.product_version 제품 버전
httpRequest.protocol network.application_protocol 네트워크 연결에 사용된 애플리케이션 프로토콜
network.direction network.direction 네트워크 트래픽 방향
httpRequest.requestMethod network.http.method HTTP 메서드
http_method network.http.method
httpRequest.status network.http.response_code HTTP 응답 코드
httpRequest.userAgent network.http.user_agent HTTP 사용자 에이전트
requestMetadata.callerSuppliedUserAgent network.http.user_agent
labels.protocol network.ip_protocol IP 프로토콜
httpRequest.responseSize network.received_bytes 수신된 바이트 수
labels.total_received_bytes network.received_bytes
httpRequest.requestSize network.sent_bytes 전송된 바이트 수
labels.total_sent_bytes network.sent_bytes
jsonPayload.session network.session_id 세션 식별자
labels.service_authentication_policy network.tls.cipher TLS 암호화 스위트
principal principal 이벤트에 관련된 주요 항목
principal_hostname principal.hostname 주 구성원의 호스트 이름
prin_userid principal.user.userid 주체의 사용자 ID
security_result security_result 보안 평가 결과
target target 이벤트에 관련된 타겟 항목
target_hostname target.hostname 타겟의 호스트 이름
resource_sub_type target.resource.resource_subtype 타겟 리소스의 하위 유형
target_userid target.user.userid 타겟의 사용자 ID
metadata.product_name metadata.product_name 제품 이름
metadata.vendor_name metadata.vendor_name 공급업체 이름

변경 로그

이 파서의 변경 로그 보기

도움이 더 필요하신가요? 커뮤니티 회원 및 Google SecOps 전문가에게 문의하여 답변을 받으세요.