收集 Oracle Fusion Cloud Applications 日志

支持的平台:

本文档介绍了如何使用 Google Cloud Storage V2 将 Oracle Fusion Cloud Applications 日志注入到 Google Security Operations。

Oracle Fusion Cloud Applications 是 Oracle 的一套全面的基于云的企业资源规划 (ERP)、人力资源管理 (HCM)、供应链管理 (SCM) 和客户体验 (CX) 应用。该平台通过 REST API 提供广泛的审核日志记录功能,可捕获所有 Fusion 模块中的用户身份验证事件、交易更改、管理操作和安全相关活动。Cloud Run 函数会查询 Oracle Fusion Audit REST API 以检索此数据,并将其写入 GCS 存储桶,以便 Google SecOps 提取数据。

准备工作

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

  • Google SecOps 实例
  • 启用了 Cloud Storage、Cloud Run、Pub/Sub 和 Cloud Scheduler API 的 GCP 项目
  • 创建和管理 GCS 存储分区的权限
  • 管理 GCS 存储分区的 IAM 政策的权限
  • 创建 Cloud Run 服务、Pub/Sub 主题和 Cloud Scheduler 作业的权限
  • 对 Oracle Fusion Cloud Applications 的管理员访问权限
  • 管理员对与 Fusion Applications 实例关联的 Oracle Cloud Infrastructure (OCI) Identity and Access Management (IAM) 身份网域的访问权限
  • 具有 FND_VIEW_AUDIT_HISTORY_PRIV 权限或 Fusion Apps Administrator 角色的 Fusion Applications 用户账号

配置 Oracle Fusion Cloud Applications OAuth 2.0 API 访问权限

如需让 Google SecOps 检索审核日志,您需要使用“客户端凭据”授权类型创建 OAuth 2.0 机密应用,并将客户端 ID 配置为 Fusion Applications 中的用户。

创建 OAuth 2.0 保密应用

  1. 使用身份网域管理员凭据登录 Oracle Cloud Infrastructure 控制台
  2. 在菜单栏中,依次点击身份和安全 > 网域
  3. 选择您的隔离区。
  4. 点击与您的 Fusion Applications 实例关联的身份网域。
  5. 在菜单栏中,依次点击集成式应用 > 添加应用
  6. 添加应用对话框中,选择保密应用,然后点击启动工作流
  7. 添加保密应用页面上的名称字段中,输入一个描述性名称(例如 Chronicle SIEM Integration)。
  8. 点击下一步
  9. Configure OAuth(配置 OAuth)部分,选中 Configure this application as a client now(立即将此应用配置为客户端)复选框。
  10. 授权部分中,选中客户端凭据复选框。
  11. 清除所有其他授权类型复选框。
  12. 向下滚动到令牌发放政策部分。
  13. 授权资源部分,选择特定
  14. 选中添加资源复选框。
  15. 资源子部分中,点击添加范围
  16. 添加范围对话框中,找到并选择 Fusion Applications 资源应用。
  17. 为 Fusion Applications 实例选择合适的范围。

  18. 点击 Add(添加)。

  19. 点击下一步

  20. Web tier policy 页面上,接受默认设置,然后点击 Finish

  21. 系统会显示一个确认对话框,其中显示自动生成的客户端 ID客户端密钥值。

  22. 立即复制并保存客户端 ID客户端密钥

  23. 点击关闭

  24. 在应用详情页面上,点击启用

  25. 在确认对话框中,点击激活应用

记录身份网域网址

  1. 在 Oracle 云基础设施控制台中,查看身份网域时,请记下页面顶部显示的网域网址
  2. 网域网址的格式为 https://idcs-<idcs-id>.identity.oraclecloud.com
  3. 保存此网址以备稍后使用。

为 OAuth 客户端创建用户账号

