Recoger registros de Atlassian Confluence
En este documento se explica cómo ingerir registros de Atlassian Confluence en Google Security Operations. El analizador primero intenta extraer campos del mensaje de registro sin procesar mediante expresiones regulares (patrones grok) diseñadas para los registros de Atlassian Confluence. Si el análisis de grok falla 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 UDM de Google SecOps y se enriquecen con contexto adicional.
Antes de empezar
Asegúrate de que cumples los siguientes requisitos previos:
- Una instancia de Google SecOps
- Cuenta de Atlassian Confluence Cloud con acceso al registro de auditoría O Confluence Data Center o Server con acceso de administrador
- En el caso de los métodos basados en AWS, acceso privilegiado a AWS (S3, IAM, Lambda y EventBridge)
- En el caso del método Bindplane, se necesita un host Windows 2016 o posterior, o un host Linux con
systemd.
Descripción general de las opciones de integración
En esta guía se describen dos formas de integrar la API:
- Opción 1: Confluence Data Center o Server a través de BindPlane + Syslog
- Opción 2: Registros de auditoría de Confluence Cloud a través de AWS Lambda y S3 (formato JSON)
Elige la opción que mejor se adapte a tu tipo de implementación e 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.
Obtener el archivo de autenticación de ingestión de Google SecOps
- Inicia sesión en la consola de Google SecOps.
- Ve a Configuración de SIEM > Agentes de recogida.
- Descarga el archivo de autenticación de ingestión. Guarda el archivo de forma segura en el sistema en el que se instalará Bindplane.
Obtener el ID de cliente de Google SecOps
- Inicia sesión en 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.
Instalar el agente de Bindplane
Instala el agente Bindplane en tu sistema operativo Windows o Linux siguiendo las instrucciones que se indican a continuación.
Instalación de ventanas
- Abre la petición de comando o PowerShell como administrador.
Ejecuta el siguiente comando:
msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
Instalación de Linux
- Abre un terminal con privilegios de root o sudo.
Ejecuta el siguiente comando:
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 ver otras opciones de instalación, consulta esta guía de instalación.
Configurar el agente de Bindplane para ingerir Syslog y enviarlo a Google SecOps
Accede al archivo de configuración:
- Busca el archivo
config.yaml. Normalmente, 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).
- Busca 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- Sustituye el puerto y la dirección IP según sea necesario en tu infraestructura.
- Sustituye
<YOUR_CUSTOMER_ID_HERE>por el ID de cliente real. - Actualiza
/path/to/ingestion-authentication-file.jsona la ruta donde se guardó el archivo de autenticación en la sección Obtener el archivo de autenticación de ingestión 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 Servicios o introducir el siguiente comando:
net stop BindPlaneAgent && net start BindPlaneAgent
Configurar el reenvío de Syslog en Confluence Data Center o Server
Opción A: Configurar Log4j SyslogAppender (recomendada)
- Inicia sesión en tu servidor de Confluence mediante SSH o RDP.
- Busca 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 añadir 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>- Sustituye
BINDPLANE_AGENT_IPpor la dirección IP de tu agente de BindPlane.
- Sustituye
Reinicia Confluence para aplicar los cambios:
sudo systemctl restart confluence
Opción B: Configurar rsyslog para reenviar archivos de registro locales
- Configura Confluence para que escriba los 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- Sustituye
BINDPLANE_AGENT_IPpor la dirección IP de tu agente de Bindplane. - Ajusta las rutas de los archivos de registro en función de tu instalación de Confluence:
- Los registros de aplicaciones suelen ser
<confluence-install>/logs/o<local-home>/logs/. - Registros de auditoría:
<confluence-home>/log/audit/*.json
- Los registros de aplicaciones suelen ser
- Sustituye
Reinicia rsyslog:
sudo systemctl restart rsyslog
Opción 2: Registros de auditoría de Confluence Cloud a través de AWS Lambda y S3
Recoger las credenciales de la API de Confluence Cloud
- Inicia sesión en tu cuenta de Atlassian.
- Ve a https://id.atlassian.com/manage-profile/security/api-tokens.
- Haz clic en Crear token de API.
- Introduce una etiqueta para el token (por ejemplo,
Google Security Operations Integration). - Haz clic en Crear.
- Copia y guarda el token de la 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 de tu cuenta de Atlassian (se usa para la autenticación).
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,
confluence-audit-logs). - 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 en 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 futuras consultas.
- 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 la política AmazonS3FullAccess.
- Selecciona la política.
- 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 > JSON tab.
Introduce 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" } ] }- Sustituye
confluence-audit-logssi has introducido otro nombre de segmento.
- Sustituye
Haz clic en Siguiente > Crear política.
Asigna un nombre a la política
ConfluenceAuditToS3Policy.Ve a IAM > Roles > Crear rol > Servicio de AWS > Lambda.
Adjunta la política que acabas de crear
ConfluenceAuditToS3Policy.Dale el nombre
ConfluenceAuditLambdaRoleal rol y haz clic en Crear rol.
Crear la función Lambda
- En la consola de AWS, ve a Lambda > Funciones.
- Haga clic en Crear función > Crear desde cero.
Proporciona los siguientes detalles de configuración:
Ajuste Valor Nombre ConfluenceAuditToS3Tiempo de ejecución Python 3.13 Arquitectura x86_64 Rol de ejecución ConfluenceAuditLambdaRoleUna vez creada la función, abra la pestaña Código, elimine el stub e introduzca 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]Vaya a Configuración > Variables de entorno.
Haz clic en Editar > Añadir nueva variable de entorno.
Introduce las siguientes variables de entorno y sustituye 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_RECORDS1000Seleccione 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).
- Proporcione los siguientes detalles de configuración:
- Programación periódica: Precio (
1 hour). - Destino: tu función Lambda
ConfluenceAuditToS3. - Nombre:
ConfluenceAuditToS3-1h.
- Programación periódica: Precio (
- Haz clic en Crear programación.
Opcional: Crear un usuario y claves de gestión de identidades y accesos de solo lectura para Google SecOps
- Ve a Consola de AWS > IAM > Usuarios.
- Haz clic en Add users (Añadir usuarios).
- Proporcione los siguientes detalles de configuración:
- Usuario: introduce
secops-confluence-reader. - Tipo de acceso: selecciona Clave de acceso – Acceso programático.
- Usuario: introduce
- Haz clic en Siguiente.
- Haz clic en Adjuntar 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:::confluence-audit-logs/*" }, { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::confluence-audit-logs" } ] }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 Confluence
- 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,
Confluence Cloud Audit Logs). - Selecciona Amazon S3 V2 como Tipo de fuente.
- Selecciona Atlassian Confluence como Tipo de registro.
- Haz clic en Siguiente.
- Especifique valores para los siguientes parámetros de entrada:
- URI de S3:
s3://confluence-audit-logs/confluence-audit/ - Opciones de eliminación de la fuente: selecciona la opción de eliminación que prefieras.
- Antigüedad máxima del archivo: incluye los archivos modificados en los últimos días. El valor predeterminado es de 180 días.
- 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 segmento de S3.
- Espacio de nombres de recursos: el espacio de nombres de recursos.
- Etiquetas de ingestión: la etiqueta aplicada a los eventos de este feed.
- URI de S3:
- Haz clic en Siguiente.
- Revise la nueva configuración del feed en la pantalla Finalizar y, a continuación, haga 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 "agent". |
| app_protocol | read_only_udm.network.application_protocol | Derivado del campo "app_protocol". Si "app_protocol" contiene "HTTPS", "HTTP", "SSH" o "RDP", se utiliza el protocolo correspondiente. De lo contrario, el valor predeterminado es "UNKNOWN_APPLICATION_PROTOCOL". |
| app_protocol | read_only_udm.network.application_protocol_version | Valor tomado del campo "app_protocol". |
| auditType.action | read_only_udm.security_result.action | Derivado del campo "auditType.action". Si "auditType.action" contiene "successful", el valor se define como "ALLOW". Si contiene "restricted", el valor se define como "BLOCK". |
| auditType.action | read_only_udm.security_result.summary | Valor tomado 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 tomado del campo "auditType.actionI18nKey" cuando "auditType" no está vacío. |
| auditType.area | read_only_udm.security_result.detection_fields.value | Valor tomado del campo "auditType.area" y asignado al campo "value" de un campo de detección con el campo "key" definido como "auditType area". Esta asignación se realiza cuando "auditType" no está vacío. |
| auditType.category | read_only_udm.security_result.category_details | Valor tomado 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" definido como "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" definido como "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 | Valor tomado del campo "author.externalCollaborator" y asignado al campo "value" de una etiqueta con el campo "key" definido como "externalCollaborator". |
| author.id | read_only_udm.principal.user.userid | Valor tomado 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 | Valor tomado del campo "author.isExternalCollaborator" y asignado al campo "value" de una etiqueta con el campo "key" definido como "isExternalCollaborator". |
| author.name | read_only_udm.principal.user.user_display_name | Valor tomado 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 "category". |
| 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 de la matriz "changedValues". |
| fecha de creación | 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 | Recorre cada elemento de "extraAttributes" y crea etiquetas con claves basadas en los campos "name" y "nameI18nKey", y valores del campo "value" correspondiente. |
| http_verb | read_only_udm.network.http.method | Valor tomado 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" y analizado como una dirección IP. |
| response_code | read_only_udm.network.http.response_code | Valor tomado 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" definido como "Session Duration". |
| fuente | 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 tomado 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 | Valor tomado del campo "sysAdmin" y asignado al campo "value" de una etiqueta con el campo "key" definido como "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" definido como "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 comprobaciones y, de forma predeterminada, es "GENERIC_EVENT". Se asignan valores específicos, como "NETWORK_HTTP", "USER_UNCATEGORIZED" o "STATUS_UPDATE", en función de la presencia y el contenido de otros campos, como "principal_host", "user_id", "has_principal" y "author.type". | |
| read_only_udm.metadata.vendor_name | Selecciona "ATLASSIAN". | |
| read_only_udm.metadata.product_name | Asigna el valor "CONFLUENCE". | |
| read_only_udm.metadata.log_type | Asigna el valor "ATLASSIAN_CONFLUENCE". | |
| read_only_udm.principal.user.user_display_name | El valor de este campo puede proceder de "author.displayName" o de "affectedObject.name", en función del contexto. | |
| read_only_udm.target.process.pid | El valor de este campo puede proceder de "principal_host" o de "pid", según el contexto. | |
| read_only_udm.principal.resource.attribute.labels | Este campo se rellena 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 en función del contenido específico de estos campos. |
¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.