Recolha registos do Atlassian Confluence
Este documento explica como carregar registos do Atlassian Confluence para o Google Security Operations. O analisador tenta primeiro extrair campos da mensagem de registo não processada através de expressões regulares (padrões grok) concebidas para registos do Atlassian Confluence. Se a análise grok falhar ou o registo estiver no formato JSON, o código tenta analisar a mensagem como JSON. Por último, os campos extraídos são mapeados para o esquema UDM do Google SecOps e enriquecidos com contexto adicional.
Antes de começar
Certifique-se de que cumpre os seguintes pré-requisitos:
- Uma instância do Google SecOps
- Conta do Atlassian Confluence Cloud com acesso ao registo de auditoria OU Confluence Data Center/Server com acesso administrativo
- Para métodos baseados no AWS: acesso privilegiado ao AWS (S3, IAM, Lambda, EventBridge)
- Para o método Bindplane: Windows 2016 ou posterior, ou anfitrião Linux com
systemd
Vista geral das opções de integração
Este guia oferece dois caminhos de integração:
- Opção 1: Confluence Data Center/Server através do BindPlane + Syslog
- Opção 2: registos de auditoria do Confluence Cloud através do AWS Lambda + S3 (formato JSON)
Escolha a opção que melhor se adequa ao seu tipo de implementação e infraestrutura do Confluence.
Opção 1: Confluence Data Center/Server através do Bindplane + Syslog
Esta opção configura o Confluence Data Center ou o Server para enviar registos através do syslog para um agente do Bindplane, que os encaminha para o Google SecOps.
Obtenha o ficheiro de autenticação de carregamento do Google SecOps
- Inicie sessão na consola Google SecOps.
- Aceda a Definições do SIEM > Agentes de recolha.
- Transfira o ficheiro de autenticação de carregamento. Guarde o ficheiro de forma segura no sistema onde o Bindplane vai ser instalado.
Obtenha o ID de cliente do Google SecOps
- Inicie sessão na consola Google SecOps.
- Aceda a Definições do SIEM > Perfil.
- Copie e guarde o ID do cliente da secção Detalhes da organização.
Instale o agente do Bindplane
Instale o agente do Bindplane no seu sistema operativo Windows ou Linux de acordo com as seguintes instruções.
Instalação de janelas
- Abra a Linha de comandos ou o PowerShell como administrador.
Execute o seguinte comando:
msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
Instalação do Linux
- Abra um terminal com privilégios de raiz ou sudo.
Execute o seguinte comando:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
Recursos de instalação adicionais
- Para ver opções de instalação adicionais, consulte este guia de instalação.
Configure o agente Bindplane para carregar o Syslog e enviá-lo para o Google SecOps
Aceda ao ficheiro de configuração:
- Localize o ficheiro
config.yaml. Normalmente, encontra-se no diretório/etc/bindplane-agent/no Linux ou no diretório de instalação no Windows. - Abra o ficheiro com um editor de texto (por exemplo,
nano,viou Bloco de notas).
- Localize o ficheiro
Edite o ficheiro
config.yamlda seguinte forma: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- Substitua a porta e o endereço IP conforme necessário na sua infraestrutura.
- Substitua
<YOUR_CUSTOMER_ID_HERE>pelo ID de cliente real. - Atualize
/path/to/ingestion-authentication-file.jsonpara o caminho onde o ficheiro de autenticação foi guardado na secção Obtenha o ficheiro de autenticação de carregamento do Google SecOps.
Reinicie o agente do Bindplane para aplicar as alterações
Para reiniciar o agente do Bindplane no Linux, execute o seguinte comando:
sudo systemctl restart bindplane-agentPara reiniciar o agente Bindplane no Windows, pode usar a consola Serviços ou introduzir o seguinte comando:
net stop BindPlaneAgent && net start BindPlaneAgent
Configure o encaminhamento de Syslog no Confluence Data Center/Server
Opção A: configure o Log4j SyslogAppender (recomendado)
- Inicie sessão no seu servidor Confluence através de SSH ou RDP.
- Localize o ficheiro de configuração do Log4j:
- Para o Log4j2:
<confluence-install>/confluence/WEB-INF/classes/log4j2.xml
- Para o Log4j2:
Edite o ficheiro de configuração para adicionar um 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>- Substitua
BINDPLANE_AGENT_IPpelo endereço IP do seu agente do BindPlane.
- Substitua
Reinicie o Confluence para aplicar as alterações:
sudo systemctl restart confluence
Opção B: configure o rsyslog para encaminhar ficheiros de registo locais
- Configurar o Confluence para escrever registos em ficheiros (comportamento predefinido).
Instale o rsyslog se não estiver presente:
sudo apt-get install rsyslog # Debian/Ubuntu sudo yum install rsyslog # RHEL/CentOSCrie o ficheiro de configuração do 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- Substitua
BINDPLANE_AGENT_IPpelo endereço IP do seu agente do Bindplane. - Ajuste os caminhos dos ficheiros de registo com base na sua instalação do Confluence:
- Normalmente, os registos de aplicações:
<confluence-install>/logs/ou<local-home>/logs/ - Registos de auditoria:
<confluence-home>/log/audit/*.json
- Normalmente, os registos de aplicações:
- Substitua
Reinicie o rsyslog:
sudo systemctl restart rsyslog
Opção 2: registos de auditoria do Confluence Cloud através do AWS Lambda + S3
Recolha credenciais da API Confluence Cloud
- Inicie sessão na sua conta da Atlassian.
- Aceda a https://id.atlassian.com/manage-profile/security/api-tokens.
- Clique em Criar token de API.
- Introduza uma etiqueta para o token (por exemplo,
Google Security Operations Integration). - Clique em Criar.
- Copie e guarde a chave da API de forma segura.
- Tome nota do URL do seu site do Confluence Cloud (por exemplo,
https://yoursite.atlassian.net). - Tome nota do endereço de email da sua conta Atlassian (usado para autenticação).
Configure o contentor do AWS S3 e o IAM para o Google SecOps
- Crie um contentor do Amazon S3 seguindo este manual do utilizador: Criar um contentor
- Guarde o nome e a região do contentor para referência futura (por exemplo,
confluence-audit-logs). - Crie um utilizador seguindo este guia do utilizador: criar um utilizador do IAM.
- Selecione o utilizador criado.
- Selecione o separador Credenciais de segurança.
- Clique em Criar chave de acesso na secção Chaves de acesso.
- Selecione Serviço de terceiros como Exemplo de utilização.
- Clicar em Seguinte.
- Opcional: adicione uma etiqueta de descrição.
- Clique em Criar chave de acesso.
- Clique em Transferir ficheiro CSV para guardar a chave de acesso e a chave de acesso secreta para referência futura.
- Clique em Concluído.
- Selecione o separador Autorizações.
- Clique em Adicionar autorizações na secção Políticas de autorizações.
- Selecione Adicionar autorizações.
- Selecione Anexar políticas diretamente.
- Pesquise a política AmazonS3FullAccess.
- Selecione a política.
- Clicar em Seguinte.
- Clique em Adicionar autorizações.
Configure a política e a função de IAM para carregamentos do S3
- Na consola da AWS, aceda a IAM > Políticas > Criar política > separador JSON.
Introduza a seguinte 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" } ] }- Substitua
confluence-audit-logsse tiver introduzido um nome de contentor diferente.
- Substitua
Clique em Seguinte > Criar política.
Atribua um nome à política
ConfluenceAuditToS3Policy.Aceda a IAM > Funções > Criar função > Serviço AWS > Lambda.
Anexe a política criada recentemente
ConfluenceAuditToS3Policy.Dê o nome
ConfluenceAuditLambdaRoleà função e clique em Criar função.
Crie a função Lambda
- Na consola da AWS, aceda a Lambda > Functions.
- Clique em Criar função > Criar do zero.
Faculte os seguintes detalhes de configuração:
Definição Valor Nome ConfluenceAuditToS3Runtime Python 3.13 Arquitetura x86_64 Função de execução ConfluenceAuditLambdaRoleDepois de criar a função, abra o separador Código, elimine o fragmento de código e introduza o seguinte 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]Aceda a Configuração > Variáveis de ambiente.
Clique em Editar > Adicionar nova variável de ambiente.
Introduza as seguintes variáveis de ambiente, substituindo-as pelos seus valores.
Chave Exemplo de valor S3_BUCKETconfluence-audit-logsS3_PREFIXconfluence-audit/STATE_KEYconfluence-audit/state.jsonCONFLUENCE_URLhttps://yoursite.atlassian.netCONFLUENCE_EMAILyour-email@example.comCONFLUENCE_API_TOKENyour-api-token-hereMAX_RECORDS1000Selecione o separador Configuração.
No painel Configuração geral, clique em Editar.
Altere Tempo limite para 5 minutos (300 segundos) e clique em Guardar.
Crie um horário do EventBridge
- Aceda a Amazon EventBridge > Scheduler > Create schedule.
- Forneça os seguintes detalhes de configuração:
- Programação recorrente: Taxa (
1 hour). - Destino: a sua função Lambda
ConfluenceAuditToS3. - Nome:
ConfluenceAuditToS3-1h.
- Programação recorrente: Taxa (
- Clique em Criar horário.
Opcional: crie um utilizador e chaves da IAM só de leitura para o Google SecOps
- Aceda a AWS Console > IAM > Users.
- Clique em Adicionar utilizadores.
- Forneça os seguintes detalhes de configuração:
- Utilizador: introduza
secops-confluence-reader. - Tipo de acesso: selecione Chave de acesso – Acesso programático.
- Utilizador: introduza
- Clicar em Seguinte.
- Clique em Anexar políticas diretamente > Criar política.
No editor JSON, introduza a seguinte 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" } ] }Defina o nome como
secops-reader-policy.Aceda a Criar política > pesquise/selecione > Seguinte > Adicionar autorizações.
Aceda a Credenciais de segurança > Chaves de acesso > Criar chave de acesso.
Transfira o CSV (estes valores são introduzidos no feed).
Configure um feed no Google SecOps para carregar registos do Confluence
- Aceda a Definições do SIEM > Feeds.
- Clique em Adicionar novo feed.
- No campo Nome do feed, introduza um nome para o feed (por exemplo,
Confluence Cloud Audit Logs). - Selecione Amazon S3 V2 como o Tipo de origem.
- Selecione Atlassian Confluence como o Tipo de registo.
- Clicar em Seguinte.
- Especifique valores para os seguintes parâmetros de entrada:
- URI do S3:
s3://confluence-audit-logs/confluence-audit/ - Opções de eliminação de origens: selecione a opção de eliminação de acordo com a sua preferência.
- Idade máxima do ficheiro: inclua ficheiros modificados no último número de dias. A predefinição é 180 dias.
- ID da chave de acesso: chave de acesso do utilizador com acesso ao contentor do S3.
- Chave de acesso secreta: chave secreta do utilizador com acesso ao contentor do S3.
- Espaço de nomes do recurso: o espaço de nomes do recurso.
- Etiquetas de carregamento: a etiqueta aplicada aos eventos deste feed.
- URI do S3:
- Clicar em Seguinte.
- Reveja a nova configuração do feed no ecrã Finalizar e, de seguida, clique em Enviar.
Tabela de mapeamento da UDM
| Campo de registo | Mapeamento da UDM | Lógica |
|---|---|---|
| agente | read_only_udm.network.http.user_agent | Valor retirado do campo "agent". |
| app_protocol | read_only_udm.network.application_protocol | Derivado do campo "app_protocol". Se "app_protocol" contiver "HTTPS", "HTTP", "SSH" ou "RDP", é usado o protocolo correspondente. Caso contrário, a predefinição é "UNKNOWN_APPLICATION_PROTOCOL". |
| app_protocol | read_only_udm.network.application_protocol_version | Valor retirado do campo "app_protocol". |
| auditType.action | read_only_udm.security_result.action | Derivado do campo "auditType.action". Se "auditType.action" contiver "successful", o valor é definido como "ALLOW". Se contiver "restricted", o valor é definido como "BLOCK". |
| auditType.action | read_only_udm.security_result.summary | Valor retirado do campo "auditType.action" quando "auditType" não está vazio e "auditType_area" é "SECURITY". |
| auditType.actionI18nKey | read_only_udm.metadata.product_event_type | Valor retirado do campo "auditType.actionI18nKey" quando "auditType" não está vazio. |
| auditType.area | read_only_udm.security_result.detection_fields.value | Valor retirado do campo "auditType.area" e atribuído ao campo "value" de um campo de deteção com o campo "key" definido como "auditType area". Este mapeamento é feito quando "auditType" não está vazio. |
| auditType.category | read_only_udm.security_result.category_details | Valor retirado do campo "auditType.category" quando "auditType" não está vazio. |
| auditType.categoryI18nKey | read_only_udm.security_result.detection_fields.value | Valor retirado do campo "auditType.categoryI18nKey" e atribuído ao campo "value" de um campo de deteção com o campo "key" definido como "auditType categoryI18nKey". Este mapeamento é feito quando "auditType" não está vazio. |
| auditType.level | read_only_udm.security_result.detection_fields.value | Valor retirado do campo "auditType.level" e atribuído ao campo "value" de um campo de deteção com o campo "key" definido como "auditType level". Este mapeamento é feito quando "auditType" não está vazio. |
| author.displayName | read_only_udm.principal.user.user_display_name | Valor retirado do campo "author.displayName". |
| author.externalCollaborator | read_only_udm.security_result.about.resource.attribute.labels.value | Valor retirado do campo "author.externalCollaborator" e atribuído ao campo "value" de uma etiqueta com o campo "key" definido como "externalCollaborator". |
| author.id | read_only_udm.principal.user.userid | Valor retirado do campo "author.id" quando "author.type" é "user" e "principal_user_present" é "false". |
| author.isExternalCollaborator | read_only_udm.security_result.about.resource.attribute.labels.value | O valor é retirado do campo "author.isExternalCollaborator" e atribuído ao campo "value" de uma etiqueta com o campo "key" definido como "isExternalCollaborator". |
| author.name | read_only_udm.principal.user.user_display_name | Valor retirado do campo "author.name" quando "author.type" é "user" e "principal_user_present" é "false". |
| bytes_in | read_only_udm.network.received_bytes | Valor retirado do campo "bytes_in" se contiver dígitos. Caso contrário, a predefinição é 0. |
| categoria | read_only_udm.security_result.category_details | Valor retirado do campo "category". |
| changedValues | read_only_udm.principal.resource.attribute.labels | Itera cada elemento em "changedValues" e cria etiquetas com chaves como "changedValue[index][key]" e valores dos valores correspondentes na matriz "changedValues". |
| creationDate | read_only_udm.metadata.event_timestamp | Valor retirado do campo "creationDate", analisado como data/hora UNIX ou UNIX_MS. |
| extraAttributes | read_only_udm.principal.resource.attribute.labels | Itera cada elemento em "extraAttributes" e cria etiquetas com chaves baseadas nos campos "name" e "nameI18nKey" e nos valores do campo "value" correspondente. |
| http_verb | read_only_udm.network.http.method | Valor retirado do campo "http_verb". |
| ip | read_only_udm.target.ip | Valor retirado do campo "ip". |
| principal_host | read_only_udm.principal.hostname | Valor retirado do campo "principal_host". |
| referral_url | read_only_udm.network.http.referral_url | Valor retirado do campo "referral_url". |
| remoteAddress | read_only_udm.principal.ip | Valor retirado do campo "remoteAddress", analisado como um endereço IP. |
| response_code | read_only_udm.network.http.response_code | Valor retirado do campo "response_code". |
| session_duration | read_only_udm.additional.fields.value.string_value | Valor retirado do campo "session_duration" e atribuído ao campo "string_value" de uma etiqueta com o campo "key" definido como "Duração da sessão". |
| fonte | read_only_udm.principal.ip | Valor retirado do campo "source", analisado como um endereço IP. |
| src_ip | read_only_udm.principal.ip | Valor retirado do campo "src_ip" se "remoteAddress" estiver vazio. |
| resumo | read_only_udm.security_result.summary | Valor retirado do campo "summary". |
| sysAdmin | read_only_udm.security_result.about.resource.attribute.labels.value | Valor retirado do campo "sysAdmin" e atribuído ao campo "value" de uma etiqueta com o campo "key" definido como "sysAdmin". |
| superAdmin | read_only_udm.security_result.about.resource.attribute.labels.value | Valor retirado do campo "superAdmin" e atribuído ao campo "value" de uma etiqueta com o campo "key" definido como "superAdmin". |
| target_url | read_only_udm.target.url | Valor retirado do campo "target_url". |
| timestamp | read_only_udm.metadata.event_timestamp | Valor retirado do campo "timestamp", analisado como uma string de data e hora. |
| user_id | read_only_udm.principal.user.userid | Valor retirado do campo "user_id". |
| read_only_udm.metadata.event_type | O valor deste campo é determinado por uma série de verificações e é predefinido como "GENERIC_EVENT". Está definido para valores específicos, como "NETWORK_HTTP", "USER_UNCATEGORIZED" ou "STATUS_UPDATE", com base na presença e no conteúdo de outros campos, como "principal_host", "user_id", "has_principal" e "author.type". | |
| read_only_udm.metadata.vendor_name | Definido como "ATLASSIAN". | |
| read_only_udm.metadata.product_name | Definido como "CONFLUENCE". | |
| read_only_udm.metadata.log_type | Definido como "ATLASSIAN_CONFLUENCE". | |
| read_only_udm.principal.user.user_display_name | O valor deste campo pode ser proveniente de "author.displayName" ou "affectedObject.name", consoante o contexto. | |
| read_only_udm.target.process.pid | O valor deste campo pode vir de "principal_host" ou "pid", consoante o contexto. | |
| read_only_udm.principal.resource.attribute.labels | Este campo é preenchido com várias etiquetas derivadas de campos como "affectedObjects", "changedValues" e "extraAttributes". As chaves e os valores destas etiquetas são gerados dinamicamente com base no conteúdo específico destes campos. |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais da Google SecOps.