收集 Oracle Cloud Infrastructure 审核日志

支持的平台:

本文档介绍了如何使用 Amazon S3 将 Oracle Cloud Infrastructure 审核日志注入到 Google Security Operations。

准备工作

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

  • Google SecOps 实例。
  • 具有创建和管理以下各项权限的 Oracle Cloud Infrastructure 账号:
    • Service Connector Hub
    • Oracle Functions
    • 保险柜和密钥
    • 动态群组和 IAM 政策
    • 日志记录
  • 具有以下权限的 AWS 账号:创建和管理:
    • S3 存储分区
    • IAM 用户和政策

创建 Amazon S3 存储桶

  1. 登录 AWS Management Console
  2. 依次前往 S3 > 创建存储桶
  3. 提供以下配置详细信息:
    • 存储分区名称:输入一个唯一名称(例如 oci-audit-logs-bucket)。
    • AWS 区域:选择一个区域(例如 us-east-1)。
    • 保留其他选项的默认设置。
  4. 点击创建存储分区
  5. 保存存储桶名称区域以备后用。

在 AWS 中为 OCI Functions 创建 IAM 用户

  1. 登录 AWS Management Console
  2. 依次前往 IAM > 用户 > 添加用户
  3. 提供以下配置详细信息:
    • 用户名:输入用户名(例如 oci-functions-s3-user)。
    • 访问权限类型:选择访问密钥 - 以程序化方式访问
  4. 点击 Next: Permissions
  5. 点击 Attach existing policies directly
  6. 搜索并选择 AmazonS3FullAccess 政策。
  7. 点击 Next: Tags
  8. 点击下一步:检查
  9. 点击创建用户
  10. 重要提示:在成功页面上,复制并保存以下凭据:
    • 访问密钥 ID
    • Secret 访问密钥

在 OCI Vault 中存储 AWS 凭据

为了安全地存储 AWS 凭据,您必须使用 Oracle Cloud Infrastructure Vault,而不是在函数代码中对其进行硬编码。

创建保险箱和主加密密钥

  1. 登录 Oracle Cloud 控制台
  2. 前往身份和安全 > 保险库
  3. 如果您没有保险库,请点击创建保险库
  4. 提供以下配置详细信息:
    • 在隔离区中创建:选择您的隔离区。
    • 名称:输入一个名称(例如 oci-functions-vault)。
  5. 点击创建保险库
  6. 创建保险柜后,点击保险柜名称即可将其打开。
  7. 主加密密钥下,点击创建密钥
  8. 提供以下配置详细信息:
    • 保护模式:软件
    • 名称:输入一个名称(例如 oci-functions-key)。
    • 密钥形状:算法:AES
    • 密钥形状:长度:256 位
  9. 点击创建密钥

为 AWS 凭据创建 Secret

  1. 在保管库中,点击 Secret 下的创建 Secret
  2. 为 AWS 访问密钥提供以下配置详细信息:
    • 在隔离区中创建:选择您的隔离区。
    • 名称aws-access-key
    • 说明:S3 的 AWS 访问密钥
    • 加密密钥:选择您创建的主加密密钥。
    • 密钥类型内容:纯文本
    • Secret Contents:粘贴您的 AWS 访问密钥 ID。
  3. 点击创建 Secret
  4. 复制并保存此密钥的 OCID(看起来像 ocid1.vaultsecret.oc1...)。
  5. 再次点击创建 Secret 以创建第二个 Secret。
  6. 为 AWS 密钥提供以下配置详细信息:
    • 在隔离区中创建:选择您的隔离区。
    • 名称aws-secret-key
    • 说明:S3 的 AWS Secret 密钥
    • 加密密钥:选择相同的主加密密钥。
    • Secret Type Contents:纯文本
    • Secret 内容:粘贴您的 AWS 私有访问密钥。
  7. 点击创建 Secret
  8. 复制并保存此密钥的 OCID

为 OCI Functions 创建动态群组

  1. 登录 Oracle Cloud 控制台
  2. 依次前往身份和安全 > 身份 > 动态群组
  3. 点击创建动态群组
  4. 提供以下配置详细信息:

    • 名称oci-functions-dynamic-group
    • 说明:用于 OCI 函数访问保险柜密钥的动态群组
    • 匹配规则:输入以下规则(将 <your_compartment_ocid> 替换为您的区间 OCID):

      ALL {resource.type = 'fnfunc', resource.compartment.id = '<your_compartment_ocid>'}
      
  5. 点击创建

