Mengumpulkan file IOC Kustom CSV
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
- Buat bucket Amazon S3 dengan mengikuti panduan pengguna ini: Membuat bucket
- Simpan Name dan Region bucket untuk referensi di masa mendatang (misalnya,
csv-ioc
). - Buat pengguna dengan mengikuti panduan pengguna ini: Membuat pengguna IAM.
- Pilih Pengguna yang dibuat.
- Pilih tab Kredensial keamanan.
- Klik Create Access Key di bagian Access Keys.
- Pilih Layanan pihak ketiga sebagai Kasus penggunaan.
- Klik Berikutnya.
- Opsional: tambahkan tag deskripsi.
- Klik Create access key.
- Klik Download CSV file untuk menyimpan Access Key dan Secret Access Key untuk digunakan nanti.
- Klik Selesai.
- Pilih tab Izin.
- Klik Tambahkan izin di bagian Kebijakan izin.
- Pilih Tambahkan izin.
- Pilih Lampirkan kebijakan secara langsung
- Telusuri dan pilih kebijakan AmazonS3FullAccess.
- Klik Berikutnya.
- Klik Add permissions.
Mengonfigurasi kebijakan dan peran IAM untuk upload S3
- Buka konsol AWS > IAM > Policies > Create policy > tab JSON.
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.
- Ganti
Klik Berikutnya > Buat kebijakan.
Buka IAM > Roles > Create role > AWS service > Lambda.
Lampirkan kebijakan yang baru dibuat.
Beri nama peran
WriteCsvIocToS3Role
, lalu klik Buat peran.
Buat fungsi Lambda
- Di Konsol AWS, buka Lambda > Functions > Create function.
- Klik Buat dari awal.
Berikan detail konfigurasi berikut:
Setelan Nilai Nama csv_custom_ioc_to_s3
Runtime Python 3.13 Arsitektur x86_64 Peran eksekusi WriteCsvIocToS3Role
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))
Buka Configuration > Environment variables > Edit > Add new environment variable.
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
Setelah fungsi dibuat, tetap buka halamannya (atau buka Lambda > Functions > your-function).
Pilih tab Configuration
Di panel General configuration, klik Edit.
Ubah Waktu tunggu menjadi 5 menit (300 detik), lalu klik Simpan.
Membuat jadwal EventBridge
- Buka Amazon EventBridge > Scheduler > Create schedule.
- Berikan detail konfigurasi berikut:
- Jadwal berulang: Tarif (
1 hour
). - Target: fungsi Lambda Anda.
- Name:
csv-custom-ioc-1h
.
- Jadwal berulang: Tarif (
- Klik Buat jadwal.
Opsional: Buat pengguna & kunci IAM hanya baca untuk Google SecOps
- Di Konsol AWS, buka IAM > Users, lalu klik Add users.
- Berikan detail konfigurasi berikut:
- Pengguna: Masukkan nama unik (misalnya,
secops-reader
) - Jenis akses: Pilih Kunci akses - Akses terprogram
- Klik Buat pengguna.
- Pengguna: Masukkan nama unik (misalnya,
- Lampirkan kebijakan baca minimal (kustom): Pengguna > pilih
secops-reader
> Izin > Tambahkan izin > Lampirkan kebijakan secara langsung > Buat kebijakan 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>" } ] }
Tetapkan nama ke
secops-reader-policy
.Buka Buat kebijakan > telusuri/pilih > Berikutnya > Tambahkan izin.
Buka Kredensial keamanan > Kunci akses > Buat kunci akses.
Download CSV (nilai ini dimasukkan ke dalam feed).
Mengonfigurasi feed di Google SecOps untuk memproses file IOC Kustom CSV
- Buka Setelan SIEM > Feed.
- Klik Tambahkan Feed Baru.
- Di kolom Nama feed, masukkan nama untuk feed (misalnya,
CSV Custom IOC
). - Pilih Amazon S3 V2 sebagai Jenis sumber.
- Pilih CSV Custom IOC sebagai Jenis log.
- Klik Berikutnya.
- 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.
- URI S3:
- Klik Berikutnya.
- 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.