파일 검색 프레임워크 로그 수집

다음에서 지원:

이 문서에서는 Google Cloud Storage V2를 사용하여 파일 스캔 프레임워크 로그를 Google Security Operations에 수집하는 방법을 설명합니다.

파일 스캔 프레임워크 (FSF)는 Emerson Electric Co.에서 개발한 오픈소스 모듈식 재귀 파일 스캔 솔루션입니다. FSF는 클라이언트-서버 아키텍처를 사용하여 파일을 분석하고 파일 메타데이터, YARA 서명 일치, 추출된 하위 객체, 모듈별 메타데이터를 포함한 자세한 JSON 스캔 결과를 생성합니다.

시작하기 전에

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

  • Google SecOps 인스턴스
  • Cloud Storage API가 사용 설정된 GCP 프로젝트
  • GCS 버킷을 만들고 관리할 수 있는 권한
  • GCS 버킷의 IAM 정책을 관리할 수 있는 권한
  • 로그 디렉터리에 대한 쓰기 액세스 권한이 있는 배포된 FSF 서버 인스턴스
  • FSF 서버 호스트에 대한 루트 또는 sudo 액세스

Google Cloud Storage 버킷 만들기

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

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

FSF 로그 출력 디렉터리 구성

FSF는 구성 가능한 로그 디렉터리에 JSON 검사 결과를 씁니다. Google SecOps 수집을 위한 전용 디렉터리를 구성합니다.

  1. SSH를 통해 FSF 서버 호스트에 연결합니다.
  2. FSF 서버 구성 파일을 엽니다.

    sudo nano /opt/fsf/fsf-server/conf/config.py
    
  3. SCANNER_CONFIG 사전을 찾습니다.

  4. LOG_PATH 매개변수를 전용 디렉터리로 업데이트합니다.

    SCANNER_CONFIG = {
        'LOG_PATH': '/var/log/fsf',
        'YARA_PATH': '/opt/fsf/fsf-server/yara/rules.yara',
        'PID_PATH': '/tmp/scanner.pid',
        'EXPORT_PATH': '/tmp',
        'TIMEOUT': 60,
        'MAX_DEPTH': 10
    }
    
  5. 저장하고 파일을 닫습니다.

  6. 적절한 권한으로 로그 디렉터리를 만듭니다.

    sudo mkdir -p /var/log/fsf
    sudo chown -R fsf:fsf /var/log/fsf
    sudo chmod 755 /var/log/fsf
    
  7. FSF 서버를 다시 시작하여 변경사항을 적용합니다.

    sudo systemctl restart fsf
    
  8. FSF가 새 디렉터리에 로그를 작성하는지 확인합니다.

    ls -lh /var/log/fsf/
    

Fluentd 설치 및 구성

Fluentd는 FSF 로그 파일을 테일링하고 Google Cloud Storage로 전송합니다.

Fluentd 설치

  1. FSF 서버 호스트에서 Fluentd (td-agent)를 설치합니다.

    curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | sh
    
  2. GCS 출력 플러그인을 설치합니다.

    sudo td-agent-gem install fluent-plugin-gcs
    
  3. 플러그인 설치를 확인합니다.

    td-agent-gem list | grep fluent-plugin-gcs
    

Fluentd용 GCP 서비스 계정 만들기

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

서비스 계정 키 만들기

  1. 서비스 계정 목록에서 서비스 계정 (fsf-fluentd-shipper)을 클릭합니다.
  2. 탭으로 이동합니다.
  3. 키 추가 > 새 키 만들기를 클릭합니다.
  4. 키 유형으로 JSON을 선택합니다.
  5. 만들기를 클릭합니다.
  6. JSON 키 파일이 컴퓨터에 다운로드됩니다.
  7. 키 파일을 FSF 서버 호스트로 전송합니다.

    scp /path/to/downloaded-key.json user@fsf-server:/etc/td-agent/gcp-key.json
    
  8. 키 파일에 적절한 권한을 설정합니다.

    sudo chown td-agent:td-agent /etc/td-agent/gcp-key.json
    sudo chmod 600 /etc/td-agent/gcp-key.json
    

