Recopila registros de Atlassian Confluence
En este documento, se explica cómo transferir registros de Atlassian Confluence a Google Security Operations. Primero, el analizador intenta extraer campos del mensaje de registro sin procesar con expresiones regulares (patrones de Grok) diseñadas para los registros de Atlassian Confluence. Si falla el análisis de grok o el registro está en formato JSON, el código intenta analizar el mensaje como JSON. Por último, los campos extraídos se asignan al esquema de UDM de Google SecOps y se enriquecen con contexto adicional.
Antes de comenzar
Asegúrate de cumplir con los siguientes requisitos previos:
- Una instancia de Google SecOps
- Cuenta de Atlassian Confluence Cloud con acceso a los registros de auditoría O Confluence Data Center/Server con acceso de administrador
- Para los métodos basados en AWS: Acceso con privilegios a AWS (S3, IAM, Lambda, EventBridge)
- Para el método de Bindplane: Host de Windows 2016 o posterior, o de Linux con
systemd
Descripción general de las opciones de integración
En esta guía, se proporcionan dos rutas de integración:
- Opción 1: Confluence Data Center o Server a través de BindPlane y Syslog
- Opción 2: Registros de auditoría de Confluence Cloud a través de AWS Lambda + S3 (formato JSON)
Elige la opción que mejor se adapte a tu tipo de implementación y a tu infraestructura de Confluence.
Opción 1: Confluence Data Center o Server a través de Bindplane y Syslog
Esta opción configura Confluence Data Center o Server para que envíe registros a través de syslog a un agente de Bindplane, que luego los reenvía a Google SecOps.
Obtén el archivo de autenticación de transferencia de Google SecOps
- Accede a la consola de Google SecOps.
- Ve a Configuración de SIEM > Agentes de recopilación.
- Descarga el archivo de autenticación de transferencia. Guarda el archivo de forma segura en el sistema en el que se instalará BindPlane.
Obtén el ID de cliente de Google SecOps
- Accede a la consola de Google SecOps.
- Ve a Configuración de SIEM > Perfil.
- Copia y guarda el ID de cliente de la sección Detalles de la organización.
Instala el agente de BindPlane
Instala el agente de Bindplane en tu sistema operativo Windows o Linux según las siguientes instrucciones.
Instalación en Windows
- Abre el símbolo del sistema o PowerShell como administrador.
Ejecuta el comando siguiente:
msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
Instalación en Linux
- Abre una terminal con privilegios de raíz o sudo.
Ejecuta el comando siguiente:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
Recursos de instalación adicionales
- Para obtener más opciones de instalación, consulta esta guía de instalación.
Configura el agente de BindPlane para transferir Syslog y enviarlo a Google SecOps
Accede al archivo de configuración:
- Ubica el archivo
config.yaml. Por lo general, se encuentra en el directorio/etc/bindplane-agent/en Linux o en el directorio de instalación en Windows. - Abre el archivo con un editor de texto (por ejemplo,
nano,vio Bloc de notas).
- Ubica el archivo
Edita el archivo
config.yamlde la siguiente manera:receivers: udplog: # Replace the port and IP address as required listen_address: "0.0.0.0:514" exporters: chronicle/chronicle_w_labels: compression: gzip # Adjust the path to the credentials file you downloaded creds_file_path: '/path/to/ingestion-authentication-file.json' # Replace with your actual customer ID customer_id: YOUR_CUSTOMER_ID endpoint: malachiteingestion-pa.googleapis.com log_type: 'ATLASSIAN_CONFLUENCE' raw_log_field: body ingestion_labels: service: pipelines: logs/confluence: receivers: - udplog exporters: - chronicle/chronicle_w_labels- Reemplaza el puerto y la dirección IP según sea necesario en tu infraestructura.
- Reemplaza
<YOUR_CUSTOMER_ID_HERE>por el ID de cliente real. - Actualiza
/path/to/ingestion-authentication-file.jsona la ruta de acceso en la que se guardó el archivo de autenticación en la sección Cómo obtener el archivo de autenticación de la transferencia de datos de Google SecOps.
Reinicia el agente de Bindplane para aplicar los cambios
Para reiniciar el agente de Bindplane en Linux, ejecuta el siguiente comando:
sudo systemctl restart bindplane-agentPara reiniciar el agente de Bindplane en Windows, puedes usar la consola de Servicios o ingresar el siguiente comando:
net stop BindPlaneAgent && net start BindPlaneAgent
Configura el reenvío de Syslog en Confluence Data Center o Server
Opción A: Configura Log4j SyslogAppender (recomendado)
- Accede a tu servidor de Confluence a través de SSH o RDP.
- Ubica el archivo de configuración de Log4j:
- Para Log4j2:
<confluence-install>/confluence/WEB-INF/classes/log4j2.xml
- Para Log4j2:
Edita el archivo de configuración para agregar un SyslogAppender:
<Configuration> <Appenders> <!-- Existing appenders --> <Syslog name="SyslogAppender" host="BINDPLANE_AGENT_IP" port="514" protocol="UDP" facility="LOCAL0" format="RFC5424"> <PatternLayout pattern="%d{ISO8601} %p [%t] [%c{1}] %m%n"/> </Syslog> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="SyslogAppender"/> <!-- Other appender refs --> </Root> <!-- Audit logger --> <Logger name="com.atlassian.confluence.event.events.security.AuditEvent" level="info" additivity="false"> <AppenderRef ref="SyslogAppender"/> </Logger> </Loggers> </Configuration>- Reemplaza
BINDPLANE_AGENT_IPpor la dirección IP de tu agente de BindPlane.
- Reemplaza
Reinicia Confluence para aplicar los cambios:
sudo systemctl restart confluence
Opción B: Configura rsyslog para que reenvíe los archivos de registro locales
- Configura Confluence para que escriba registros en archivos (comportamiento predeterminado).
Instala rsyslog si no está presente:
sudo apt-get install rsyslog # Debian/Ubuntu sudo yum install rsyslog # RHEL/CentOSCrea el archivo de configuración de rsyslog
/etc/rsyslog.d/confluence.conf:# Forward Confluence logs to BindPlane $ModLoad imfile # Application logs $InputFileName /opt/atlassian/confluence/logs/atlassian-confluence.log $InputFileTag confluence-app: $InputFileStateFile stat-confluence-app $InputFileSeverity info $InputFileFacility local0 $InputRunFileMonitor # Audit logs (JSON format in DC/Server) $InputFileName /var/atlassian/application-data/confluence/log/audit/*.json $InputFileTag confluence-audit: $InputFileStateFile stat-confluence-audit $InputFileSeverity info $InputFileFacility local1 $InputRunFileMonitor # Forward to BindPlane agent *.* @@BINDPLANE_AGENT_IP:514- Reemplaza
BINDPLANE_AGENT_IPpor la dirección IP de tu agente de Bindplane. - Ajusta las rutas de acceso de los archivos de registro según tu instalación de Confluence:
- Por lo general, los registros de la aplicación son
<confluence-install>/logs/o<local-home>/logs/. - Registros de auditoría:
<confluence-home>/log/audit/*.json
- Por lo general, los registros de la aplicación son
- Reemplaza
Reinicia rsyslog:
sudo systemctl restart rsyslog
Opción 2: Registros de auditoría de Confluence Cloud a través de AWS Lambda y S3
Recopila credenciales de la API de Confluence Cloud
- Accede a tu cuenta de Atlassian.
- Ve a https://id.atlassian.com/manage-profile/security/api-tokens.
- Haz clic en Crear token de API.
- Ingresa una etiqueta para el token (por ejemplo,
Google Security Operations Integration). - Haz clic en Crear.
- Copia y guarda el token de API de forma segura.
- Anota la URL de tu sitio de Confluence Cloud (por ejemplo,
https://yoursite.atlassian.net). - Anota la dirección de correo electrónico de tu cuenta de Atlassian (que se usa para la autenticación).
Configura el bucket de AWS S3 y el IAM para Google SecOps
- Crea un bucket de Amazon S3 siguiendo esta guía del usuario: Crea un bucket
- Guarda el Nombre y la Región del bucket para futuras referencias (por ejemplo,
confluence-audit-logs). - Crea un usuario siguiendo esta guía del usuario: Cómo crear un usuario de IAM.
- Selecciona el usuario creado.
- Selecciona la pestaña Credenciales de seguridad.
- Haz clic en Crear clave de acceso en la sección Claves de acceso.
- Selecciona Servicio de terceros como Caso de uso.
- Haz clic en Siguiente.
- Opcional: Agrega 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 consultarlas en el futuro.
- Haz clic en Listo.
- Selecciona la pestaña Permisos.
- Haz clic en Agregar permisos en la sección Políticas de permisos.
- Selecciona Agregar permisos.
- Selecciona Adjuntar políticas directamente.
- Busca la política AmazonS3FullAccess.
- Selecciona la política.
- Haz clic en Siguiente.
- Haz clic en Agregar permisos.
Configura la política y el rol de IAM para las cargas de S3
- En la consola de AWS, ve a IAM > Policies > Create policy > pestaña JSON.
Ingresa la siguiente política:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPutObjects", "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::confluence-audit-logs/*" }, { "Sid": "AllowGetStateObject", "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::confluence-audit-logs/confluence-audit/state.json" } ] }- Reemplaza
confluence-audit-logssi ingresaste un nombre de bucket diferente.
- Reemplaza
Haz clic en Siguiente > Crear política.
Asigna a la política el nombre
ConfluenceAuditToS3Policy.Ve a IAM > Roles > Crear rol > Servicio de AWS > Lambda.
Adjunta la política recién creada
ConfluenceAuditToS3Policy.Nombra el rol
ConfluenceAuditLambdaRoley haz clic en Crear rol.
Crea la función Lambda
- En la consola de AWS, ve a Lambda > Functions.
- Haz clic en Crear función > Autor desde cero.
Proporciona los siguientes detalles de configuración:
Configuración Valor Nombre ConfluenceAuditToS3Tiempo de ejecución Python 3.13 Arquitectura x86_64 Rol de ejecución ConfluenceAuditLambdaRoleDespués de crear la función, abre la pestaña Code, borra el código auxiliar y, luego, ingresa el siguiente código:
import json import os import boto3 from datetime import datetime, timezone, timedelta from urllib import request, parse, error from base64 import b64encode # Environment variables S3_BUCKET = os.environ['S3_BUCKET'] S3_PREFIX = os.environ.get('S3_PREFIX', 'confluence-audit/') STATE_KEY = os.environ.get('STATE_KEY', 'confluence-audit/state.json') CONFLUENCE_URL = os.environ['CONFLUENCE_URL'] # e.g., https://yoursite.atlassian.net CONFLUENCE_EMAIL = os.environ['CONFLUENCE_EMAIL'] CONFLUENCE_API_TOKEN = os.environ['CONFLUENCE_API_TOKEN'] MAX_RECORDS = int(os.environ.get('MAX_RECORDS', '1000')) s3_client = boto3.client('s3') def lambda_handler(event, context): """Fetch Confluence Cloud audit logs and write to S3.""" # Read last execution state start_date = get_last_execution_time() end_date = datetime.now(timezone.utc) print(f"Fetching audit logs from {start_date} to {end_date}") # Fetch audit records records = fetch_audit_logs(start_date, end_date) if not records: print("No new audit records found.") save_state(end_date) return {'statusCode': 200, 'body': 'No new records'} # Write to S3 timestamp = end_date.strftime('%Y%m%d_%H%M%S') object_key = f"{S3_PREFIX}audit_{timestamp}.json" s3_client.put_object( Bucket=S3_BUCKET, Key=object_key, Body='\n'.join(json.dumps(record) for record in records), ContentType='application/json' ) print(f"Wrote {len(records)} records to s3://{S3_BUCKET}/{object_key}") # Update state save_state(end_date) return { 'statusCode': 200, 'body': f"Processed {len(records)} records" } def get_last_execution_time(): """Retrieve the last execution timestamp from S3 state file.""" try: response = s3_client.get_object(Bucket=S3_BUCKET, Key=STATE_KEY) state = json.loads(response['Body'].read()) return datetime.fromisoformat(state['last_execution']) except s3_client.exceptions.NoSuchKey: # First run: fetch logs from last 24 hours return datetime.now(timezone.utc) - timedelta(hours=24) except Exception as e: print(f"Error reading state: {e}") return datetime.now(timezone.utc) - timedelta(hours=24) def save_state(execution_time): """Save the execution timestamp to S3 state file.""" state = {'last_execution': execution_time.isoformat()} s3_client.put_object( Bucket=S3_BUCKET, Key=STATE_KEY, Body=json.dumps(state), ContentType='application/json' ) def fetch_audit_logs(start_date, end_date): """Fetch audit logs from Confluence Cloud REST API.""" records = [] start_param = int(start_date.timestamp() * 1000) # milliseconds end_param = int(end_date.timestamp() * 1000) # Build authentication header auth_string = f"{CONFLUENCE_EMAIL}:{CONFLUENCE_API_TOKEN}" auth_bytes = auth_string.encode('ascii') auth_b64 = b64encode(auth_bytes).decode('ascii') headers = { 'Authorization': f'Basic {auth_b64}', 'Accept': 'application/json' } # Confluence Cloud Audit API endpoint url = f"{CONFLUENCE_URL}/wiki/rest/api/audit?startDate={start_param}&endDate={end_param}&limit=1000" try: req = request.Request(url, headers=headers) with request.urlopen(req) as response: data = json.loads(response.read()) records = data.get('results', []) print(f"Retrieved {len(records)} audit records") except error.HTTPError as e: print(f"HTTP Error: {e.code} - {e.reason}") print(e.read().decode()) except Exception as e: print(f"Error fetching audit logs: {e}") return records[:MAX_RECORDS]Ve a Configuration > Environment variables.
Haz clic en Editar > Agregar nueva variable de entorno.
Ingresa las siguientes variables de entorno y reemplaza los valores por los tuyos.
Clave Valor de ejemplo S3_BUCKETconfluence-audit-logsS3_PREFIXconfluence-audit/STATE_KEYconfluence-audit/state.jsonCONFLUENCE_URLhttps://yoursite.atlassian.netCONFLUENCE_EMAILyour-email@example.comCONFLUENCE_API_TOKENyour-api-token-hereMAX_RECORDS1000Selecciona 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.
Crea una programación de EventBridge
- Ve a Amazon EventBridge > Scheduler > Create schedule.
- Proporciona los siguientes detalles de configuración:
- Programación recurrente: Frecuencia (
1 hour). - Destino: Tu función Lambda
ConfluenceAuditToS3. - Nombre:
ConfluenceAuditToS3-1h.
- Programación recurrente: Frecuencia (
- Haz clic en Crear programación.
Opcional: Crea un usuario y claves de IAM de solo lectura para Google SecOps
- Ve a Consola de AWS > IAM > Usuarios.
- Haz clic en Agregar usuarios.
- Proporciona los siguientes detalles de configuración:
- Usuario: Ingresa
secops-confluence-reader. - Tipo de acceso: Selecciona Clave de acceso: Acceso programático.
- Usuario: Ingresa
- Haz clic en Siguiente.
- Haz clic en Adjuntar políticas directamente > Crear política.
En el editor de JSON, ingresa la siguiente política:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::confluence-audit-logs/*" }, { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::confluence-audit-logs" } ] }Configura el nombre como
secops-reader-policy.Ve a Crear política > busca o selecciona > Siguiente > Agregar permisos.
Ve a Credenciales de seguridad > Claves de acceso > Crear clave de acceso.
Descarga el archivo CSV (estos valores se ingresan en el feed).
Configura un feed en Google SecOps para transferir registros de Confluence
- Ve a Configuración de SIEM > Feeds.
- Haz clic en Agregar feed nuevo.
- En el campo Nombre del feed, ingresa un nombre para el feed (por ejemplo,
Confluence Cloud Audit Logs). - Selecciona Amazon S3 V2 como el Tipo de fuente.
- Selecciona Atlassian Confluence como el Tipo de registro.
- Haz clic en Siguiente.
- Especifica valores para los siguientes parámetros de entrada:
- URI de S3:
s3://confluence-audit-logs/confluence-audit/ - Opciones de borrado de la fuente: Selecciona la opción de borrado según tu preferencia.
- Antigüedad máxima del archivo: Incluye los archivos modificados en la cantidad de días especificada. El valor predeterminado es de 180 días.
- ID de clave de acceso: Clave de acceso del usuario con acceso al bucket de S3.
- Clave de acceso secreta: Clave secreta del usuario con acceso al bucket de S3.
- Espacio de nombres del recurso: Es el espacio de nombres del recurso.
- Etiquetas de transmisión: Es la etiqueta que se aplica a los eventos de este feed.
- URI de S3:
- Haz clic en Siguiente.
- Revisa la nueva configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.
Tabla de asignación de UDM
| Campo de registro | Asignación de UDM | Lógica |
|---|---|---|
| agente | read_only_udm.network.http.user_agent | Valor tomado del campo "agente". |
| app_protocol | read_only_udm.network.application_protocol | Se deriva del campo "app_protocol". Si "app_protocol" contiene "HTTPS", "HTTP", "SSH" o "RDP", se usa el protocolo correspondiente. De lo contrario, el valor predeterminado es "UNKNOWN_APPLICATION_PROTOCOL". |
| app_protocol | read_only_udm.network.application_protocol_version | Es el valor que se toma del campo "app_protocol". |
| auditType.action | read_only_udm.security_result.action | Se deriva del campo "auditType.action". Si "auditType.action" contiene "successful", el valor se establece en "ALLOW". Si contiene "restricted", el valor se establece en "BLOCK". |
| auditType.action | read_only_udm.security_result.summary | Valor que se toma del campo "auditType.action" cuando "auditType" no está vacío y "auditType_area" es "SECURITY". |
| auditType.actionI18nKey | read_only_udm.metadata.product_event_type | Valor que se toma del campo "auditType.actionI18nKey" cuando "auditType" no está vacío. |
| auditType.area | read_only_udm.security_result.detection_fields.value | El valor se toma del campo "auditType.area" y se asigna al campo "value" de un campo de detección con el campo "key" establecido en "auditType area". Esta asignación se realiza cuando "auditType" no está vacío. |
| auditType.category | read_only_udm.security_result.category_details | Valor que se toma del campo "auditType.category" cuando "auditType" no está vacío. |
| auditType.categoryI18nKey | read_only_udm.security_result.detection_fields.value | Valor tomado del campo "auditType.categoryI18nKey" y asignado al campo "value" de un campo de detección con el campo "key" establecido en "auditType categoryI18nKey". Esta asignación se realiza cuando "auditType" no está vacío. |
| auditType.level | read_only_udm.security_result.detection_fields.value | Valor tomado del campo "auditType.level" y asignado al campo "value" de un campo de detección con el campo "key" establecido en "auditType level". Esta asignación se realiza cuando "auditType" no está vacío. |
| author.displayName | read_only_udm.principal.user.user_display_name | Valor tomado del campo "author.displayName". |
| author.externalCollaborator | read_only_udm.security_result.about.resource.attribute.labels.value | El valor se toma del campo "author.externalCollaborator" y se asigna al campo "value" de una etiqueta con el campo "key" establecido en "externalCollaborator". |
| author.id | read_only_udm.principal.user.userid | Valor que se toma del campo "author.id" cuando "author.type" es "user" y "principal_user_present" es "false". |
| author.isExternalCollaborator | read_only_udm.security_result.about.resource.attribute.labels.value | El valor se toma del campo "author.isExternalCollaborator" y se asigna al campo "value" de una etiqueta con el campo "key" establecido en "isExternalCollaborator". |
| author.name | read_only_udm.principal.user.user_display_name | El valor se toma del campo "author.name" cuando "author.type" es "user" y "principal_user_present" es "false". |
| bytes_in | read_only_udm.network.received_bytes | Valor tomado del campo "bytes_in" si contiene dígitos. De lo contrario, el valor predeterminado es 0. |
| category | read_only_udm.security_result.category_details | Valor tomado del campo "categoría". |
| changedValues | read_only_udm.principal.resource.attribute.labels | Itera por cada elemento de "changedValues" y crea etiquetas con claves como "changedValue[index][key]" y valores de los valores correspondientes en el array "changedValues". |
| creationDate | read_only_udm.metadata.event_timestamp | Valor tomado del campo "creationDate", analizado como marca de tiempo UNIX o UNIX_MS. |
| extraAttributes | read_only_udm.principal.resource.attribute.labels | Itera por cada elemento de "extraAttributes" y crea etiquetas con claves basadas en los campos "name" y "nameI18nKey", y los valores del campo "value" correspondiente. |
| http_verb | read_only_udm.network.http.method | Es el valor que se toma del campo "http_verb". |
| ip | read_only_udm.target.ip | Valor tomado del campo "ip". |
| principal_host | read_only_udm.principal.hostname | Valor tomado del campo "principal_host". |
| referral_url | read_only_udm.network.http.referral_url | Valor tomado del campo "referral_url". |
| remoteAddress | read_only_udm.principal.ip | Valor tomado del campo "remoteAddress", analizado como una dirección IP. |
| response_code | read_only_udm.network.http.response_code | Es el valor que se toma del campo "response_code". |
| session_duration | read_only_udm.additional.fields.value.string_value | Valor tomado del campo "session_duration" y asignado al campo "string_value" de una etiqueta con el campo "key" establecido en "Duración de la sesión". |
| source | read_only_udm.principal.ip | Valor tomado del campo "source" y analizado como una dirección IP. |
| src_ip | read_only_udm.principal.ip | Valor que se toma del campo "src_ip" si "remoteAddress" está vacío. |
| resumen | read_only_udm.security_result.summary | Valor tomado del campo "summary". |
| sysAdmin | read_only_udm.security_result.about.resource.attribute.labels.value | El valor se toma del campo "sysAdmin" y se asigna al campo "value" de una etiqueta con el campo "key" establecido en "sysAdmin". |
| superAdmin | read_only_udm.security_result.about.resource.attribute.labels.value | Valor tomado del campo "superAdmin" y asignado al campo "value" de una etiqueta con el campo "key" establecido en "superAdmin". |
| target_url | read_only_udm.target.url | Valor tomado del campo "target_url". |
| timestamp | read_only_udm.metadata.event_timestamp | Valor tomado del campo "timestamp", analizado como una cadena de fecha y hora. |
| user_id | read_only_udm.principal.user.userid | Valor tomado del campo "user_id". |
| read_only_udm.metadata.event_type | El valor de este campo se determina mediante una serie de verificaciones y, de forma predeterminada, se establece en "GENERIC_EVENT". Se establece en valores específicos, como "NETWORK_HTTP", "USER_UNCATEGORIZED" o "STATUS_UPDATE", según la presencia y el contenido de otros campos, como "principal_host", "user_id", "has_principal" y "author.type". | |
| read_only_udm.metadata.vendor_name | Se debe establecer en "ATLASSIAN". | |
| read_only_udm.metadata.product_name | Se establece en "CONFLUENCE". | |
| read_only_udm.metadata.log_type | Se debe establecer en "ATLASSIAN_CONFLUENCE". | |
| read_only_udm.principal.user.user_display_name | El valor de este campo puede provenir de "author.displayName" o "affectedObject.name", según el contexto. | |
| read_only_udm.target.process.pid | El valor de este campo puede provenir de "principal_host" o "pid", según el contexto. | |
| read_only_udm.principal.resource.attribute.labels | Este campo se propaga con varias etiquetas derivadas de campos como "affectedObjects", "changedValues" y "extraAttributes". Las claves y los valores de estas etiquetas se generan de forma dinámica según el contenido específico de estos campos. |
¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.