创建用于保险柜访问权限的 IAM 政策

  1. 登录 Oracle Cloud 控制台
  2. 依次前往身份和安全 > 身份 > 政策
  3. 选择要在其中创建政策的区间。
  4. 点击创建政策
  5. 提供以下配置详细信息:

    • 名称oci-functions-vault-access-policy
    • 说明:允许 OCI Functions 从 Vault 读取 Secret
    • 政策生成器:切换显示手动编辑器
    • 政策语句:输入以下内容(将 <compartment_name> 替换为您的区间名称):

      allow dynamic-group oci-functions-dynamic-group to manage secret-family in compartment <compartment_name>
      
  6. 点击创建

创建 OCI 函数应用

  1. 登录 Oracle Cloud 控制台
  2. 依次前往开发者服务 > 应用(位于“功能”下方)
  3. 点击创建应用
  4. 提供以下配置详细信息:
    • 名称:输入一个名称(例如 oci-logs-to-s3-app)。
    • VCN:选择您所在隔离区中的 VCN。
    • 子网:选择一个或多个子网。
  5. 点击创建

创建和部署 OCI 函数

  1. Oracle Cloud 控制台中,点击右上角的 Cloud Shell 图标。
  2. 等待 Cloud Shell 完成初始化。

创建函数

  1. 在 Cloud Shell 中,为您的函数创建一个新目录:

    mkdir pushlogs
    cd pushlogs
    
  2. 初始化新的 Python 函数:

    fn init --runtime python
    
  3. 这会创建三个文件:func.pyfunc.yamlrequirements.txt

更新了 func.py

  • func.py 的内容替换为以下代码:

    import io
    import json
    import logging
    import boto3
    import oci
    import base64
    import os
    from fdk import response
    
    def handler(ctx, data: io.BytesIO = None):
        """
        OCI Function to push audit logs from OCI Logging to AWS S3
        """
        try:
            # Parse incoming log data from Service Connector
            funDataStr = data.read().decode('utf-8')
            funData = json.loads(funDataStr)
    
            logging.getLogger().info(f"Received {len(funData)} log entries")
    
            # Replace these with your actual OCI Vault secret OCIDs
            secret_key_id = "ocid1.vaultsecret.oc1..<your_secret_key_ocid>"
            access_key_id = "ocid1.vaultsecret.oc1..<your_access_key_ocid>"
    
            # Replace with your S3 bucket name
            s3_bucket_name = "oci-audit-logs-bucket"
    
            # Use Resource Principals for OCI authentication
            signer = oci.auth.signers.get_resource_principals_signer()
            secret_client = oci.secrets.SecretsClient({}, signer=signer)
    
            def read_secret_value(secret_client, secret_id):
                """Retrieve and decode secret value from OCI Vault"""
                response = secret_client.get_secret_bundle(secret_id)
                base64_secret_content = response.data.secret_bundle_content.content
                base64_secret_bytes = base64_secret_content.encode('ascii')
                base64_message_bytes = base64.b64decode(base64_secret_bytes)
                secret_content = base64_message_bytes.decode('ascii')
                return secret_content
    
            # Retrieve AWS credentials from OCI Vault
            awsaccesskey = read_secret_value(secret_client, access_key_id)
            awssecretkey = read_secret_value(secret_client, secret_key_id)
    
            # Initialize boto3 session with AWS credentials
            session = boto3.Session(
                aws_access_key_id=awsaccesskey,
                aws_secret_access_key=awssecretkey
            )
            s3 = session.resource('s3')
    
            # Process each log entry
            for i in range(0, len(funData)):
                # Use timestamp as filename
                filename = funData[i].get('time', f'log_{i}')
                # Remove special characters from filename
                filename = filename.replace(':', '-').replace('.', '-')
    
                logging.getLogger().info(f"Processing log entry: {filename}")
    
                # Write log entry to temporary file
                temp_file = f'/tmp/{filename}.json'
                with open(temp_file, 'w', encoding='utf-8') as f:
                    json.dump(funData[i], f, ensure_ascii=False, indent=4)
    
                # Upload to S3
                s3_key = f'{filename}.json'
                s3.meta.client.upload_file(
                    Filename=temp_file,
                    Bucket=s3_bucket_name,
                    Key=s3_key
                )
    
                logging.getLogger().info(f"Uploaded {s3_key} to S3 bucket {s3_bucket_name}")
    
                # Clean up temporary file
                os.remove(temp_file)
    
            return response.Response(
                ctx,
                response_data=json.dumps({
                    "status": "success",
                    "processed_logs": len(funData)
                }),
                headers={"Content-Type": "application/json"}
            )
    
        except Exception as e:
            logging.getLogger().error(f"Error processing logs: {str(e)}")
            return response.Response(
                ctx,
                response_data=json.dumps({
                    "status": "error",
                    "message": str(e)
                }),
                headers={"Content-Type": "application/json"},
                status_code=500
            )
    
    • secret_key_id 替换为 AWS 密钥的实际保险库密钥 OCID
    • access_key_id 替换为 AWS 访问密钥的实际保险库密钥 OCID
    • s3_bucket_name 替换为您的实际 S3 存储桶名称