GCS 버킷에 IAM 권한 부여

  1. Cloud Storage> 버킷으로 이동합니다.
  2. 버킷 이름 (fsf-logs-secops)을 클릭합니다.
  3. 권한 탭으로 이동합니다.
  4. 액세스 권한 부여를 클릭합니다.
  5. 다음 구성 세부정보를 제공합니다.
    • 주 구성원 추가: 서비스 계정 이메일 (예: fsf-fluentd-shipper@PROJECT_ID.iam.gserviceaccount.com)을 입력합니다.
    • 역할 할당: 스토리지 객체 관리자를 선택합니다.
  6. 저장을 클릭합니다.

Fluentd 구성

  1. FSF 서버 호스트에서 Fluentd 구성 파일을 만듭니다.

    sudo nano /etc/td-agent/td-agent.conf
    
  2. 다음 구성을 추가합니다.

    # Tail FSF JSON logs
    <source>
        @type tail
        path /var/log/fsf/*.log
        pos_file /var/log/td-agent/fsf.log.pos
        tag fsf.scan
        read_from_head true
        <parse>
            @type json
            time_key timestamp
            time_format %Y-%m-%dT%H:%M:%S.%L%z
        </parse>
    </source>
    
    # Ship to Google Cloud Storage
    <match fsf.scan>
        @type gcs
        project YOUR_GCP_PROJECT_ID
        keyfile /etc/td-agent/gcp-key.json
        bucket fsf-logs-secops
        object_key_format %{path}%{time_slice}_%{index}.%{file_extension}
        path fsf-logs/
        <buffer tag,time>
            @type file
            path /var/log/td-agent/buffer/gcs
            timekey 3600
            timekey_wait 10m
            timekey_use_utc true
            chunk_limit_size 10MB
        </buffer>
        <format>
            @type json
        </format>
        store_as json
        auto_create_bucket false
    </match>
    
  3. YOUR_GCP_PROJECT_ID를 실제 GCP 프로젝트 ID로 바꿉니다.

  4. 저장하고 파일을 닫습니다.

  5. 버퍼 디렉터리를 만듭니다.

    sudo mkdir -p /var/log/td-agent/buffer/gcs
    sudo chown -R td-agent:td-agent /var/log/td-agent/buffer
    
  6. Fluentd를 다시 시작하여 구성을 적용합니다.

    sudo systemctl restart td-agent
    
  7. 부팅 시 Fluentd가 시작되도록 사용 설정합니다.

    sudo systemctl enable td-agent
    
  8. Fluentd가 실행 중인지 확인합니다.

    sudo systemctl status td-agent
    

로그 전송 확인

  1. Fluentd 로그에서 오류를 확인합니다.

    sudo tail -f /var/log/td-agent/td-agent.log
    
  2. 테스트 FSF 스캔을 트리거하여 로그를 생성합니다.

    echo "test content" > /tmp/test.txt
    /opt/fsf/fsf-client/fsf_client.py /tmp/test.txt --suppress-report
    
  3. Fluentd가 로그를 처리하고 전송할 때까지 1~2분 정도 기다립니다.

  4. GCP 콘솔에서 Cloud Storage > 버킷으로 이동합니다.

  5. 버킷 이름 (fsf-logs-secops)을 클릭합니다.

  6. fsf-logs/ 접두사로 이동합니다.

  7. 타임스탬프가 포함된 JSON 파일이 생성되는지 확인합니다.

  8. 파일을 다운로드하고 검사하여 JSON 형식의 FSF 검사 결과가 포함되어 있는지 확인합니다.

Google SecOps 서비스 계정 가져오기

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

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

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

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

  9. 다음을 클릭합니다.

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

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

      gs://fsf-logs-secops/fsf-logs/
      
    • 소스 삭제 옵션: 환경설정에 따라 삭제 옵션을 선택합니다.

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

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

    • 애셋 네임스페이스: 애셋 네임스페이스입니다.

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

  11. 다음을 클릭합니다.

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

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

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

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

수집 확인

  1. 초기 인게션이 완료될 때까지 10~15분 정도 기다립니다.
  2. Google SecOps에서 SIEM 설정 > 피드로 이동합니다.
  3. 피드 (FSF File Scanning Logs)를 찾습니다.
  4. 상태활성으로 표시되는지 확인합니다.
  5. 피드 이름을 클릭하여 수집 측정항목을 확인합니다.
  6. 수집된 이벤트 수가 증가하는지 확인합니다.
  7. Google SecOps에서 검색으로 이동합니다.
  8. 검색 쿼리를 실행하여 FSF 로그가 수집되고 있는지 확인합니다.

    metadata.log_type = "FILE_SCANNING_FRAMEWORK"
    
  9. FSF 검색 결과가 검색 결과에 표시되는지 확인합니다.

문제 해결

GCS에 로그가 표시되지 않음

  • FSF가 /var/log/fsf/에 로그를 쓰고 있는지 확인합니다.

    ls -lh /var/log/fsf/
    tail -f /var/log/fsf/*.log
    
  • Fluentd 로그에서 오류를 확인합니다.

    sudo tail -f /var/log/td-agent/td-agent.log
    
  • GCP 서비스 계정 키가 유효하고 올바른 권한이 있는지 확인합니다.

  • Fluentd 구성의 버킷 이름이 실제 버킷 이름과 일치하는지 확인합니다.

Fluentd 권한 오류

  • 서비스 계정 (fsf-fluentd-shipper)에 버킷에 대한 스토리지 객체 관리자 역할이 있는지 확인합니다.
  • Fluentd 구성의 키 경로가 올바른지 확인합니다.
  • 키 파일에 올바른 소유권과 권한이 있는지 확인합니다.

    ls -l /etc/td-agent/gcp-key.json
    

Google SecOps에서 로그를 수집하지 않음

  • Google SecOps 서비스 계정에 버킷에 대한 스토리지 객체 뷰어 역할이 있는지 확인합니다.
  • 피드 구성의 버킷 URI가 올바르고 후행 슬래시가 포함되어 있는지 확인합니다.
  • 지정된 접두사 경로에 GCS 버킷에 파일이 있는지 확인합니다.
  • SIEM 설정> 피드에서 피드 상태를 확인하여 오류 메시지를 확인합니다.

FSF 로그가 예상 형식에 없습니다.

  • FSF가 JSON 출력을 작성하도록 구성되어 있는지 확인합니다 (기본 동작).
  • Fluentd <parse> 섹션이 @type json으로 구성되어 있는지 확인합니다.
  • 로그 파일을 수동으로 검사하여 유효한 JSON이 포함되어 있는지 확인합니다.

    head -n 1 /var/log/fsf/*.log | jq .
    

UDM 매핑 테이블

로그 필드 UDM 매핑 논리
CompressType_label, compressed_parents about.labels CompressType_label('압축 유형' 키, 메시지에 '압축 유형'이 포함된 경우 Object.EXTRACT_ZIP.Object_0.Compress Type의 값)과 compressed_parents('압축된 상위 파일' 키, Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.additional_info.compressed_parents에서 연결됨)에서 병합됨
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5, Object.EXTRACT_SWF.META_BASIC_INFO.MD5, Object.EXTRACT_GZIP.META_BASIC_INFO.MD5, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5 intermediary.file.md5 EXTRACT_EMBEDDED가 있는 경우 Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5 값, EXTRACT_ZIP이 있는 경우 Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5 값, EXTRACT_SWF가 있는 경우 Object.EXTRACT_SWF.META_BASIC_INFO.MD5 값, EXTRACT_GZIP이 있는 경우 Object.EXTRACT_GZIP.META_BASIC_INFO.MD5 값, 그 외의 경우 Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5 값
Object.EXTRACT_EMBEDDED.Object_0.Description intermediary.file.mime_type 값이 직접 복사됨
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1, Object.EXTRACT_SWF.META_BASIC_INFO.SHA1, Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1 intermediary.file.sha1 EXTRACT_EMBEDDED가 있는 경우 Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1, EXTRACT_ZIP이 있는 경우 Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1, EXTRACT_SWF가 있는 경우 Object.EXTRACT_SWF.META_BASIC_INFO.SHA1, EXTRACT_GZIP이 있는 경우 Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1, 그렇지 않은 경우 Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256, Object.EXTRACT_SWF.META_BASIC_INFO.SHA256, Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256 intermediary.file.sha256 EXTRACT_EMBEDDED가 있는 경우 Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256 값, EXTRACT_ZIP이 있는 경우 Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256 값, EXTRACT_SWF가 있는 경우 Object.EXTRACT_SWF.META_BASIC_INFO.SHA256 값, EXTRACT_GZIP이 있는 경우 Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256 값, 그렇지 않은 경우 Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256 값
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size, Object.EXTRACT_SWF.META_BASIC_INFO.Size, Object.EXTRACT_GZIP.META_BASIC_INFO.Size, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size intermediary.file.size EXTRACT_EMBEDDED가 있는 경우 Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size, EXTRACT_ZIP이 있는 경우 Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size, EXTRACT_SWF가 있는 경우 Object.EXTRACT_SWF.META_BASIC_INFO.Size, EXTRACT_GZIP이 있는 경우 Object.EXTRACT_GZIP.META_BASIC_INFO.Size, EXTRACT_CAB가 있는 경우 Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size. 후행 ' .*'이 삭제되고 uinteger로 변환됩니다.
Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.scan_id intermediary.resource.id 값이 직접 복사됨
Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.permalink intermediary.url 값이 직접 복사됨
Object.META_EMERSON_INFO.results intermediary.user.email_addresses 결과 배열의 matched_email에서 병합됨
Summary.Observations metadata.description 쉼표와 공백(", ") 구분자를 사용하여 배열에서 연결됨, 선행 쉼표 삭제됨
스캔 시간 metadata.event_timestamp yyyy-MM-dd HH:mm:ss 형식의 날짜 필터를 사용하여 변환됨
소스 metadata.event_type 소스가 비어 있지 않으면 'SCAN_FILE'로 설정하고, 그렇지 않으면 'GENERIC_EVENT'로 설정합니다.
Object.META_VT_CACHE._id metadata.product_log_id 값이 직접 복사됨
result.ad_data.message network.http.response_code result.ad_data.message에서 grok 패턴 INT를 사용하여 정수로 추출됨
소스 principal.hostname 값이 직접 복사됨
Object.META_EMERSON_INFO.result_summary, Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg security_result.summary 있는 경우 Object.META_EMERSON_INFO.result_summary로 설정하고, 그렇지 않으면 Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg로 설정합니다.
파일 이름 target.file.full_path 값이 직접 복사됨
Object.META_BASIC_INFO.MD5 target.file.md5 값이 직접 복사됨
Summary.Yara target.file.mime_type Summary.Yara의 첫 번째 색인에서 추출되며, Yara가 있는 경우 대문자로 변환되고 'FT_'가 삭제됩니다. Yara가 없는 경우 EXTRACT_ZIP이 있으면 'ZIP', EXTRACT_SWF가 있으면 'SWF', EXTRACT_GZIP이 있으면 'GZIP', EXTRACT_CAB이 있으면 'CAB'로 설정됩니다.
Object.META_BASIC_INFO.SHA1, Object.META_VT_CACHE.SHA1 target.file.sha1 비어 있지 않은 경우 Object.META_BASIC_INFO.SHA1의 값, 비어 있는 경우 Object.META_VT_CACHE.SHA1의 값
Object.META_BASIC_INFO.SHA256 target.file.sha256 값이 직접 복사됨
Object.META_BASIC_INFO.Size target.file.size 후행 ' .*'이 삭제되고 uinteger로 변환됨
metadata.vendor_name 'EMERSON'으로 설정
metadata.product_name '파일 검색 프레임워크'로 설정

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