Mengumpulkan file IOC Kustom CSV

Didukung di:

Dokumen ini menjelaskan cara menyerap file IOC Kustom CSV ke Google Security Operations menggunakan Amazon S3. Kemudian, UDM memetakan kolom ini ke UDM, menangani berbagai jenis data seperti IP, domain, dan hash, serta memperkaya output dengan detail ancaman, informasi entitas, dan tingkat keparahan.

Sebelum memulai

  • Instance Google SecOps
  • Akses istimewa ke AWS (S3, IAM, Lambda, EventBridge)
  • Akses ke satu atau beberapa URL feed IOC CSV (HTTPS) atau endpoint internal yang menayangkan CSV

Mengonfigurasi bucket AWS S3 dan IAM untuk Google SecOps

  1. Buat bucket Amazon S3 dengan mengikuti panduan pengguna ini: Membuat bucket
  2. Simpan Name dan Region bucket untuk referensi di masa mendatang (misalnya, csv-ioc).
  3. Buat pengguna dengan mengikuti panduan pengguna ini: Membuat pengguna IAM.
  4. Pilih Pengguna yang dibuat.
  5. Pilih tab Kredensial keamanan.
  6. Klik Create Access Key di bagian Access Keys.
  7. Pilih Layanan pihak ketiga sebagai Kasus penggunaan.
  8. Klik Berikutnya.
  9. Opsional: tambahkan tag deskripsi.
  10. Klik Create access key.
  11. Klik Download CSV file untuk menyimpan Access Key dan Secret Access Key untuk digunakan nanti.
  12. Klik Selesai.
  13. Pilih tab Izin.
  14. Klik Tambahkan izin di bagian Kebijakan izin.
  15. Pilih Tambahkan izin.
  16. Pilih Lampirkan kebijakan secara langsung
  17. Telusuri dan pilih kebijakan AmazonS3FullAccess.
  18. Klik Berikutnya.
  19. Klik Add permissions.

Mengonfigurasi kebijakan dan peran IAM untuk upload S3

  1. Buka konsol AWS > IAM > Policies > Create policy > tab JSON.
  2. Masukkan kebijakan berikut:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPutCsvIocObjects",
          "Effect": "Allow",
          "Action": "s3:PutObject",
          "Resource": "arn:aws:s3:::csv-ioc/*"
        }
      ]
    }
    
    • Ganti csv-ioc jika Anda memasukkan nama bucket yang berbeda.
  3. Klik Berikutnya > Buat kebijakan.

  4. Buka IAM > Roles > Create role > AWS service > Lambda.

  5. Lampirkan kebijakan yang baru dibuat.

  6. Beri nama peran WriteCsvIocToS3Role, lalu klik Buat peran.