更新 func.yaml

func.yaml 的内容替换为:

  schema_version: 20180708
  name: pushlogs
  version: 0.0.1
  runtime: python
  build_image: fnproject/python:3.9-dev
  run_image: fnproject/python:3.9
  entrypoint: /python/bin/fdk /function/func.py handler
  memory: 256

更新 requirements.txt

  • requirements.txt 的内容替换为:

    fdk>=0.1.56
    boto3
    oci
    

部署该函数

  1. 将 Fn 上下文设置为使用您的应用:

    fn use context <region-context>
    fn update context oracle.compartment-id <compartment-ocid>
    
  2. 部署函数的方法如下:

    fn -v deploy --app oci-logs-to-s3-app
    
  3. 等待部署完成。您应该会看到输出,指示函数已成功部署。

  4. 验证函数是否已创建:

    fn list functions oci-logs-to-s3-app
    

创建服务连接器以将 OCI 审核日志发送到函数

  1. 登录 Oracle Cloud 控制台
  2. 依次前往分析和 AI > 信息传递 > Service Connector Hub
  3. 选择要在其中创建服务连接器的区间。
  4. 点击创建服务连接器

配置服务连接器详细信息

  1. 提供以下配置详细信息:

服务连接器信息: * 连接器名称:输入一个描述性名称(例如 audit-logs-to-s3-connector)。 * 说明:可选说明(例如“将 OCI 审核日志转发到 AWS S3”)。 * 资源隔离区:选择隔离区。

配置来源

  1. 配置来源下:
    • 来源:选择日志记录
    • 区间:选择包含审核日志的区间。
    • 日志组:选择 _Audit(这是审核日志的默认日志组)。
    • 日志:点击 + 另一条日志
    • 选择相应区间对应的审核日志(例如 _Audit_Include_Subcompartment)。

配置目标

  1. 配置目标下:
    • 目标:选择函数
    • 隔离区:选择包含函数应用的隔离区。
    • 函数应用:选择 oci-logs-to-s3-app(您之前创建的应用)。
    • 函数:选择 pushlogs(您部署的函数)。

配置政策

  1. 配置政策下:

    • 查看显示的必需 IAM 政策语句。
    • 点击创建以自动创建所需的政策。
  2. 点击创建以创建服务连接器。

  3. 等待服务连接器创建并激活。状态应更改为有效

验证日志是否正在推送到 AWS S3

  1. 登录 Oracle Cloud 控制台
  2. 执行一些会生成审核日志的操作(例如,创建或修改资源)。
  3. 等待 2-5 分钟,让系统处理日志。
  4. 登录 AWS Management Console
  5. 前往 S3 > 存储分区
  6. 点击您的存储桶(例如 oci-audit-logs-bucket)。
  7. 验证 JSON 日志文件是否显示在存储桶中。

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

为 Chronicle 创建 IAM 用户

  1. 登录 AWS Management Console
  2. 依次前往 IAM > 用户 > 添加用户
  3. 提供以下配置详细信息:
    • 用户名:输入 chronicle-s3-reader
    • 访问权限类型:选择访问密钥 - 以程序化方式访问
  4. 点击 Next: Permissions
  5. 点击 Attach existing policies directly
  6. 搜索并选择 AmazonS3ReadOnlyAccess 政策。
  7. 点击 Next: Tags
  8. 点击下一步:检查
  9. 点击创建用户
  10. 点击下载 CSV 文件以保存访问密钥 ID私有访问密钥
  11. 点击关闭

可选:创建自定义 IAM 政策以实现最小权限访问

