Recoger registros de auditoría de Harness IO
En este documento se explica cómo ingerir registros de auditoría de Harness IO en Google Security Operations mediante Amazon S3.
Antes de empezar
- Instancia de Google SecOps
- Acceso privilegiado a Harness (clave de API e ID de cuenta)
- Acceso privilegiado a AWS (S3, IAM, Lambda y EventBridge)
Obtener la clave de API y el ID de cuenta de Harness para una cuenta personal
- Inicia sesión en la interfaz de usuario web de Harness.
- Ve a tu Perfil de usuario > Mis claves de API.
- Selecciona Clave de API.
- Introduce un nombre para la clave de API.
- Haz clic en Guardar.
- Selecciona Token en la nueva clave de API.
- Introduce un nombre para el token.
- Haz clic en Generate Token (Generar token).
- Copia y guarda el token en un lugar seguro.
- Copia y guarda el valor de Account ID (ID de cuenta), que aparece en la URL de Harness y en Account Settings (Configuración de la cuenta).
Opcional: Obtener la clave de API y el ID de cuenta de Harness de una cuenta de servicio
- Inicia sesión en la interfaz de usuario web de Harness.
- Crear una cuenta de servicio
- Ve a Configuración de la cuenta > Control de acceso.
- Selecciona Cuentas de servicio > selecciona la cuenta de servicio para la que quieras crear una clave de API.
- En Claves de API, selecciona Clave de API.
- Introduce un nombre para la clave de API.
- Haz clic en Guardar.
- Selecciona Token en la nueva clave de API.
- Introduce un nombre para el token.
- Haz clic en Generate Token (Generar token).
- Copia y guarda el token en un lugar seguro.
- Copia y guarda el valor de Account ID (ID de cuenta), que aparece en la URL de Harness y en Account Settings (Configuración de la cuenta).
Configurar un segmento de AWS S3 y IAM para Google SecOps
- Crea un segmento de Amazon S3 siguiendo esta guía de usuario: Crear un segmento.
- Guarda el nombre y la región del segmento para consultarlos más adelante (por ejemplo,
harness-io
). - Crea un usuario siguiendo esta guía: Crear un usuario de gestión de identidades y accesos.
- Selecciona el Usuario creado.
- Selecciona la pestaña Credenciales de seguridad.
- En la sección Claves de acceso, haz clic en Crear clave de acceso.
- Selecciona Servicio de terceros como Caso práctico.
- Haz clic en Siguiente.
- Opcional: añade una etiqueta de descripción.
- Haz clic en Crear clave de acceso.
- Haz clic en Descargar archivo CSV para guardar la clave de acceso y la clave de acceso secreta para usarlas más adelante.
- Haz clic en Listo.
- Selecciona la pestaña Permisos.
- En la sección Políticas de permisos, haz clic en Añadir permisos.
- Selecciona Añadir permisos.
- Seleccione Adjuntar políticas directamente.
- Busca y selecciona la política AmazonS3FullAccess.
- Haz clic en Siguiente.
- Haz clic en Añadir permisos.
Configurar la política y el rol de gestión de identidades y accesos para las subidas de S3
- En la consola de AWS, ve a IAM > Policies > Create policy > pestaña JSON.
Introduce la siguiente política:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPutHarnessObjects", "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::harness-io/*" }, { "Sid": "AllowGetStateObject", "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::harness-io/harness/audit/state.json" } ] }
- Sustituye
harness-io
si has introducido otro nombre de segmento:
- Sustituye
Haz clic en Siguiente > Crear política.
Ve a IAM > Roles > Crear rol > Servicio de AWS > Lambda.
Adjunte la política que acaba de crear.
Dale el nombre
WriteHarnessToS3Role
al rol y haz clic en Crear rol.
Crear la función Lambda
- En la consola de AWS, ve a Lambda > Funciones > Crear función.
- Haz clic en Crear desde cero.
Proporciona los siguientes detalles de configuración:
Ajuste Valor Nombre harness_io_to_s3
Tiempo de ejecución Python 3.13 Arquitectura x86_64 Rol de ejecución WriteHarnessToS3Role
Una vez creada la función, abra la pestaña Código, elimine el stub e introduzca el siguiente código (
harness_io_to_s3.py
).#!/usr/bin/env python3 import os, json, time, urllib.parse from urllib.request import Request, urlopen from urllib.error import HTTPError, URLError import boto3 API_BASE = os.environ.get("HARNESS_API_BASE", "https://app.harness.io").rstrip("/") ACCOUNT_ID = os.environ["HARNESS_ACCOUNT_ID"] API_KEY = os.environ["HARNESS_API_KEY"] # x-api-key token BUCKET = os.environ["S3_BUCKET"] PREFIX = os.environ.get("S3_PREFIX", "harness/audit/").strip("/") STATE_KEY = os.environ.get("STATE_KEY", "harness/audit/state.json") PAGE_SIZE = min(int(os.environ.get("PAGE_SIZE", "100")), 100) # <=100 START_MINUTES_BACK = int(os.environ.get("START_MINUTES_BACK", "60")) s3 = boto3.client("s3") HDRS = {"x-api-key": API_KEY, "Content-Type": "application/json", "Accept": "application/json"} def _read_state(): try: obj = s3.get_object(Bucket=BUCKET, Key=STATE_KEY) j = json.loads(obj["Body"].read()) return j.get("since"), j.get("pageToken") except Exception: return None, None def _write_state(since_ms: int, page_token: str | None): body = json.dumps({"since": since_ms, "pageToken": page_token}).encode("utf-8") s3.put_object(Bucket=BUCKET, Key=STATE_KEY, Body=body, ContentType="application/json") def _http_post(path: str, body: dict, query: dict, timeout: int = 60, max_retries: int = 5) -> dict: qs = urllib.parse.urlencode(query) url = f"{API_BASE}{path}?{qs}" data = json.dumps(body).encode("utf-8") attempt, backoff = 0, 1.0 while True: req = Request(url, data=data, method="POST") for k, v in HDRS.items(): req.add_header(k, v) try: with urlopen(req, timeout=timeout) as r: return json.loads(r.read().decode("utf-8")) 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 _write_page(obj: dict, now: float, page_index: int) -> str: ts = time.strftime("%Y/%m/%d/%H%M%S", time.gmtime(now)) key = f"{PREFIX}/{ts}-page{page_index:05d}.json" s3.put_object( Bucket=BUCKET, Key=key, Body=json.dumps(obj, separators=(",", ":")).encode("utf-8"), ContentType="application/json", ) return key def fetch_and_store(): now_s = time.time() since_ms, page_token = _read_state() if since_ms is None: since_ms = int((now_s - START_MINUTES_BACK * 60) * 1000) until_ms = int(now_s * 1000) page_index = 0 total = 0 while True: body = {"startTime": since_ms, "endTime": until_ms} query = {"accountIdentifier": ACCOUNT_ID, "pageSize": PAGE_SIZE} if page_token: query["pageToken"] = page_token else: query["pageIndex"] = page_index data = _http_post("/audit/api/audits/listV2", body, query) _write_page(data, now_s, page_index) entries = [] for key in ("data", "content", "response", "resource", "resources", "items"): if isinstance(data.get(key), list): entries = data[key] break total += len(entries) if isinstance(entries, list) else 0 next_token = ( data.get("pageToken") or (isinstance(data.get("meta"), dict) and data["meta"].get("pageToken")) or (isinstance(data.get("metadata"), dict) and data["metadata"].get("pageToken")) ) if next_token: page_token = next_token page_index += 1 continue if len(entries) < PAGE_SIZE: break page_index += 1 _write_state(until_ms, None) return {"pages": page_index + 1, "objects_estimate": total} def lambda_handler(event=None, context=None): return fetch_and_store() if __name__ == "__main__": print(lambda_handler())
Ve a Configuración > Variables de entorno > Editar > Añadir nueva variable de entorno.
Introduce las siguientes variables de entorno y sustituye los valores por los tuyos:
Clave Ejemplo S3_BUCKET
harness-io
S3_PREFIX
harness/audit/
STATE_KEY
harness/audit/state.json
HARNESS_ACCOUNT_ID
123456789
HARNESS_API_KEY
harness_xxx_token
HARNESS_API_BASE
https://app.harness.io
PAGE_SIZE
100
START_MINUTES_BACK
60
Una vez creada la función, permanece en su página (o abre Lambda > Funciones > tu‑función).
Seleccione la pestaña Configuración.
En el panel Configuración general, haz clic en Editar.
Cambia Tiempo de espera a 5 minutos (300 segundos) y haz clic en Guardar.
Crear una programación de EventBridge
- Ve a Amazon EventBridge > Scheduler > Create schedule (Amazon EventBridge > Programador > Crear programación).
Proporciona los siguientes detalles de configuración:
- Programación periódica: Precio (
1 hour
). - Destino: tu función Lambda.
- Nombre:
harness-io-1h
.
- Programación periódica: Precio (
Haz clic en Crear programación.
Crear un usuario y claves de IAM de solo lectura para Google SecOps
- En la consola de AWS, vaya a IAM > Usuarios y, a continuación, haga clic en Añadir usuarios.
- Proporcione los siguientes detalles de configuración:
- Usuario: introduce un nombre único (por ejemplo,
secops-reader
). - Tipo de acceso: selecciona Clave de acceso - Acceso programático.
- Haz clic en Crear usuario.
- Usuario: introduce un nombre único (por ejemplo,
- Asigna una política de lectura mínima (personalizada): Usuarios > selecciona
secops-reader
> Permisos > Añadir permisos > Asignar políticas directamente > Crear política. En el editor de JSON, introduce la siguiente política:
{ "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>" } ] }
Asigna el nombre
secops-reader-policy
.Ve a Crear política > busca o selecciona > Siguiente > Añadir permisos.
Ve a Credenciales de seguridad > Claves de acceso > Crear clave de acceso.
Descarga el archivo CSV (estos valores se introducen en el feed).
Configurar un feed en Google SecOps para ingerir registros de Harness IO
- Ve a Configuración de SIEM > Feeds.
- Haz clic en Añadir feed.
- En el campo Nombre del feed, introduce un nombre para el feed (por ejemplo,
Harness IO
). - Selecciona Amazon S3 V2 como Tipo de fuente.
- Selecciona Harness IO como Tipo de registro.
- Haz clic en Siguiente.
- Especifique los valores de los siguientes parámetros de entrada:
- URI de S3:
s3://harness-io/harness/audit/
- Opciones de eliminación de la fuente: selecciona la opción de eliminación que prefieras.
- Antigüedad máxima de los archivos: 180 días de forma predeterminada.
- ID de clave de acceso: clave de acceso de usuario con acceso al bucket de S3.
- Clave de acceso secreta: clave secreta del usuario con acceso al bucket de S3.
- Espacio de nombres de recursos: el espacio de nombres de recursos.
- Etiquetas de ingestión: etiqueta que se aplicará a los eventos de este feed.
- URI de S3:
- Haz clic en Siguiente.
- Revise la configuración de la nueva fuente en la pantalla Finalizar y, a continuación, haga clic en Enviar.
¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.