在客户端凭据流程中,API 调用是在应用本身(而非用户)的上下文中调用的。您必须在 Fusion Applications 中创建一个与 OAuth 客户端 ID 具有相同用户名的用户账号。

  1. 登录 Oracle Fusion Cloud Applications
  2. 点击左上角的Navigator图标。
  3. 工具下,选择安全控制台
  4. 点击用户
  5. 点击添加用户账号
  6. 用户信息部分的用户名字段中,输入 OAuth 应用中的客户端 ID 值。

  7. 填写剩余的必填字段:

    • First Name(名字):输入 Google SecOps 或描述性名称
    • Last Name(姓氏):输入 Integration 或描述性名称
    • 电子邮件地址:输入有效的电子邮件地址(例如 chronicle-integration@yourcompany.com
  8. 点击添加角色

  9. 搜索并添加以下角色:

    • Fusion Apps 管理员
  10. 点击保存并关闭

记录 Fusion Applications 基准网址

  1. 登录 Oracle Fusion Cloud Applications 后,记下浏览器地址栏中的网址。
  2. 基本网址的格式为 https://<instance>.<service>.<datacenter>.oraclecloud.com
  3. 仅提取主机名部分(例如,mycompany.fa.us2.oraclecloud.com)。
  4. 保存此主机名以备稍后使用。

验证权限

如需验证 OAuth 客户端是否拥有所需权限,请执行以下操作:

  1. 登录 Oracle Fusion Cloud Applications
  2. 依次点击导航器图标 > 工具 > 安全控制台
  3. 点击用户,然后搜索与客户端 ID 匹配的用户账号。
  4. 验证用户是否已获分配 Fusion Apps 管理员角色或 FND_VIEW_AUDIT_HISTORY_PRIV 权限。
  5. 如果您找不到相应用户或缺少相应权限,请与 Fusion Applications 管理员联系,以获取所需角色。

测试 API 访问权限

  • 在继续进行集成之前,请先测试您的凭据:

    # Replace with your actual values
    IDENTITY_DOMAIN_URL="https://idcs-xxxxxxxxxxxx.identity.oraclecloud.com"
    CLIENT_ID="your-client-id"
    CLIENT_SECRET="your-client-secret"
    FUSION_HOST="mycompany.fa.us2.oraclecloud.com"
    OAUTH_SCOPE="urn:opc:resource:fusion:podname:boss/"
    FUSION_USERNAME="svc_secops_audit"
    FUSION_PASSWORD="your-user-password"
    
    # Step 1: Obtain OAuth access token (only needed if you use bearer auth instead of Basic)
    TOKEN=$(curl -s -u "${CLIENT_ID}:${CLIENT_SECRET}" \
        -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
        -X POST "${IDENTITY_DOMAIN_URL}/oauth2/v1/token" \
        -d "grant_type=client_credentials&scope=${OAUTH_SCOPE}" \
        | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
    
    echo "Token obtained: ${TOKEN:0:20}..."
    
    # Step 2: Test the Sign In - Sign Out Audit REST API (last 7 days of data)
    # The API is documented with HTTP Basic auth (-u "<user>:<password>").
    # If your tenant accepts the bearer token instead, replace -u with
    # -H "Authorization: Bearer ${TOKEN}".
    curl -s -X GET "https://${FUSION_HOST}/oam/services/rest/access/api/v1/audit/events/1?fromDate=$(date -u -v-7d '+%Y-%m-%dT%H:%M:%S.000Z')&toDate=$(date -u '+%Y-%m-%dT%H:%M:%S.000Z')&pageSize=5" \
        -u "${FUSION_USERNAME}:${FUSION_PASSWORD}" \
        -H "Accept: application/json" \
        | python3 -m json.tool
    

如果请求成功,系统会返回一个 JSON 对象,其中包含一个 Events.eventData 数组,该数组包含登录和退出记录(每条记录都包含 eventIDuserIDipAddresstypestatusaccessTime 等字段)。

创建 Google Cloud Storage 存储桶

  1. 前往 Google Cloud 控制台
  2. 选择您的项目或创建新项目。
  3. 在导航菜单中,依次前往 Cloud Storage > 存储分区
  4. 点击创建存储分区
  5. 提供以下配置详细信息:

    设置
    为存储桶命名 输入一个全局唯一的名称(例如 oracle-fusion-audit-logs
    位置类型 根据您的需求进行选择(区域级、双区域、多区域)
    位置 选择营业地点(例如 us-central1
    存储类别 标准(建议用于经常访问的日志)
    访问权限控制 均匀(推荐)
    保护工具 可选:启用对象版本控制或保留政策
  6. 点击创建

为 Cloud Run 函数创建服务账号

Cloud Run 函数需要一个服务账号,该账号具有写入 GCS 存储桶的权限,并且可以由 Pub/Sub 调用。

创建服务账号

  1. GCP 控制台中,依次前往 IAM 和管理 > 服务账号
  2. 点击创建服务账号
  3. 提供以下配置详细信息:
    • 服务账号名称:输入 oracle-fusion-audit-collector-sa
    • 服务账号说明:输入 Service account for Cloud Run function to collect Oracle Fusion Cloud Applications audit logs
  4. 点击创建并继续
  5. 向此服务账号授予对项目的访问权限部分中,添加以下角色:
    1. 点击选择角色
    2. 搜索并选择 Storage Object Admin
    3. 点击 + 添加其他角色
    4. 搜索并选择 Cloud Run Invoker
    5. 点击 + 添加其他角色
    6. 搜索并选择 Cloud Functions Invoker
  6. 点击继续
  7. 点击完成

必须拥有这些角色,才能:

  • Storage Object Admin:将日志写入 GCS 存储桶并管理状态文件
  • Cloud Run Invoker:允许 Pub/Sub 调用函数
  • Cloud Functions Invoker:允许调用函数

授予对 GCS 存储桶的 IAM 权限

  1. 前往 Cloud Storage > 存储分区
  2. 点击您的存储桶名称 (oracle-fusion-audit-logs)。
  3. 前往权限标签页。
  4. 点击授予访问权限
  5. 提供以下配置详细信息:
    • 添加主账号:输入服务账号电子邮件地址 (oracle-fusion-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com)
    • 分配角色:选择 Storage Object Admin
  6. 点击保存

创建 Pub/Sub 主题

  1. GCP 控制台中,前往 Pub/Sub > 主题
  2. 点击创建主题
  3. 提供以下配置详细信息:
    • 主题 ID:输入 oracle-fusion-audit-trigger
    • 将其他设置保留为默认值
  4. 点击创建

创建 Cloud Run 函数以收集日志

Cloud Run 函数将由来自 Cloud Scheduler 的 Pub/Sub 消息触发,以从 Oracle Fusion Cloud Applications Audit REST API 中提取审核数据并将其写入 GCS。

  1. GCP 控制台中,前往 Cloud Run
  2. 点击创建服务
  3. 选择函数(使用内嵌编辑器创建函数)。
  4. 配置部分中,提供以下配置详细信息:

    设置
    Service 名称 oracle-fusion-audit-collector
    区域 选择与您的 GCS 存储桶匹配的区域(例如 us-central1
    运行时 选择 Python 3.12 或更高版本
  5. 触发器(可选)部分中:

    1. 点击 + 添加触发器
    2. 选择 Cloud Pub/Sub
    3. 选择 Cloud Pub/Sub 主题中,选择 oracle-fusion-audit-trigger
    4. 点击保存
  6. 身份验证部分中:

    1. 选择需要进行身份验证
    2. 检查 Identity and Access Management (IAM)
  7. 向下滚动并展开容器、网络、安全性

  8. 前往安全性标签页:

    • 服务账号:选择 oracle-fusion-audit-collector-sa
  9. 前往容器标签页:

    1. 点击变量和密钥
    2. 为每个环境变量点击+ 添加变量
    变量名称 示例值 说明
    GCS_BUCKET oracle-fusion-audit-logs GCS 存储桶名称
    GCS_PREFIX oracle-fusion-audit 日志文件的前缀
    STATE_KEY oracle-fusion-audit/state.json 状态文件路径
    FUSION_HOST mycompany.fa.us2.oraclecloud.com Fusion Applications 主机名
    IDENTITY_DOMAIN_URL https://idcs-xxxx.identity.oraclecloud.com 身份网域网址
    CLIENT_ID your-client-id OAuth 2.0 客户端 ID
    CLIENT_SECRET your-client-secret OAuth 2.0 客户端密钥
    OAUTH_SCOPE urn:opc:resource:fusion:podname:boss/ Fusion Applications 的 OAuth 范围
    LOOKBACK_HOURS 24 初始回溯期
    PAGE_SIZE 100 每页记录数
    FUSION_USERNAME svc_secops_audit 可选。HTTP 基本身份验证的用户,用于登录/退出审核 API。如果为空,则使用 OAuth 2.0 不记名令牌
    FUSION_PASSWORD your-user-password 可选。FUSION_USERNAME 的密码(存储为 Secret Manager Secret)
  10. 变量和 Secret 部分中,向下滚动到请求

    • 请求超时:输入 600 秒(10 分钟)
  11. 前往设置标签页:

    • 资源部分中:
      • 内存:选择 512 MiB 或更高值
      • CPU:选择 1
  12. 修订版本伸缩部分中:

    • 实例数下限:输入 0
    • 实例数上限:输入 100
  13. 点击创建

  14. 等待服务创建完成(1-2 分钟)。

  15. 创建服务后,系统会自动打开内嵌代码编辑器

添加函数代码

  1. 入口点字段中输入 main
  2. 在内嵌代码编辑器中,创建两个文件:

    • main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timezone, timedelta
    import time
    import base64
    import urllib.parse
    
    http = urllib3.PoolManager(
      timeout=urllib3.Timeout(connect=10.0, read=60.0),
      retries=False,
    )
    
    storage_client = storage.Client()
    
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'oracle-fusion-audit')
    STATE_KEY = os.environ.get('STATE_KEY', 'oracle-fusion-audit/state.json')
    FUSION_HOST = os.environ.get('FUSION_HOST', '').strip()
    IDENTITY_DOMAIN_URL = os.environ.get('IDENTITY_DOMAIN_URL', '').rstrip('/')
    CLIENT_ID = os.environ.get('CLIENT_ID')
    CLIENT_SECRET = os.environ.get('CLIENT_SECRET')
    OAUTH_SCOPE = os.environ.get('OAUTH_SCOPE', '')
    # The Sign In - Sign Out Audit REST API is documented with HTTP Basic auth.
    # Set FUSION_USERNAME / FUSION_PASSWORD to use it; otherwise the function falls
    # back to the OAuth 2.0 bearer token configured above.
    FUSION_USERNAME = os.environ.get('FUSION_USERNAME', '')
    FUSION_PASSWORD = os.environ.get('FUSION_PASSWORD', '')
    LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '100'))
    
    # Sign In - Sign Out Audit REST API. Returns {"Events": {"eventData": [...]}},
    # which the ORACLE_FUSION parser reads directly. Data is retained for 7 days.
    AUDIT_PATH = '/oam/services/rest/access/api/v1/audit/events'
    
    def get_oauth_token():
      token_url = f"{IDENTITY_DOMAIN_URL}/oauth2/v1/token"
      auth_b64 = base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode('utf-8')).decode('utf-8')
      body = f"grant_type=client_credentials&scope={urllib.parse.quote(OAUTH_SCOPE, safe='')}"
      try:
        response = http.request(
          'POST', token_url,
          body=body.encode('utf-8'),
          headers={
            'Authorization': f'Basic {auth_b64}',
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
          }
        )
        if response.status != 200:
          print(f"OAuth token request failed: {response.status} {response.data.decode('utf-8')}")
          return None
        return json.loads(response.data.decode('utf-8')).get('access_token')
      except Exception as e:
        print(f"Error obtaining OAuth token: {e}")
        return None
    
    def get_auth_header():
      """Use HTTP Basic auth when FUSION_USERNAME/PASSWORD are set, else OAuth bearer."""
      if FUSION_USERNAME and FUSION_PASSWORD:
        creds_b64 = base64.b64encode(f"{FUSION_USERNAME}:{FUSION_PASSWORD}".encode('utf-8')).decode('utf-8')
        return f"Basic {creds_b64}"
      token = get_oauth_token()
      return f"Bearer {token}" if token else None
    
    def fetch_signin_audit(auth_header, start_time, end_time):
      """Page through the Sign In - Sign Out Audit REST API.
    
      Returns (pages, newest_time). Each item in pages is a raw
      {"Events": {"eventData": [...]}} object, written unchanged for the parser.
      """
      base_url = f"https://{FUSION_HOST}{AUDIT_PATH}"
      from_date = start_time.strftime('%Y-%m-%dT%H:%M:%S.000Z')
      to_date = end_time.strftime('%Y-%m-%dT%H:%M:%S.000Z')
    
      headers = {'Authorization': auth_header, 'Accept': 'application/json'}
    
      pages = []
      newest_time = None
      page_num = 1
      backoff = 1.0
    
      while True:
        query_string = urllib.parse.urlencode({
          'fromDate': from_date,
          'toDate': to_date,
          'pageSize': str(PAGE_SIZE),
        })
        # The page number is a path segment: /audit/events/{page}
        request_url = f"{base_url}/{page_num}?{query_string}"
    
        try:
          response = http.request('GET', request_url, headers=headers)
    
          if response.status == 429:
            retry_after = int(response.headers.get('Retry-After', str(int(backoff))))
            print(f"Rate limited (429). Retrying after {retry_after}s...")
            time.sleep(retry_after)
            backoff = min(backoff * 2, 60.0)
            continue
          backoff = 1.0
    
          if response.status != 200:
            print(f"HTTP Error {response.status}: {response.data.decode('utf-8')}")
            break
    
          data = json.loads(response.data.decode('utf-8'))
          event_list = data.get('Events', {}).get('eventData', [])
          if isinstance(event_list, dict):
            event_list = [event_list]
    
          if not event_list:
            print(f"No more sign-in events (empty page {page_num})")
            break
    
          # Preserve the exact {"Events": {"eventData": [...]}} shape the parser
          # consumes; do not rename or flatten individual records.
          pages.append({'Events': {'eventData': event_list}})
          print(f"Page {page_num}: retrieved {len(event_list)} sign-in events")
    
          for event in event_list:
            access_time = event.get('accessTime')
            if access_time and (newest_time is None or access_time > newest_time):
              newest_time = access_time
    
          if len(event_list) < PAGE_SIZE:
            break
          page_num += 1
    
        except Exception as e:
          print(f"Error fetching sign-in audit: {e}")
          break
    
      print(f"Retrieved {len(pages)} page(s) of sign-in audit events")
      return pages, newest_time
    
    @functions_framework.cloud_event
    def main(cloud_event):
      if not all([GCS_BUCKET, FUSION_HOST]):
        print('Error: Missing required environment variables (GCS_BUCKET, FUSION_HOST)')
        return
    
      try:
        bucket = storage_client.bucket(GCS_BUCKET)
        state = load_state(bucket)
        now = datetime.now(timezone.utc)
    
        if isinstance(state, dict) and state.get('last_event_time'):
          try:
            last_val = state['last_event_time']
            if last_val.endswith('Z'):
              last_val = last_val[:-1] + '+00:00'
            last_time = datetime.fromisoformat(last_val) - timedelta(minutes=2)
          except Exception as e:
            print(f"Warning: could not parse last_event_time: {e}")
            last_time = now - timedelta(hours=LOOKBACK_HOURS)
        else:
          last_time = now - timedelta(hours=LOOKBACK_HOURS)
    
        # The API retains only 7 days of data; never look back further.
        earliest = now - timedelta(days=7)
        if last_time < earliest:
          last_time = earliest
    
        print(f"Fetching sign-in audit from {last_time.isoformat()} to {now.isoformat()}")
    
        auth_header = get_auth_header()
        if not auth_header:
          print("Error: could not build authorization header")
          return
    
        pages, newest_time = fetch_signin_audit(auth_header, last_time, now)
    
        if not pages:
          print("No new sign-in audit events found.")
          save_state(bucket, now.isoformat())
          return
    
        timestamp = now.strftime('%Y%m%d_%H%M%S')
        object_key = f"{GCS_PREFIX}/oracle_fusion_audit_{timestamp}.ndjson"
        blob = bucket.blob(object_key)
    
        ndjson = '\n'.join([json.dumps(p, ensure_ascii=False, default=str) for p in pages]) + '\n'
        blob.upload_from_string(ndjson, content_type='application/x-ndjson')
        print(f"Wrote {len(pages)} page(s) to gs://{GCS_BUCKET}/{object_key}")
    
        save_state(bucket, newest_time if newest_time else now.isoformat())
        print("Successfully processed sign-in audit events")
    
      except Exception as e:
        print(f'Error processing logs: {str(e)}')
        raise
    
    def load_state(bucket):
      try:
        blob = bucket.blob(STATE_KEY)
        if blob.exists():
          return json.loads(blob.download_as_text())
      except Exception as e:
        print(f"Warning: Could not load state: {e}")
      return {}
    
    def save_state(bucket, last_event_time_iso):
      try:
        state = {
          'last_event_time': last_event_time_iso,
          'last_run': datetime.now(timezone.utc).isoformat()
        }
        blob = bucket.blob(STATE_KEY)
        blob.upload_from_string(json.dumps(state, indent=2), content_type='application/json')
        print(f"Saved state: last_event_time={last_event_time_iso}")
      except Exception as e:
        print(f"Warning: Could not save state: {e}")
    

    • requirements.txt:

      functions-framework==3.*
      google-cloud-storage==2.*
      urllib3>=2.0.0
      
  3. 点击部署以保存并部署该函数。

  4. 等待部署完成(2-3 分钟)。

创建 Cloud Scheduler 作业

  1. GCP Console 中,前往 Cloud Scheduler
  2. 点击创建作业
  3. 提供以下配置详细信息:

    设置
    名称 oracle-fusion-audit-collector-hourly
    区域 选择与 Cloud Run 函数相同的区域
    频率 0 * * * *(每小时一次,整点时)
    时区 选择时区(建议选择 UTC)
    目标类型 Pub/Sub
    主题 选择oracle-fusion-audit-trigger
    消息正文 {}(空 JSON 对象)
  4. 点击创建

时间表频率选项

根据日志量和延迟时间要求选择频次:

频率 Cron 表达式 使用场景
每隔 5 分钟 */5 * * * * 大批量、低延迟
每隔 15 分钟 */15 * * * * 搜索量中等
每小时 0 * * * * 标准(推荐)
每 6 小时 0 */6 * * * 低成交量、批处理
每天 0 0 * * * 历史数据收集

测试集成

  1. Cloud Scheduler 控制台中,找到您的作业 (oracle-fusion-audit-collector-hourly)。
  2. 点击强制运行以手动触发作业。
  3. 等待几秒钟。
  4. 前往 Cloud Run > 服务
  5. 点击 oracle-fusion-audit-collector
  6. 点击日志标签页。
  7. 验证函数是否已成功执行。查找:

    Fetching logs from YYYY-MM-DDTHH:MM:SS+00:00 to YYYY-MM-DDTHH:MM:SS+00:00
    Successfully obtained OAuth access token
    Page 1: Retrieved X audit events
    Wrote X records to gs://oracle-fusion-audit-logs/oracle-fusion-audit/oracle_fusion_audit_YYYYMMDD_HHMMSS.ndjson
    Successfully processed X records
    
  8. 前往 Cloud Storage > 存储分区

  9. 点击 oracle-fusion-audit-logs

  10. 转到 oracle-fusion-audit/ 文件夹。

  11. 验证是否已创建具有当前时间戳的新 .ndjson 文件。

如果您在日志中看到错误,请执行以下操作:

  • HTTP 401:验证 CLIENT_IDCLIENT_SECRET 环境变量是否正确,以及 OAuth 应用是否已激活
  • HTTP 403:验证 Fusion Applications 用户(与客户端 ID 匹配)是否具有 FND_VIEW_AUDIT_HISTORY_PRIV 权限或 Fusion Apps 管理员角色
  • HTTP 429:速率限制 - 函数将自动重试,并采用指数退避算法
  • API 状态为“失败”:验证 FUSION_HOST 环境变量是否正确,以及 Fusion Applications 实例是否可访问
  • OAuth 令牌错误:验证 IDENTITY_DOMAIN_URLOAUTH_SCOPE 环境变量是否正确

所需 API 权限

  • OAuth 客户端需要以下权限:

    权限/范围 访问权限级别 用途
    FND_VIEW_AUDIT_HISTORY_PRIV 读取 从 Fusion Applications 检索审核历史记录数据
    Fusion 应用范围 应用 访问 Fusion Applications REST API 资源

区域端点

Oracle Fusion Cloud Applications 使用不同的数据中心区域。基本网址格式因区域而异:

区域 数据中心代码 主机名示例
美国西部(凤凰城) us-phoenix-1 instance.fa.us-phoenix-1.oraclecloud.com
美国东部(阿什本) us-ashburn-1 instance.fa.us-ashburn-1.oraclecloud.com
美国商业广告 2 us2 instance.fa.us2.oraclecloud.com
欧盟西部(法兰克福) eu-frankfurt-1 instance.fa.eu-frankfurt-1.oraclecloud.com
欧盟西部(阿姆斯特丹) eu-amsterdam-1 instance.fa.eu-amsterdam-1.oraclecloud.com
英国南部(伦敦) uk-london-1 instance.fa.uk-london-1.oraclecloud.com
加拿大东南部(多伦多) ca-toronto-1 instance.fa.ca-toronto-1.oraclecloud.com
亚太地区东南(悉尼) ap-sydney-1 instance.fa.ap-sydney-1.oraclecloud.com
亚太东北地区(东京) ap-tokyo-1 instance.fa.ap-tokyo-1.oraclecloud.com

使用与您的 Oracle Fusion Cloud Applications 实例区域对应的主机名。您可以通过访问 Fusion Applications 环境时显示的网址来确定您的区域。

API 速率限制

Oracle Fusion Cloud Applications Audit REST API 具有以下特征:

限制类型
令牌有效期 3600 秒(1 小时)
审核历史记录查询范围 每次请求最多可查询 1 个月的数据
登录/退出审核日志保留 7 天
交易审核日志保留 30-365 天(因产品而异)

Cloud Run 函数会自动处理 OAuth 令牌刷新、分页和查询范围分块。该函数会将超过一个月的时间范围拆分为按月分块,并通过自动重新身份验证来处理令牌过期问题。

Note: For sign-in and sign-out audit events, the retention period is limited to 7 days. Configure the scheduler to poll frequently to avoid data loss. Transaction audit retention varies by Fusion Applications product and configuration.

检索 Google SecOps 服务账号

  1. 依次前往 SIEM 设置 > Feed
  2. 点击添加新 Feed
  3. 点击配置单个 Feed
  4. Feed 名称字段中,输入 Feed 的名称(例如 Oracle Fusion Audit Logs)。
  5. 选择 Google Cloud Storage V2 作为来源类型
  6. 选择 Oracle Fusion Cloud Applications 作为日志类型
  7. 点击获取服务账号
  8. 系统会显示一个唯一的服务账号电子邮件地址,例如:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  9. 复制此电子邮件地址,以便在下一步中使用。

  10. 点击下一步

  11. 为以下输入参数指定值:

    • 存储桶网址:输入带有前缀路径的 GCS 存储桶 URI:

      gs://oracle-fusion-audit-logs/oracle-fusion-audit/
      
    • 来源删除选项:根据您的偏好选择删除选项:

      • 永不:转移后永不删除任何文件(建议用于测试)。
      • 删除已转移的文件:在成功转移后删除文件。
      • 删除已转移的文件和空目录:成功转移后删除文件和空目录。

    • 文件存在时间上限:包含在过去指定天数内修改过的文件(默认值为 180 天)

    • 资产命名空间资产命名空间

    • 注入标签:要应用于此 Feed 中事件的标签

  12. 点击下一步

  13. 最终确定界面中查看新的 Feed 配置,然后点击提交

向 Google SecOps 服务账号授予 IAM 权限

Google SecOps 服务账号需要您的 GCS 存储桶的 Storage Object Viewer 角色。

  1. 前往 Cloud Storage > 存储分区
  2. 点击 oracle-fusion-audit-logs
  3. 前往权限标签页。
  4. 点击授予访问权限
  5. 提供以下配置详细信息:
    • 添加主账号:粘贴 Google SecOps 服务账号电子邮件地址
    • 分配角色:选择 Storage Object Viewer
  6. 点击保存

UDM 映射表

日志字段 UDM 映射 逻辑
类型 extensions.auth.type 身份验证类型
类型 metadata.event_type 事件类型
ipAddress metadata.event_type
eventID metadata.product_log_id 产品日志 ID
attributeMap.attribute.value network.http.user_agent HTTP 用户代理
ipAddress principal.asset.ip 与正文相关联的资产的 IP 地址
ipAddress principal.ip 主账号的 IP 地址
userID.userDN principal.user.attribute.labels 用户属性的标签
userID.userDN principal.user.email_addresses 用户的电子邮件地址
userID.loginID principal.user.userid 用户 ID
状态 security_result.action 安全操作
oracleECID target.user.userid 目标的相应用户 ID

更新日志

查看相应解析器的更改日志

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