Keycloak 로그 수집

다음에서 지원:

이 문서에서는 웹훅을 사용하여 로그를 Google Security Operations로 푸시하도록 Keycloak을 구성하는 방법을 설명합니다.

Keycloak은 싱글 사인온 (SSO), 사용자 페더레이션, ID 브로커링, 소셜 로그인 기능을 제공하는 오픈소스 ID 및 액세스 관리 (IAM) 솔루션입니다. OpenID Connect, OAuth 2.0, SAML 2.0 프로토콜을 지원하며 보안 감사를 위해 사용자 이벤트 (로그인, 로그아웃, 등록, 비밀번호 변경) 및 관리자 이벤트 (사용자, 클라이언트, 영역, 역할 관리 작업)를 추적합니다.

시작하기 전에

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

  • Google SecOps 인스턴스
  • 실행 중인 Keycloak 인스턴스 (버전 20 이상 권장)
  • Keycloak 관리 콘솔에 대한 관리자 액세스 권한
  • 확장 프로그램을 배포하기 위한 Keycloak 서버 파일 시스템 또는 컨테이너 액세스
  • Google Cloud 콘솔 액세스 (API 키 생성용)

Google SecOps에서 웹훅 피드 만들기

피드 만들기

  1. SIEM 설정> 피드로 이동합니다.
  2. 새 피드 추가를 클릭합니다.
  3. 다음 페이지에서 단일 피드 구성을 클릭합니다.
  4. 피드 이름 필드에 피드 이름을 입력합니다(예: Keycloak Events).
  5. 소스 유형으로 웹훅을 선택합니다.
  6. 로그 유형으로 Keycloak을 선택합니다.
  7. 다음을 클릭합니다.
  8. 다음 입력 파라미터의 값을 지정합니다.
    • 분할 구분자 (선택사항): \n를 입력하여 여러 줄 이벤트를 분할합니다 (각 웹훅 POST에는 단일 이벤트가 포함되므로 비워 둘 수 있음).
    • 애셋 네임스페이스: 애셋 네임스페이스
    • 수집 라벨: 이 피드의 이벤트에 적용할 라벨입니다.
  9. 다음을 클릭합니다.
  10. 확정 화면에서 새 피드 구성을 검토한 다음 제출을 클릭합니다.

보안 비밀 키 생성 및 저장

피드를 만든 후 인증을 위한 보안 비밀 키를 생성해야 합니다.

  1. 피드 세부정보 페이지에서 보안 비밀 키 생성을 클릭합니다.
  2. 대화상자에 보안 비밀 키가 표시됩니다.
  3. 보안 비밀번호를 안전하게 복사하여 저장합니다.

중요: 비밀 키는 한 번만 표시되며 나중에 검색할 수 없습니다. 분실할 경우 새 비밀번호 키를 생성해야 합니다.

피드 엔드포인트 URL 가져오기

  1. 피드의 세부정보 탭으로 이동합니다.
  2. 엔드포인트 정보 섹션에서 피드 엔드포인트 URL을 복사합니다.
  3. URL 형식은 다음과 같습니다.

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    

    또는

    https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    
  4. 다음 단계를 위해 이 URL을 저장합니다.

  5. 완료를 클릭합니다.

Google Cloud API 키 만들기

Chronicle에는 인증을 위한 API 키가 필요합니다. Google Cloud 콘솔에서 제한된 API 키를 만듭니다.

API 키 만들기

  1. Google Cloud 콘솔 사용자 인증 정보 페이지로 이동합니다.
  2. 프로젝트 (Chronicle 인스턴스와 연결된 프로젝트)를 선택합니다.
  3. 사용자 인증 정보 만들기 API 키를 클릭합니다.
  4. API 키가 생성되어 대화상자에 표시됩니다.
  5. API 키 수정을 클릭하여 키를 제한합니다.

API 키 제한

  1. API 키 설정 페이지에서 다음을 수행합니다.
    • 이름: 설명이 포함된 이름을 입력합니다 (예: Chronicle Webhook API Key).
  2. API 제한사항에서 다음을 수행합니다.
    1. 키 제한을 선택합니다.
    2. API 선택 드롭다운에서 Google SecOps API (또는 Chronicle API)를 검색하여 선택합니다.
  3. 저장을 클릭합니다.
  4. 페이지 상단의 API 키 필드에서 API 키 값을 복사합니다.
  5. API 키를 안전하게 저장합니다.

