收集 Atlassian Confluence 日志

支持的平台:

本文档介绍了如何将 Atlassian Confluence 日志注入到 Google Security Operations。解析器首先尝试使用专为 Atlassian Confluence 日志设计的正则表达式(Grok 模式)从原始日志消息中提取字段。如果 grok 解析失败或日志采用 JSON 格式,则代码会尝试将消息解析为 JSON。最后,提取的字段会映射到 Google SecOps UDM 架构,并添加更多上下文信息。

准备工作

请确保满足以下前提条件:

  • Google SecOps 实例
  • 具有审核日志访问权限的 Atlassian Confluence Cloud 账号,或者具有管理员权限的 Confluence Data Center/Server 账号
  • 对于基于 AWS 的方法:对 AWS(S3、IAM、Lambda、EventBridge)的特权访问权限
  • 对于 Bindplane 方法:Windows 2016 或更高版本,或者具有 systemd 的 Linux 主机

集成选项概览

本指南提供了两种集成途径:

  • 方法 1:通过 BindPlane + Syslog 监控 Confluence Data Center/Server
  • 选项 2:通过 AWS Lambda + S3 获取 Confluence Cloud 审核日志(JSON 格式)

请选择最适合您的 Confluence 部署类型和基础架构的选项。

选项 1:通过 Bindplane + Syslog 监控 Confluence Data Center/Server

此选项用于将 Confluence Data Center 或 Server 配置为通过 syslog 将日志发送到 Bindplane 代理,然后由该代理将日志转发到 Google SecOps。

获取 Google SecOps 注入身份验证文件

  1. 登录 Google SecOps 控制台。
  2. 依次前往 SIEM 设置 > 收集代理
  3. 下载注入身份验证文件。将文件安全地保存在将要安装 Bindplane 的系统上。

获取 Google SecOps 客户 ID

  1. 登录 Google SecOps 控制台。
  2. 依次前往 SIEM 设置 > 个人资料
  3. 复制并保存组织详细信息部分中的客户 ID

安装 Bindplane 代理

按照以下说明在 Windows 或 Linux 操作系统上安装 Bindplane 代理。

Windows 安装

  1. 以管理员身份打开命令提示符PowerShell
  2. 运行以下命令:

    msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
    

Linux 安装

  1. 打开具有 root 或 sudo 权限的终端。
  2. 运行以下命令:

    sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
    

其他安装资源

  • 如需了解其他安装选项,请参阅此安装指南

配置 Bindplane 代理以注入 Syslog 并将其发送到 Google SecOps

  1. 访问配置文件:

    1. 找到 config.yaml 文件。通常,它位于 Linux 上的 /etc/bindplane-agent/ 目录中或 Windows 上的安装目录中。
    2. 使用文本编辑器(例如 nanovi 或记事本)打开该文件。
  2. 按如下方式修改 config.yaml 文件:

    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
    
    • 根据基础架构的需要替换端口和 IP 地址。
    • <YOUR_CUSTOMER_ID_HERE> 替换为实际的客户 ID。
    • /path/to/ingestion-authentication-file.json 更新为获取 Google SecOps 注入身份验证文件部分中保存身份验证文件的路径。

重启 Bindplane 代理以应用更改

  • 如需在 Linux 中重启 Bindplane 代理,请运行以下命令:

    sudo systemctl restart bindplane-agent
    
  • 如需在 Windows 中重启 Bindplane 代理,您可以使用服务控制台,也可以输入以下命令:

    net stop BindPlaneAgent && net start BindPlaneAgent
    

在 Confluence Data Center/Server 上配置 Syslog 转发

  1. 通过 SSH 或 RDP 登录您的 Confluence 服务器。
  2. 找到 Log4j 配置文件:
    • 对于 Log4j2:<confluence-install>/confluence/WEB-INF/classes/log4j2.xml
  3. 修改配置文件以添加 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>
    
    • BINDPLANE_AGENT_IP 替换为 BindPlane 代理的 IP 地址。
  4. 重启 Confluence 以应用更改:

    sudo systemctl restart confluence
    