如果您只想限制对特定存储桶的访问权限,请执行以下操作:

  1. 依次前往 IAM > 政策 > 创建政策
  2. 点击 JSON 标签页。
  3. 输入以下政策:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:GetObject",
            "s3:ListBucket"
          ],
          "Resource": [
            "arn:aws:s3:::oci-audit-logs-bucket",
            "arn:aws:s3:::oci-audit-logs-bucket/*"
          ]
        }
      ]
    }
    
    • oci-audit-logs-bucket 替换为您的存储分区名称。
  4. 点击 Next: Tags

  5. 点击下一步:检查

  6. 提供以下配置详细信息:

    • 名称chronicle-s3-read-policy
    • 说明:对 OCI 审核日志存储桶的只读访问权限
  7. 点击创建政策

  8. 返回到 IAM > 用户,然后选择 chronicle-s3-reader 用户。

  9. 依次点击添加权限 > 直接附加政策

  10. 搜索并选择 chronicle-s3-read-policy

  11. 移除之前添加的 AmazonS3ReadOnlyAccess 政策。

  12. 点击添加权限

在 Google SecOps 中配置 Feed 以注入 Oracle Cloud 审核日志

  1. 依次前往 SIEM 设置> Feed
  2. 点击添加新 Feed
  3. 在下一页上,点击配置单个 Feed
  4. Feed 名称字段中,输入 Feed 的名称(例如 Oracle Cloud Audit Logs)。
  5. 选择 Amazon S3 V2 作为来源类型
  6. 选择 Oracle Cloud Infrastructure 作为日志类型
  7. 点击下一步
  8. 为以下输入参数指定值:
    • S3 URI:输入 S3 存储桶 URI(例如 s3://oci-audit-logs-bucket/)。
    • 来源删除选项:根据您的偏好选择删除选项:
      • 从不:建议用于测试和初始设置。
      • 删除已转移的文件:成功提取文件后将其删除(用于生产环境,以控制存储费用)。
    • 文件存在时间上限:包含在过去指定天数内修改的文件。默认值为 180 天。
    • 访问密钥 ID:输入您创建的 Chronicle IAM 用户的访问密钥 ID。
    • 私有访问密钥:输入您创建的 Chronicle IAM 用户的私有访问密钥。
    • 资产命名空间资产命名空间
    • 注入标签:要应用于此 Feed 中事件的标签。
  9. 点击下一步
  10. 最终确定界面中查看新的 Feed 配置,然后点击提交

UDM 映射表

日志字段 UDM 映射 逻辑
data.request.headers.authorization.0 event.idm.read_only_udm.additional.fields data.request.headers.authorization.0 中获取的值,并以键值对的形式添加,其中键为“Request Headers Authorization”。
data.compartmentId event.idm.read_only_udm.additional.fields data.compartmentId 中提取的值,并以键值对的形式添加,其中键为“compartmentId”。
data.compartmentName event.idm.read_only_udm.additional.fields data.compartmentName 中获取的值,并以键值对的形式添加,其中键为“compartmentName”。
data.response.headers.Content-Length.0 event.idm.read_only_udm.additional.fields data.response.headers.Content-Length.0 中获取的值,并以键值对的形式添加,其中键为“Response Headers Content-Length”。
data.response.headers.Content-Type.0 event.idm.read_only_udm.additional.fields data.response.headers.Content-Type.0 中获取的值,并添加为键值对,其中键为“Response Headers Content-Type”。
data.eventGroupingId event.idm.read_only_udm.additional.fields data.eventGroupingId 中提取的值,并添加为键值对,其中键为“eventGroupingId”。
oracle.tenantiddata.identity.tenantId event.idm.read_only_udm.additional.fields 如果存在,则从 oracle.tenantid 中获取值,否则从 data.identity.tenantId 中获取值。它以键值对的形式添加,其中键为“tenantId”。
data.message event.idm.read_only_udm.metadata.description data.message 中获取的值。
time event.idm.read_only_udm.metadata.event_timestamp time 中提取的值,并解析为 ISO8601 时间戳。
event.idm.read_only_udm.metadata.event_type 默认设置为 GENERIC_EVENT。如果存在正文(IP 或主机名)和目标 IP,则设置为 NETWORK_CONNECTION。如果仅存在正文,则设置为 STATUS_UPDATE
time event.idm.read_only_udm.metadata.ingested_timestamp 如果 oracle.ingestedtime 不为空,则从 time 字段中获取值并将其解析为 ISO8601 时间戳。
oracle.tenantid event.idm.read_only_udm.metadata.product_deployment_id oracle.tenantid 中获取的值。
type event.idm.read_only_udm.metadata.product_event_type type 中获取的值。
oracle.logid event.idm.read_only_udm.metadata.product_log_id oracle.logid 中获取的值。
specversion event.idm.read_only_udm.metadata.product_version specversion 中获取的值。
data.request.action event.idm.read_only_udm.network.http.method data.request.action 中获取的值。
data.identity.userAgent event.idm.read_only_udm.network.http.parsed_user_agent data.identity.userAgent 中提取并解析的值。
data.response.status event.idm.read_only_udm.network.http.response_code data.response.status 中获取的值并转换为整数。
data.protocol event.idm.read_only_udm.network.ip_protocol data.protocol 中的数值会转换为其字符串表示形式(例如,6 变为“TCP”,17 变为“UDP”)。
data.bytesOut event.idm.read_only_udm.network.sent_bytes data.bytesOut 中获取的值,并转换为无符号整数。
data.packets event.idm.read_only_udm.network.sent_packets data.packets 中获取的值并转换为整数。
data.identity.consoleSessionId event.idm.read_only_udm.network.session_id data.identity.consoleSessionId 中获取的值。
id event.idm.read_only_udm.principal.asset.product_object_id id 中获取的值。
source event.idm.read_only_udm.principal.hostname source 中获取的值。
data.sourceAddressdata.identity.ipAddress event.idm.read_only_udm.principal.ip data.sourceAddressdata.identity.ipAddress 中的值会合并到此字段中。
data.sourcePort event.idm.read_only_udm.principal.port data.sourcePort 中获取的值并转换为整数。
data.request.headers.X-Forwarded-For.0 event.idm.read_only_udm.principal.resource.attribute.labels data.request.headers.X-Forwarded-For.0 中获取值,并以键值对的形式添加,其中键为“x forward”。
oracle.compartmentid event.idm.read_only_udm.principal.resource.attribute.labels oracle.compartmentid 中获取的值,并添加为键值对,其中键为“compartmentid”。
oracle.loggroupid event.idm.read_only_udm.principal.resource.attribute.labels oracle.loggroupid 中提取的值,并以键值对的形式添加,其中键为“loggroupid”。
oracle.vniccompartmentocid event.idm.read_only_udm.principal.resource.attribute.labels oracle.vniccompartmentocid 中获取的值,并添加为键值对,其中键为“vniccompartmentocid”。
oracle.vnicocid event.idm.read_only_udm.principal.resource.attribute.labels oracle.vnicocid 中提取的值,并添加为键值对,其中键为“vnicocid”。
oracle.vnicsubnetocid event.idm.read_only_udm.principal.resource.attribute.labels oracle.vnicsubnetocid 中获取的值,并以键值对的形式添加,其中键为“vnicsubnetocid”。
data.flowid event.idm.read_only_udm.principal.resource.product_object_id data.flowid 中获取的值。
data.identity.credentials event.idm.read_only_udm.principal.user.attribute.labels data.identity.credentials 中获取值,并以键值对的形式添加,其中键为“credentials”。
data.identity.principalName event.idm.read_only_udm.principal.user.user_display_name data.identity.principalName 中获取的值。
data.identity.principalId event.idm.read_only_udm.principal.user.userid data.identity.principalId 中获取的值。
data.action event.idm.read_only_udm.security_result.action 默认设置为 UNKNOWN_ACTION。如果 data.action 为“REJECT”,则此参数设置为 BLOCK。如果 data.action 为“ACCEPT”,则此属性设置为 ALLOW
data.endTime event.idm.read_only_udm.security_result.detection_fields data.endTime 中提取的值,并添加为键值对,其中键为“endTime”。
data.startTime event.idm.read_only_udm.security_result.detection_fields data.startTime 中提取的值,并添加为键为“startTime”的键值对。
data.status event.idm.read_only_udm.security_result.detection_fields data.status 中获取的值,并添加为键值对,其中键为“status”。
data.version event.idm.read_only_udm.security_result.detection_fields data.version 中提取的值,并以键值对的形式添加,其中键为“version”。
data.destinationAddress event.idm.read_only_udm.target.ip data.destinationAddress 中获取的值。
data.destinationPort event.idm.read_only_udm.target.port data.destinationPort 中获取的值并转换为整数。
data.request.path event.idm.read_only_udm.target.url data.request.path 中获取的值。
event.idm.read_only_udm.metadata.product_name 设置为“ORACLE CLOUD AUDIT”。
event.idm.read_only_udm.metadata.vendor_name 设置为“ORACLE”。

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