Keycloak에서 이벤트 저장소 사용 설정

웹훅 확장 프로그램을 구성하기 전에 Keycloak에서 이벤트 스토리지를 사용 설정하여 이벤트가 생성되고 전달할 수 있도록 합니다.

사용자 이벤트 사용 설정

  1. Keycloak 관리 콘솔에 로그인합니다.
  2. 왼쪽 상단의 영역 드롭다운에서 모니터링할 영역을 선택합니다.
  3. Realm Settings(렐름 설정) > Events(이벤트)로 이동합니다.
  4. 사용자 이벤트 설정 하위 탭을 선택합니다.
  5. 일정 저장 전환 버튼을 사용 설정합니다.
  6. 만료 기간을 설정합니다 (최소 권장 기간: 7일).
  7. 저장을 클릭합니다.

관리 이벤트 사용 설정

  1. 동일한 이벤트 탭에서 관리 이벤트 설정 하위 탭을 선택합니다.
  2. 일정 저장 전환 버튼을 사용 설정합니다.
  3. 표현 포함 전환 버튼을 사용 설정하여 변경된 객체의 전체 세부정보를 캡처합니다.
  4. 만료 기간을 설정합니다 (최소 권장 기간: 7일).
  5. 저장을 클릭합니다.

웹훅 이벤트 리스너 확장 프로그램 설치

Keycloak에는 기본 웹훅 이벤트 리스너가 포함되어 있지 않습니다. 2단계 (p2-inc)에서 keycloak-events 확장 프로그램을 설치하여 웹훅 전송을 사용 설정합니다.

확장 프로그램 다운로드 및 배포

  1. Maven Central의 keycloak-events 출시 페이지에서 최신 출시 JAR를 다운로드하거나 소스에서 빌드합니다.

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. 결과로 생성된 fat JAR 파일을 Keycloak providers 디렉터리에 복사합니다.

    cp target/keycloak-events-*.jar /opt/keycloak/providers/
    
  3. Keycloak을 다시 빌드하고 다시 시작합니다.

    /opt/keycloak/bin/kc.sh build
    /opt/keycloak/bin/kc.sh start
    

웹훅 이벤트 리스너 사용 설정

  1. Keycloak 관리 콘솔에 로그인합니다.
  2. 영역 드롭다운에서 타겟 영역을 선택합니다.
  3. Realm Settings(렐름 설정) > Events(이벤트)로 이동합니다.
  4. 이벤트 리스너 드롭다운에서 ext-event-webhook을 선택합니다.
  5. 저장을 클릭합니다.

Keycloak 웹훅 구성

웹훅 URL 구성

  • Chronicle 엔드포인트 URL과 API 키를 결합합니다.

    <ENDPOINT_URL>?key=<API_KEY>
    
  • 예:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...
    

Keycloak REST API를 통해 웹훅 구독 만들기

keycloak-events 확장 프로그램은 웹훅 구독을 관리하기 위한 REST 엔드포인트를 제공합니다. Keycloak Admin REST API를 사용하여 웹훅을 만듭니다.

1단계: 액세스 토큰 가져오기

  • 관리자 계정을 사용하여 Keycloak에서 액세스 토큰을 요청합니다.

    TOKEN=$(curl -sS -X POST "https://<KEYCLOAK_HOST>/realms/master/protocol/openid-connect/token" \
      -H "Content-Type: application/x-www-form-urlencoded" \
      --data-urlencode "grant_type=password" \
      --data-urlencode "client_id=admin-cli" \
      --data-urlencode "username=<ADMIN_USERNAME>" \
      --data-urlencode "password=<ADMIN_PASSWORD>" \
      | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p')
    

다음을 바꿉니다.

  • <KEYCLOAK_HOST>: Keycloak 서버 호스트 이름 및 포트 (예: keycloak.example.com:8443)
  • <ADMIN_USERNAME>: Keycloak 관리자 사용자 이름
  • <ADMIN_PASSWORD>: Keycloak 관리자 비밀번호

2단계: 웹훅 만들기

  • POST 요청을 보내 타겟 영역의 웹훅 구독을 만듭니다.

    curl -sS -X POST "https://<KEYCLOAK_HOST>/realms/<REALM_NAME>/webhooks" \
      -H "Authorization: Bearer ${TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{
        "enabled": "true",
        "url": "<ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>",
        "secret": "<WEBHOOK_HMAC_SECRET>",
        "eventTypes": ["*"]
      }'
    