Buat fungsi Lambda

  1. Di Konsol AWS, buka Lambda > Functions > Create function.
  2. Klik Buat dari awal.
  3. Berikan detail konfigurasi berikut:

    Setelan Nilai
    Nama csv_custom_ioc_to_s3
    Runtime Python 3.13
    Arsitektur x86_64
    Peran eksekusi WriteCsvIocToS3Role
  4. Setelah fungsi dibuat, buka tab Code, hapus stub, lalu masukkan kode berikut (csv_custom_ioc_to_s3.py):

    #!/usr/bin/env python3
    # Lambda: Pull CSV IOC feeds over HTTPS and write raw CSV to S3 (no transform)
    # - Multiple URLs (comma-separated)
    # - Optional auth header
    # - Retries for 429/5xx
    # - Unique filenames per page
    # - Sets ContentType=text/csv
    
    import os, time, json
    from urllib.request import Request, urlopen
    from urllib.error import HTTPError, URLError
    import boto3
    
    BUCKET = os.environ["S3_BUCKET"]
    PREFIX = os.environ.get("S3_PREFIX", "csv-ioc/").strip("/")
    IOC_URLS = [u.strip() for u in os.environ.get("IOC_URLS", "").split(",") if u.strip()]
    AUTH_HEADER = os.environ.get("AUTH_HEADER", "")  # e.g., "Authorization: Bearer <token>" OR just "Bearer <token>"
    TIMEOUT = int(os.environ.get("TIMEOUT", "60"))
    
    s3 = boto3.client("s3")
    
    def _build_request(url: str) -> Request:
        if not url.lower().startswith("https://"):
            raise ValueError("Only HTTPS URLs are allowed in IOC_URLS")
        req = Request(url, method="GET")
        # Auth header: either "Header-Name: value" or just "Bearer token" -> becomes Authorization
        if AUTH_HEADER:
            if ":" in AUTH_HEADER:
                k, v = AUTH_HEADER.split(":", 1)
                req.add_header(k.strip(), v.strip())
            else:
                req.add_header("Authorization", AUTH_HEADER.strip())
        req.add_header("Accept", "text/csv, */*")
        return req
    
    def _http_bytes(req: Request, timeout: int = TIMEOUT, max_retries: int = 5) -> bytes:
        attempt, backoff = 0, 1.0
        while True:
            try:
                with urlopen(req, timeout=timeout) as r:
                    return r.read()
            except HTTPError as e:
                if (e.code == 429 or 500 <= e.code <= 599) and attempt < max_retries:
                    time.sleep(backoff); attempt += 1; backoff *= 2; continue
                raise
            except URLError:
                if attempt < max_retries:
                    time.sleep(backoff); attempt += 1; backoff *= 2; continue
                raise
    
    def _safe_name(url: str) -> str:
        # Create a short, filesystem-safe token for the URL
        return url.replace("://", "_").replace("/", "_").replace("?", "_").replace("&", "_")[:100]
    
    def _put_csv(blob: bytes, url: str, run_ts: int, idx: int) -> str:
        key = f"{PREFIX}/{time.strftime('%Y/%m/%d/%H%M%S', time.gmtime(run_ts))}-url{idx:03d}-{_safe_name(url)}.csv"
        s3.put_object(
            Bucket=BUCKET,
            Key=key,
            Body=blob,
            ContentType="text/csv",
        )
        return key
    
    def lambda_handler(event=None, context=None):
        assert IOC_URLS, "IOC_URLS must contain at least one HTTPS URL"
        run_ts = int(time.time())
        written = []
        for i, url in enumerate(IOC_URLS):
            req = _build_request(url)
            data = _http_bytes(req)
            key = _put_csv(data, url, run_ts, i)
            written.append({"url": url, "s3_key": key, "bytes": len(data)})
        return {"ok": True, "written": written}
    
    if __name__ == "__main__":
        print(json.dumps(lambda_handler(), indent=2))
    
  5. Buka Configuration > Environment variables > Edit > Add new environment variable.

  6. Masukkan variabel lingkungan berikut, ganti dengan nilai Anda:

    Kunci Contoh
    S3_BUCKET csv-ioc
    S3_PREFIX csv-ioc/
    IOC_URLS https://ioc.example.com/feed.csv,https://another.example.org/iocs.csv
    AUTH_HEADER Authorization: Bearer <token>
    TIMEOUT 60
  7. Setelah fungsi dibuat, tetap buka halamannya (atau buka Lambda > Functions > your-function).

  8. Pilih tab Configuration

  9. Di panel General configuration, klik Edit.

  10. Ubah Waktu tunggu menjadi 5 menit (300 detik), lalu klik Simpan.

Membuat jadwal EventBridge

  1. Buka Amazon EventBridge > Scheduler > Create schedule.
  2. Berikan detail konfigurasi berikut:
    • Jadwal berulang: Tarif (1 hour).
    • Target: fungsi Lambda Anda.
    • Name: csv-custom-ioc-1h.
  3. Klik Buat jadwal.

