Collecter les ensembles de données principaux de Code42 Incydr
Ce document explique comment ingérer les ensembles de données principaux de Code42 Incydr (utilisateurs, sessions, audit, cas et, éventuellement, événements de fichier) dans Google Security Operations à l'aide d'Amazon S3.
Avant de commencer
- Instance Google SecOps
- Accès privilégié à Code42 Incydr
- Accès privilégié à AWS (S3, IAM, Lambda, EventBridge)
Collecter les conditions préalables de la source (ID, clés API, ID d'organisation, jetons)
- Connectez-vous à l'interface utilisateur Web Code42 Incydr.
- Accédez à Administration> Intégrations> Clients API.
- Créez un client.
- Copiez et enregistrez les informations suivantes dans un emplacement sécurisé :
- ID client.
- Code secret du client.
- URL de base : (par exemple,
https://api.us.code42.com
,https://api.us2.code42.com
,https://api.ie.code42.com
,https://api.gov.code42.com
).
Configurer un bucket AWS S3 et IAM pour Google SecOps
- Créez un bucket Amazon S3 en suivant ce guide de l'utilisateur : Créer un bucket.
- Enregistrez le nom et la région du bucket pour une utilisation ultérieure.
- Créez un utilisateur en suivant ce guide : Créer un utilisateur IAM.
- Sélectionnez l'utilisateur créé.
- Sélectionnez l'onglet Informations d'identification de sécurité.
- Cliquez sur Créer une clé d'accès dans la section Clés d'accès.
- Sélectionnez Service tiers comme Cas d'utilisation.
- Cliquez sur Suivant.
- Facultatif : ajoutez un tag de description.
- Cliquez sur Créer une clé d'accès.
- Cliquez sur Télécharger le fichier CSV pour enregistrer la clé d'accès et la clé d'accès secrète pour une utilisation ultérieure.
- Cliquez sur OK.
- Sélectionnez l'onglet Autorisations.
- Cliquez sur Ajouter des autorisations dans la section Règles d'autorisation.
- Sélectionnez Ajouter des autorisations.
- Sélectionnez Joindre directement des règles.
- Recherchez et sélectionnez la règle AmazonS3FullAccess.
- Cliquez sur Suivant.
- Cliquez sur Ajouter des autorisations.
Configurer AWS Lambda pour interroger Code42 Incydr (sans transformation)
- Dans la console AWS, accédez à Lambda> Functions> Create function (Lambda > Fonctions > Créer une fonction).
- Cliquez sur Créer à partir de zéro.
- Fournissez les informations de configuration suivantes :
- Nom : saisissez un nom unique et explicite (par exemple,
code42-incydr-pull
). - Environnement d'exécution : sélectionnez Python 3.13.
- Autorisations : sélectionnez un rôle avec s3:PutObject et Cloudwatch.
- Nom : saisissez un nom unique et explicite (par exemple,
- Cliquez sur Créer une fonction.
- Sélectionnez Configuration > Configuration générale > Modifier.
- Configurez Timeout=5m et Memory=1024 MB.
- Cliquez sur Enregistrer.
- Sélectionnez Configuration > Variables d'environnement > Modifier > Ajouter.
INCYDR_BASE_URL
=https://api.us.code42.com
INCYDR_CLIENT_ID
=<Client ID>
INCYDR_CLIENT_SECRET
=<Client Secret>
S3_BUCKET
=code42-incydr
S3_PREFIX
=code42/
PAGE_SIZE
=500
LOOKBACK_MINUTES
=60
STREAMS
=users,sessions,audit,cases
- Facultatif :
FE_ADV_QUERY_JSON
= `` - Facultatif :
FE_PAGE_SIZE
=1000
- Cliquez sur Enregistrer.
Sélectionnez Code et saisissez le code Python suivant :
import base64, json, os, time from datetime import datetime, timedelta, timezone from urllib.parse import urlencode from urllib.request import Request, urlopen import boto3 BASE = os.environ["INCYDR_BASE_URL"].rstrip("/") CID = os.environ["INCYDR_CLIENT_ID"] CSECRET = os.environ["INCYDR_CLIENT_SECRET"] BUCKET = os.environ["S3_BUCKET"] PREFIX_BASE = os.environ.get("S3_PREFIX", "code42/") PAGE_SIZE = int(os.environ.get("PAGE_SIZE", "500")) LOOKBACK_MINUTES = int(os.environ.get("LOOKBACK_MINUTES", "60")) STREAMS = [s.strip() for s in os.environ.get("STREAMS", "users").split(",") if s.strip()] FE_ADV_QUERY_JSON = os.environ.get("FE_ADV_QUERY_JSON", "").strip() FE_PAGE_SIZE = int(os.environ.get("FE_PAGE_SIZE", "1000")) s3 = boto3.client("s3") def now_utc(): return datetime.now(timezone.utc) def iso_minus(minutes: int): return (now_utc() - timedelta(minutes=minutes)).strftime("%Y-%m-%dT%H:%M:%SZ") def put_bytes(key: str, body: bytes): s3.put_object(Bucket=BUCKET, Key=key, Body=body) def put_json(prefix: str, page_label: str, data): ts = now_utc().strftime("%Y/%m/%d/%H%M%S") key = f"{PREFIX_BASE}{prefix}{ts}-{page_label}.json" put_bytes(key, json.dumps(data).encode("utf-8")) return key def auth_header(): auth = base64.b64encode(f"{CID}:{CSECRET}".encode()).decode() req = Request(f"{BASE}/v1/oauth", data=b"", method="POST") req.add_header("Authorization", f"Basic {auth}") req.add_header("Accept", "application/json") with urlopen(req, timeout=30) as r: data = json.loads(r.read().decode()) return {"Authorization": f"Bearer {data['access_token']}", "Accept": "application/json"} def http_get(path: str, params: dict | None = None, headers: dict | None = None): url = f"{BASE}{path}" if params: url += ("?" + urlencode(params)) req = Request(url, method="GET") for k, v in (headers or {}).items(): req.add_header(k, v) with urlopen(req, timeout=60) as r: return r.read() def http_post_json(path: str, body: dict, headers: dict | None = None): url = f"{BASE}{path}" req = Request(url, data=json.dumps(body).encode("utf-8"), method="POST") req.add_header("Content-Type", "application/json") for k, v in (headers or {}).items(): req.add_header(k, v) with urlopen(req, timeout=120) as r: return r.read() # USERS (/v1/users) def pull_users(hdrs): next_token = None pages = 0 while True: params = {"active": "true", "blocked": "false", "pageSize": PAGE_SIZE} if next_token: params["pgToken"] = next_token raw = http_get("/v1/users", params, hdrs) data = json.loads(raw.decode()) put_json("users/", f"users-page-{pages}", data) pages += 1 next_token = data.get("nextPgToken") or data.get("next_pg_token") if not next_token: break return pages # SESSIONS (/v1/sessions) — alerts live inside sessions def pull_sessions(hdrs): start_iso = iso_minus(LOOKBACK_MINUTES) next_token = None pages = 0 while True: params = { "hasAlerts": "true", "startTime": start_iso, "pgSize": PAGE_SIZE, } if next_token: params["pgToken"] = next_token raw = http_get("/v1/sessions", params, hdrs) data = json.loads(raw.decode()) put_json("sessions/", f"sessions-page-{pages}", data) pages += 1 next_token = data.get("nextPgToken") or data.get("next_page_token") if not next_token: break return pages # AUDIT LOG (/v1/audit) — CSV export or paged JSON; write as received def pull_audit(hdrs): start_iso = iso_minus(LOOKBACK_MINUTES) next_token = None pages = 0 while True: params = {"startTime": start_iso, "pgSize": PAGE_SIZE} if next_token: params["pgToken"] = next_token raw = http_get("/v1/audit", params, hdrs) try: data = json.loads(raw.decode()) put_json("audit/", f"audit-page-{pages}", data) next_token = data.get("nextPgToken") or data.get("next_page_token") pages += 1 if not next_token: break except Exception: ts = now_utc().strftime("%Y/%m/%d/%H%M%S") key = f"{PREFIX_BASE}audit/{ts}-audit-export.bin" put_bytes(key, raw) pages += 1 break return pages # CASES (/v1/cases) def pull_cases(hdrs): next_token = None pages = 0 while True: params = {"pgSize": PAGE_SIZE} if next_token: params["pgToken"] = next_token raw = http_get("/v1/cases", params, hdrs) data = json.loads(raw.decode()) put_json("cases/", f"cases-page-{pages}", data) pages += 1 next_token = data.get("nextPgToken") or data.get("next_page_token") if not next_token: break return pages # FILE EVENTS (/v2/file-events/search) — enabled only if you provide FE_ADV_QUERY_JSON def pull_file_events(hdrs): if not FE_ADV_QUERY_JSON: return 0 try: base_query = json.loads(FE_ADV_QUERY_JSON) except Exception: raise RuntimeError("FE_ADV_QUERY_JSON is not valid JSON") pages = 0 next_token = None while True: body = dict(base_query) body["pgSize"] = FE_PAGE_SIZE if next_token: body["pgToken"] = next_token raw = http_post_json("/v2/file-events/search", body, hdrs) data = json.loads(raw.decode()) put_json("file_events/", f"fileevents-page-{pages}", data) pages += 1 next_token = ( data.get("nextPgToken") or data.get("next_page_token") or (data.get("file_events") or {}).get("nextPgToken") ) if not next_token: break return pages def handler(event, context): hdrs = auth_header() report = {} if "users" in STREAMS: report["users_pages"] = pull_users(hdrs) if "sessions" in STREAMS: report["sessions_pages"] = pull_sessions(hdrs) if "audit" in STREAMS: report["audit_pages"] = pull_audit(hdrs) if "cases" in STREAMS: report["cases_pages"] = pull_cases(hdrs) if "file_events" in STREAMS: report["file_events_pages"] = pull_file_events(hdrs) return report def lambda_handler(event, context): return handler(event, context)
Cliquez sur Déployer.
Créer une programmation EventBridge
- Dans la console AWS, accédez à Amazon EventBridge > Règles.
- Cliquez sur Créer une règle.
- Fournissez les informations de configuration suivantes :
- Schéma de programmation : sélectionnez Taux fixe de
1
heure. - Name (Nom) : saisissez un nom unique et pertinent (par exemple,
code42-incydr-hourly
). - Cible : sélectionnez Fonction Lambda, puis choisissez
code42-incydr-pull
.
- Schéma de programmation : sélectionnez Taux fixe de
- Cliquez sur Créer une règle.
Facultatif : Créez un utilisateur et des clés IAM en lecture seule pour Google SecOps
- Dans la console AWS, accédez à IAM> Utilisateurs, puis cliquez sur Ajouter des utilisateurs.
- Fournissez les informations de configuration suivantes :
- Utilisateur : saisissez un nom unique (par exemple,
secops-reader
). - Type d'accès : sélectionnez Clé d'accès – Accès programmatique.
- Cliquez sur Créer un utilisateur.
- Utilisateur : saisissez un nom unique (par exemple,
- Associez une règle de lecture minimale (personnalisée) : Utilisateurs> sélectionnez
secops-reader
> Autorisations> Ajouter des autorisations> Associer des règles directement> Créer une règle Dans l'éditeur JSON, saisissez la stratégie suivante :
{ "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>" } ] }
Définissez le nom sur
secops-reader-policy
.Accédez à Créer une règle > recherchez/sélectionnez > Suivant > Ajouter des autorisations.
Accédez à Identifiants de sécurité > Clés d'accès > Créer une clé d'accès.
Téléchargez le CSV (ces valeurs sont saisies dans le flux).
Configurer un flux dans Google SecOps pour ingérer le journal Code42 Incydr
- Accédez à Paramètres SIEM> Flux.
- Cliquez sur Add New Feed (Ajouter un flux).
- Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple,
Code42 Incydr Datasets
). - Sélectionnez Amazon S3 V2 comme type de source.
- Sélectionnez Code42 Incydr comme type de journal.
- Cliquez sur Suivant.
- Spécifiez les valeurs des paramètres d'entrée suivants :
- URI S3 :
s3://code42-incydr/code42/
- Options de suppression de la source : sélectionnez l'option de suppression de votre choix.
- Âge maximal des fichiers : 180 jours par défaut.
- ID de clé d'accès : clé d'accès utilisateur ayant accès au bucket S3.
- Clé d'accès secrète : clé secrète de l'utilisateur ayant accès au bucket S3.
- Espace de noms de l'élément : espace de noms de l'élément.
- Libellés d'ingestion : libellé à appliquer aux événements de ce flux.
- URI S3 :
- Cliquez sur Suivant.
- Vérifiez la configuration de votre nouveau flux sur l'écran Finaliser, puis cliquez sur Envoyer.
Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.