다음을 바꿉니다.

  • <KEYCLOAK_HOST>: Keycloak 서버 호스트 이름
  • <REALM_NAME>: 모니터링할 렐름의 이름입니다 (예: master 또는 my-realm).
  • <ENDPOINT_URL>: 이전에 복사한 Chronicle 피드 엔드포인트 URL
  • <API_KEY>: 이전에 만든 Google Cloud API 키
  • <SECRET_KEY>: 이전에 생성된 Chronicle 웹훅 보안 비밀 키
  • <WEBHOOK_HMAC_SECRET>: 웹훅 페이로드의 HMAC 서명을 위한 임의의 보안 비밀 문자열입니다 (예: mySecretKey123).

3단계: 웹훅 확인

  • 영역의 모든 웹훅을 나열하여 웹훅이 생성되었는지 확인합니다.

    curl -sS -X GET "https://<KEYCLOAK_HOST>/realms/<REALM_NAME>/webhooks" \
      -H "Authorization: Bearer ${TOKEN}" \
      -H "Accept: application/json"
    

이 응답은 웹훅 객체 목록을 반환합니다. 웹훅이 "enabled": "true" 및 올바른 URL과 함께 표시되는지 확인합니다.

웹훅 이벤트 유형

eventTypes 필드는 전송되는 이벤트를 필터링하는 표현식 배열을 허용합니다.

  • * - 모든 이벤트 전송 (SIEM 통합에 권장)
  • access.* - 모든 액세스 이벤트 전송
  • admin.* - 모든 관리 이벤트 전송
  • admin.USER-* - 사용자와 관련된 모든 관리자 이벤트 전송
  • admin-USER-CREATE - 사용자 생성 관리 이벤트만 전송

웹훅 페이로드 형식

  • 웹훅은 JSON 페이로드가 포함된 HTTP POST 요청으로 이벤트를 전송합니다. 사용자 이벤트 페이로드의 예:

    {
      "id": "987865-1a2b-3c4d-9876-654321abc",
      "time": 1767799710612,
      "type": "LOGIN",
      "realmId": "12345abcde-1a2b-4d3c-9876-abcd456",
      "clientId": "account-console",
      "userId": "abcd456-1234-5678-abc9-987gfed654",
      "sessionId": "efghij-9876-abcd-456-11223344",
      "ipAddress": "203.0.113.45",
      "details": {
        "auth_method": "openid-connect",
        "auth_type": "code",
        "redirect_uri": "https://app.example.com/callback",
        "consent": "no_consent_required",
        "username": "jdoe"
      }
    }
    

웹훅 재시도 동작

확장 프로그램은 2xx가 아닌 응답이 수신될 때 재시도를 위해 자동 지수 백오프를 사용합니다.

매개변수 기본값 설명
backoffInitialInterval 500 ms 초기 재시도 간격
backoffMaxElapsedTime 900,000ms (15분) 최대 총 재시도 시간
backoffMaxInterval 180,000ms (3분) 재시도 간 최대 간격
backoffMultiplier 5 각 재시도 간격의 승수
backoffRandomizationFactor 0.5 지터의 무작위화 요소

인증 방법 참조

Chronicle 웹훅 피드는 여러 인증 방법을 지원합니다. 공급업체에서 지원하는 방법을 선택합니다.

공급업체에서 맞춤 HTTP 헤더를 지원하는 경우 이 방법을 사용하여 보안을 강화하세요.

  • 요청 형식:

    POST <ENDPOINT_URL> HTTP/1.1
    Content-Type: application/json
    x-goog-chronicle-auth: <API_KEY>
    x-chronicle-auth: <SECRET_KEY>
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