Opsional: Buat pengguna & kunci IAM hanya baca untuk Google SecOps

  1. Di Konsol AWS, buka IAM > Users, lalu klik Add users.
  2. Berikan detail konfigurasi berikut:
    • Pengguna: Masukkan nama unik (misalnya, secops-reader)
    • Jenis akses: Pilih Kunci akses - Akses terprogram
    • Klik Buat pengguna.
  3. Lampirkan kebijakan baca minimal (kustom): Pengguna > pilih secops-reader > Izin > Tambahkan izin > Lampirkan kebijakan secara langsung > Buat kebijakan
  4. Di editor JSON, masukkan kebijakan berikut:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:GetObject"],
          "Resource": "arn:aws:s3:::<your-bucket>/*"
        },
        {
          "Effect": "Allow",
          "Action": ["s3:ListBucket"],
          "Resource": "arn:aws:s3:::<your-bucket>"
        }
      ]
    }
    
  5. Tetapkan nama ke secops-reader-policy.

  6. Buka Buat kebijakan > telusuri/pilih > Berikutnya > Tambahkan izin.

  7. Buka Kredensial keamanan > Kunci akses > Buat kunci akses.

  8. Download CSV (nilai ini dimasukkan ke dalam feed).

Mengonfigurasi feed di Google SecOps untuk memproses file IOC Kustom CSV

  1. Buka Setelan SIEM > Feed.
  2. Klik Tambahkan Feed Baru.
  3. Di kolom Nama feed, masukkan nama untuk feed (misalnya, CSV Custom IOC).
  4. Pilih Amazon S3 V2 sebagai Jenis sumber.
  5. Pilih CSV Custom IOC sebagai Jenis log.
  6. Klik Berikutnya.
  7. Tentukan nilai untuk parameter input berikut:
    • URI S3: s3://csv-ioc/csv-ioc/
    • Opsi penghapusan sumber: Pilih opsi penghapusan sesuai preferensi Anda.
    • Usia File Maksimum: Default 180 Hari.
    • ID Kunci Akses: Kunci akses pengguna dengan akses ke bucket S3.
    • Kunci Akses Rahasia: Kunci rahasia pengguna dengan akses ke bucket S3.
    • Namespace aset: Namespace aset.
    • Label penyerapan: Label yang akan diterapkan ke peristiwa dari feed ini.
  8. Klik Berikutnya.
  9. Tinjau konfigurasi feed baru Anda di layar Selesaikan, lalu klik Kirim.

Tabel Pemetaan UDM