选项 B:将 rsyslog 配置为转发本地日志文件

  1. 将 Confluence 配置为将日志写入文件(默认行为)。
  2. 如果未安装 rsyslog,请进行安装:

    sudo apt-get install rsyslog  # Debian/Ubuntu
    sudo yum install rsyslog      # RHEL/CentOS
    
  3. 创建 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
    
    • BINDPLANE_AGENT_IP 替换为 Bindplane 代理的 IP 地址。
    • 根据您的 Confluence 安装情况调整日志文件路径:
      • 应用日志通常:<confluence-install>/logs/<local-home>/logs/
      • 审核日志:<confluence-home>/log/audit/*.json
  4. 重启 rsyslog:

    sudo systemctl restart rsyslog
    

选项 2:通过 AWS Lambda + S3 获取 Confluence Cloud 审核日志

收集 Confluence Cloud API 凭据

  1. 登录您的 Atlassian 账号
  2. 前往 https://id.atlassian.com/manage-profile/security/api-tokens
  3. 点击创建 API 令牌
  4. 为令牌输入标签(例如,Google Security Operations Integration)。
  5. 点击创建
  6. 复制并妥善保存 API 令牌。
  7. 记下您的 Confluence Cloud 网站网址(例如 https://yoursite.atlassian.net)。
  8. 记下您的 Atlassian 账号电子邮件地址(用于身份验证)。

为 Google SecOps 配置 AWS S3 存储桶和 IAM

  1. 按照以下用户指南创建 Amazon S3 存储桶创建存储桶
  2. 保存存储桶名称区域以供日后参考(例如 confluence-audit-logs)。
  3. 按照以下用户指南创建用户创建 IAM 用户
  4. 选择创建的用户
  5. 选择安全凭据标签页。
  6. 访问密钥部分中,点击创建访问密钥
  7. 选择第三方服务作为使用情形
  8. 点击下一步
  9. 可选:添加说明标记。
  10. 点击创建访问密钥
  11. 点击下载 CSV 文件,保存访问密钥不公开的访问密钥以供日后参考。
  12. 点击完成
  13. 选择权限标签页。
  14. 权限政策部分中,点击添加权限
  15. 选择添加权限
  16. 选择直接附加政策
  17. 搜索 AmazonS3FullAccess 政策。
  18. 选择相应政策。
  19. 点击下一步
  20. 点击添加权限

为 S3 上传配置 IAM 政策和角色

  1. 在 AWS 控制台中,依次前往 IAM > 政策 > 创建政策 > JSON 标签页
  2. 输入以下政策:

    {
      "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"
        }
      ]
    }
    
    • 如果您输入了其他存储桶名称,请替换 confluence-audit-logs
  3. 依次点击下一步 > 创建政策

  4. 将政策命名为 ConfluenceAuditToS3Policy

  5. 依次前往 IAM > 角色 > 创建角色 > AWS 服务 > Lambda

  6. 附加新创建的政策 ConfluenceAuditToS3Policy

  7. 将角色命名为 ConfluenceAuditLambdaRole,然后点击创建角色

创建 Lambda 函数

  1. AWS 控制台中,依次前往 Lambda > 函数
  2. 依次点击创建函数 > 从头开始创作
  3. 提供以下配置详细信息:

    设置
    名称 ConfluenceAuditToS3
    运行时 Python 3.13
    架构 x86_64
    执行角色 ConfluenceAuditLambdaRole
  4. 创建函数后,打开 Code 标签页,删除桩代码并输入以下代码:

    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]
    
  5. 依次前往配置 > 环境变量

  6. 依次点击修改 > 添加新的环境变量

  7. 输入以下环境变量,并将其替换为您的值。

    示例值
    S3_BUCKET confluence-audit-logs
    S3_PREFIX confluence-audit/
    STATE_KEY confluence-audit/state.json
    CONFLUENCE_URL https://yoursite.atlassian.net
    CONFLUENCE_EMAIL your-email@example.com
    CONFLUENCE_API_TOKEN your-api-token-here
    MAX_RECORDS 1000
  8. 选择配置标签页。

  9. 常规配置面板中,点击修改

  10. 超时更改为 5 分钟(300 秒),然后点击保存

创建 EventBridge 计划

  1. 依次前往 Amazon EventBridge > 调度器 > 创建调度
  2. 提供以下配置详细信息:
    • 周期性安排费率 (1 hour)。
    • 目标:您的 Lambda 函数 ConfluenceAuditToS3
    • 名称ConfluenceAuditToS3-1h
  3. 点击创建时间表

可选:为 Google SecOps 创建只读 IAM 用户和密钥

  1. 前往 AWS 控制台 > IAM > 用户
  2. 点击 Add users(添加用户)。
  3. 提供以下配置详细信息:
    • 用户:输入 secops-confluence-reader
    • 访问类型:选择访问密钥 - 以程序化方式访问
  4. 点击下一步
  5. 依次点击直接附加政策 > 创建政策
  6. 在 JSON 编辑器中,输入以下政策:

    {
      "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"
        }
      ]
    }
    
  7. 将名称设置为 secops-reader-policy

  8. 依次前往创建政策 > 搜索/选择 > 下一步 > 添加权限

  9. 依次前往安全凭据 > 访问密钥 > 创建访问密钥

  10. 下载 CSV(这些值会输入到 Feed 中)。

在 Google SecOps 中配置 Feed 以注入 Confluence 日志

  1. 依次前往 SIEM 设置 > Feed
  2. 点击添加新 Feed
  3. Feed 名称字段中,输入 Feed 的名称(例如 Confluence Cloud Audit Logs)。
  4. 选择 Amazon S3 V2 作为来源类型
  5. 选择 Atlassian Confluence 作为日志类型
  6. 点击下一步
  7. 为以下输入参数指定值:
    • S3 URIs3://confluence-audit-logs/confluence-audit/
    • 源删除选项:根据您的偏好选择删除选项。
    • 文件存在时间上限:包含在过去指定天数内修改的文件。默认值为 180 天。
    • 访问密钥 ID:有权访问 S3 存储桶的用户访问密钥。
    • 私有访问密钥:有权访问 S3 存储桶的用户私有密钥。
    • 资产命名空间资产命名空间
    • 注入标签:应用于此 Feed 中事件的标签。
  8. 点击下一步
  9. 最终确定界面中查看新的 Feed 配置,然后点击提交

UDM 映射表

日志字段 UDM 映射 逻辑
代理 read_only_udm.network.http.user_agent 从“agent”字段中获取的值。
app_protocol read_only_udm.network.application_protocol 派生自“app_protocol”字段。如果“app_protocol”包含“HTTPS”“HTTP”“SSH”或“RDP”,则使用相应协议。否则,默认值为“UNKNOWN_APPLICATION_PROTOCOL”。
app_protocol read_only_udm.network.application_protocol_version 值取自“app_protocol”字段。
auditType.action read_only_udm.security_result.action 派生自“auditType.action”字段。如果“auditType.action”包含“successful”,则该值设置为“ALLOW”。如果包含“restricted”,则将值设置为“BLOCK”。
auditType.action read_only_udm.security_result.summary 当“auditType”不为空且“auditType_area”为“SECURITY”时,从“auditType.action”字段中获取的值。
auditType.actionI18nKey read_only_udm.metadata.product_event_type 当“auditType”不为空时,从“auditType.actionI18nKey”字段中获取的值。
auditType.area read_only_udm.security_result.detection_fields.value 从“auditType.area”字段中获取值,并将其分配给检测字段的“value”字段,同时将“key”字段设置为“auditType area”。当“auditType”不为空时,系统会执行此映射。
auditType.category read_only_udm.security_result.category_details 当“auditType”不为空时,从“auditType.category”字段中获取的值。
auditType.categoryI18nKey read_only_udm.security_result.detection_fields.value 从“auditType.categoryI18nKey”字段中获取值,并将其分配给检测字段的“value”字段,同时将“key”字段设置为“auditType categoryI18nKey”。当“auditType”不为空时,系统会执行此映射。
auditType.level read_only_udm.security_result.detection_fields.value 从“auditType.level”字段中获取值,并将其分配给检测字段的“value”字段,其中“key”字段设置为“auditType level”。当“auditType”不为空时,系统会执行此映射。
author.displayName read_only_udm.principal.user.user_display_name 取自“author.displayName”字段的值。
author.externalCollaborator read_only_udm.security_result.about.resource.attribute.labels.value 从“author.externalCollaborator”字段中提取值,并将其分配给“key”字段设置为“externalCollaborator”的标签的“value”字段。
author.id read_only_udm.principal.user.userid 当“author.type”为“user”且“principal_user_present”为“false”时,从“author.id”字段中获取的值。
author.isExternalCollaborator read_only_udm.security_result.about.resource.attribute.labels.value 从“author.isExternalCollaborator”字段中提取值,并将其分配给“key”字段设置为“isExternalCollaborator”的标签的“value”字段。
author.name read_only_udm.principal.user.user_display_name 当“author.type”为“user”且“principal_user_present”为“false”时,从“author.name”字段中获取的值。
bytes_in read_only_udm.network.received_bytes 如果“bytes_in”字段包含数字,则取自该字段的值。否则,默认值为 0。
类别 read_only_udm.security_result.category_details 值取自“category”字段。
changedValues read_only_udm.principal.resource.attribute.labels 遍历“changedValues”中的每个元素,并创建具有“changedValue[index][key]”等键的标签,以及“changedValues”数组中相应的值。
创建日期 read_only_udm.metadata.event_timestamp 从“creationDate”字段中获取的值,解析为 UNIX 或 UNIX_MS 时间戳。
extraAttributes read_only_udm.principal.resource.attribute.labels 遍历“extraAttributes”中的每个元素,并根据“name”和“nameI18nKey”字段创建键,根据相应的“value”字段创建值。
http_verb read_only_udm.network.http.method 值取自“http_verb”字段。
ip read_only_udm.target.ip 从“ip”字段中获取的值。
principal_host read_only_udm.principal.hostname 从“principal_host”字段中获取的值。
referral_url read_only_udm.network.http.referral_url 从“referral_url”字段中获取的值。
remoteAddress read_only_udm.principal.ip 从“remoteAddress”字段中获取的值,解析为 IP 地址。
response_code read_only_udm.network.http.response_code 从“response_code”字段中获取的值。
session_duration read_only_udm.additional.fields.value.string_value 从“session_duration”字段中获取值,并将其分配给“key”字段设置为“Session Duration”的标签的“string_value”字段。
来源 read_only_udm.principal.ip 从“来源”字段中获取的值,解析为 IP 地址。
src_ip read_only_udm.principal.ip 如果“remoteAddress”为空,则取自“src_ip”字段的值。
摘要 read_only_udm.security_result.summary 值取自“摘要”字段。
sysAdmin read_only_udm.security_result.about.resource.attribute.labels.value 从“sysAdmin”字段中提取的值,并分配给“key”字段设置为“sysAdmin”的标签的“value”字段。
superAdmin read_only_udm.security_result.about.resource.attribute.labels.value 从“superAdmin”字段中获取值,并将其分配给“key”字段设置为“superAdmin”的标签的“value”字段。
target_url read_only_udm.target.url 从“target_url”字段中获取的值。
时间戳 read_only_udm.metadata.event_timestamp 从“时间戳”字段中获取的值,解析为日期和时间字符串。
user_id read_only_udm.principal.user.userid 值取自“user_id”字段。
read_only_udm.metadata.event_type 此字段的值由一系列检查确定,默认值为“GENERIC_EVENT”。系统会根据“principal_host”“user_id”“has_principal”和“author.type”等其他字段的存在情况和内容,将其设置为特定值,例如“NETWORK_HTTP”“USER_UNCATEGORIZED”或“STATUS_UPDATE”。
read_only_udm.metadata.vendor_name 设置为“ATLASSIAN”。
read_only_udm.metadata.product_name 设置为“CONFLUENCE”。
read_only_udm.metadata.log_type 设置为“ATLASSIAN_CONFLUENCE”。
read_only_udm.principal.user.user_display_name 此字段的值可能来自“author.displayName”或“affectedObject.name”,具体取决于上下文。
read_only_udm.target.process.pid 此字段的值可以来自“principal_host”或“pid”,具体取决于上下文。
read_only_udm.principal.resource.attribute.labels 此字段填充了从“affectedObjects”“changedValues”和“extraAttributes”等字段派生的各种标签。这些标签的键和值会根据这些字段的具体内容动态生成。

需要更多帮助?获得社区成员和 Google SecOps 专业人士的解答。