장점:

  • API 키와 보안 비밀이 URL에 표시되지 않음
  • 더 안전함 (헤더가 웹 서버 액세스 로그에 기록되지 않음)
  • 공급업체에서 지원하는 경우 선호되는 방법

방법 2: 쿼리 매개변수

공급업체에서 맞춤 헤더를 지원하지 않는 경우 사용자 인증 정보를 URL에 추가하세요.

  • URL 형식:

    <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>
    
  • 예:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...&secret=abcd1234...
    
  • 요청 형식:

    POST <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY> HTTP/1.1
    Content-Type: application/json
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

단점:

  • URL에 사용자 인증 정보가 표시됨
  • 웹 서버 액세스 로그에 기록될 수 있음
  • 헤더보다 보안 수준이 낮음

방법 3: 하이브리드 (URL + 헤더)

일부 구성에서는 URL에 API 키를 사용하고 헤더에 비밀 키를 사용합니다.

  • 요청 형식:

    POST <ENDPOINT_URL>?key=<API_KEY> HTTP/1.1
    Content-Type: application/json
    x-chronicle-auth: <SECRET_KEY>
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

인증 헤더 이름

Chronicle은 인증을 위해 다음 헤더 이름을 허용합니다.

API 키:

  • x-goog-chronicle-auth(권장)
  • X-Goog-Chronicle-Auth (대소문자 구분 안 함)

보안 비밀 키:

  • x-chronicle-auth(권장)
  • X-Chronicle-Auth (대소문자 구분 안 함)

웹훅 한도 및 권장사항

요청 한도

한도
최대 요청 크기 4MB
최대 QPS (초당 쿼리 수) 15,000
요청 제한 시간 30초
재시도 동작 지수 백오프를 사용한 자동

UDM 매핑 테이블

로그 필드 UDM 매핑 논리
payload.client_id additional.fields payload.client_id, payload.realm_id에서 생성된 필드와 병합됨
payload.realm_id additional.fields
source_timestamp metadata.event_timestamp ISO8601 및 yyyy-MM-dd'T'HH:mm:ss.SSSZ 패턴의 날짜 필터를 사용하여 파싱됨
payload.ip_address metadata.event_type payload.ip_address가 비어 있지 않으면 'STATUS_UPDATE'로 설정되고, uuid가 비어 있지 않으면 'USER_UNCATEGORIZED'로 설정되고, 그 외에는 'GENERIC_EVENT'로 설정됩니다.
uuid metadata.event_type
payload.type metadata.product_event_type 값이 직접 복사됨
payload.session_id network.session_id 값이 직접 복사됨
payload.ip_address principal.ip 값이 직접 복사됨
source_metadata.schema principal.resource.attribute.labels source_metadata.schema, source_metadata.table, source_metadata.is_deleted (문자열로 변환됨), source_metadata.change_type, source_metadata.tx_id, source_metadata.lsn에서 생성된 라벨과 병합됨
source_metadata.table principal.resource.attribute.labels
source_metadata.is_deleted principal.resource.attribute.labels
source_metadata.change_type principal.resource.attribute.labels
source_metadata.tx_id principal.resource.attribute.labels
source_metadata.lsn principal.resource.attribute.labels
uuid principal.user.userid 값이 직접 복사됨
객체 security_result.detection_fields 객체, read_method, payload.id에서 생성된 라벨과 병합됨
read_method security_result.detection_fields
payload.id security_result.detection_fields
redirect_uri target.url 값이 직접 복사됨
사용자 이름 target.user.userid 값이 직접 복사됨
metadata.product_name metadata.product_name 'KEYCLOAK'으로 설정
metadata.vendor_name metadata.vendor_name 'KEYCLOAK'으로 설정
username" from "details_json target.user.userid 변경 로그에서 매핑됨
redirect_uri" from "details_json target.url 변경 로그에서 매핑됨
realm_id" and "client_id additional.fields 변경 로그에서 매핑됨

변경 로그

이 파서의 변경 로그 보기

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