Kolom Log Pemetaan UDM Logika
asn entity.metadata.threat.detection_fields.asn_label.value Dipetakan langsung dari kolom "asn".
category entity.metadata.threat.category_details Dipetakan langsung dari kolom "category".
classification entity.metadata.threat.category_details Ditambahkan ke "classification - " dan dipetakan ke kolom "entity.metadata.threat.category_details".
column2 entity.entity.hostname Dipetakan ke "entity.entity.hostname" jika [category] cocok dengan ".?ip" atau ".?proxy" dan [not_ip] bernilai benar (true).
column2 entity.entity.ip Digabungkan ke "entity.entity.ip" jika [category] cocok dengan ".?ip" atau ".?proxy" dan [not_ip] adalah salah (false).
confidence entity.metadata.threat.confidence_score Dikonversi menjadi float dan dipetakan ke kolom "entity.metadata.threat.confidence_score".
country entity.entity.location.country_or_region Dipetakan langsung dari kolom "country".
date_first entity.metadata.threat.first_discovered_time Diuraikan sebagai ISO8601 dan dipetakan ke kolom "entity.metadata.threat.first_discovered_time".
date_last entity.metadata.threat.last_updated_time Diuraikan sebagai ISO8601 dan dipetakan ke kolom "entity.metadata.threat.last_updated_time".
detail entity.metadata.threat.summary Dipetakan langsung dari kolom "detail".
detail2 entity.metadata.threat.description Dipetakan langsung dari kolom "detail2".
domain entity.entity.hostname Dipetakan langsung dari kolom "domain".
email entity.entity.user.email_addresses Digabungkan ke kolom "entity.entity.user.email_addresses".
id entity.metadata.product_entity_id Ditambahkan ke "id - " dan dipetakan ke kolom "entity.metadata.product_entity_id".
import_session_id entity.metadata.threat.detection_fields.import_session_id_label.value Dipetakan langsung dari kolom "import_session_id".
itype entity.metadata.threat.detection_fields.itype_label.value Dipetakan langsung dari kolom "itype".
lat entity.entity.location.region_latitude Dikonversi menjadi float dan dipetakan ke kolom "entity.entity.location.region_latitude".
lon entity.entity.location.region_longitude Dikonversi menjadi float dan dipetakan ke kolom "entity.entity.location.region_longitude".
maltype entity.metadata.threat.detection_fields.maltype_label.value Dipetakan langsung dari kolom "maltype".
md5 entity.entity.file.md5 Dipetakan langsung dari kolom "md5".
media entity.metadata.threat.detection_fields.media_label.value Dipetakan langsung dari kolom "media".
media_type entity.metadata.threat.detection_fields.media_type_label.value Dipetakan langsung dari kolom "media_type".
org entity.metadata.threat.detection_fields.org_label.value Dipetakan langsung dari kolom "org".
resource_uri entity.entity.url Dipetakan ke "entity.entity.url" jika [itype] tidak cocok dengan "(ip
resource_uri entity.metadata.threat.url_back_to_product Dipetakan ke "entity.metadata.threat.url_back_to_product" jika [itype] cocok dengan "(ip
score entity.metadata.threat.confidence_details Dipetakan langsung dari kolom "score".
severity entity.metadata.threat.severity Dikonversi menjadi huruf besar dan dipetakan ke kolom "entity.metadata.threat.severity" jika cocok dengan "LOW", "MEDIUM", "HIGH", atau "CRITICAL".
source entity.metadata.threat.detection_fields.source_label.value Dipetakan langsung dari kolom "source".
source_feed_id entity.metadata.threat.detection_fields.source_feed_id_label.value Dipetakan langsung dari kolom "source_feed_id".
srcip entity.entity.ip Digabungkan ke "entity.entity.ip" jika [srcip] tidak kosong dan tidak sama dengan [value].
state entity.metadata.threat.detection_fields.state_label.value Dipetakan langsung dari kolom "state".
trusted_circle_ids entity.metadata.threat.detection_fields.trusted_circle_ids_label.value Dipetakan langsung dari kolom "trusted_circle_ids".
update_id entity.metadata.threat.detection_fields.update_id_label.value Dipetakan langsung dari kolom "update_id".
value entity.entity.file.full_path Dipetakan ke "entity.entity.file.full_path" jika [category] cocok dengan ".*?file".
value entity.entity.file.md5 Dipetakan ke "entity.entity.file.md5" jika [category] cocok dengan ".*?md5" dan [value] adalah string heksadesimal 32 karakter.
value entity.entity.file.sha1 Dipetakan ke "entity.entity.file.sha1" jika ([category] cocok dengan ".?md5" dan [value] adalah string heksadesimal 40 karakter) atau ([category] cocok dengan ".?sha1" dan [value] adalah string heksadesimal 40 karakter).
value entity.entity.file.sha256 Dipetakan ke "entity.entity.file.sha256" jika ([category] cocok dengan ".?md5" dan [value] adalah string heksadesimal dan [file_type] bukan "md5") atau ([category] cocok dengan ".?sha256" dan [value] adalah string heksadesimal).
value entity.entity.hostname Dipetakan ke "entity.entity.hostname" jika ([category] cocok dengan ".?domain") atau ([category] cocok dengan ".?ip" atau ".*?proxy" dan [not_ip] adalah benar).
value entity.entity.url Dipetakan ke "entity.entity.url" jika ([category] cocok dengan ".*?url") atau ([category] cocok dengan "url" dan [resource_uri] tidak kosong).
T/A entity.metadata.collected_timestamp Diisi dengan stempel waktu peristiwa.
T/A entity.metadata.interval.end_time Ditetapkan ke nilai konstan 253402300799 detik.
T/A entity.metadata.interval.start_time Diisi dengan stempel waktu peristiwa.
T/A entity.metadata.vendor_name Tetapkan ke nilai konstan "IOC Kustom".

Perlu bantuan lain? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.