本页面适用于 Apigee 和 Apigee Hybrid。
本文档介绍了如何将 Apigee 与 Google Security Operations (Google SecOps) 集成。如果您将 Google SecOps 用作 SIEM 解决方案,请按照本文档中的步骤配置 Apigee 以将日志数据发送到 SecOps。
为了简化此集成,Google SecOps 支持用于提取 Apigee 日志数据的 Apigee 解析器。 另请参阅将 Google Cloud 数据注入到 Google Security Operations。 完成本文档中的配置步骤后,您的 Apigee 日志数据将流向 Google SecOps。
如需了解如何将 SecOps 与其他 SIEM 解决方案集成,请参阅将 Apigee 与您的 SIEM 解决方案集成。
受众群体
本文档的目标受众包括:
- API 管理员,他们负责确保 API 安全性、管理平台配置、支持运营效率以及遵守安全合规性要求。
- 安全分析师,他们专注于主动检测和调查与 API 相关的安全事件,以最大限度地降低风险并保护敏感数据。
配置概览
本文档中讨论的配置使用 Apigee MessageLogging 政策将各种 Apigee 日志数据(包括特定的流变量)发送到 SecOps。
Google SecOps 提供了一个特殊的 Cloud Logging 过滤器,可将特定日志类型(包括 Apigee 日志)实时发送到 Google SecOps。Google SecOps 支持 Apigee 解析器,用于将 Apigee 日志数据提取到 Google SecOps。另请参阅将 Google Cloud 数据注入到 Google Security Operations。
前提条件
满足这些前提条件后,请按照本文档中的说明将 Apigee 与 SecOps 实例集成。 在开始集成之前,请确保您已满足以下条件:
- 具有开发和部署 API 代理的管理员权限的 Apigee 或 Apigee Hybrid 账号
- Google SecOps 账号
- 已启用 Cloud Logging,并有 Cloud Logging 配置和使用方面的经验
- 了解 Apigee 流变量
- 了解 Apigee MessageLogging 政策以及常规政策使用和配置
- (可选)了解如何使用 Google SecOps 解析器解读提取的日志。 SecOps 解析器默认内置,用于解析和理解 MessageLogging 政策提取的 Apigee 日志。
- 使用 Cloud Logging API 和向 SecOps 服务账号授予 IAM 角色的 Google Cloud IAM 权限
将 Apigee 与 SecOps 集成
如果您将 Google SecOps 用作 SIEM 解决方案,请按照以下步骤将 Apigee 日志数据发送到 SecOps。共有两个基本步骤:
- 配置 MessageLogging 政策以将 Apigee 日志数据发送到 Cloud Logging
- 将 MessageLogging 政策附加到 Apigee 代理
完成本部分中所述的 MessageLogging 政策配置后,SecOps 将解析发送到 Cloud Logging 的 Apigee 日志数据。如需详细了解该解析器以及 Apigee 流变量数据如何映射到 SecOps 数据字段,请参阅将 Apigee 与 Google SecOps SIEM 集成。 另请参阅收集 Apigee 日志。
如需使用 MessageLogging 政策将 Apigee 与 SecOps 集成,请按以下步骤操作:
配置新的 MessageLogging 政策。请参阅在界面中关联和配置政策。
以下是将数据发送到 Cloud Logging 的 MessageLogging 政策示例。该政策指定了要发送到 Cloud Logging 的大量流变量。您可以根据您确定对 SecOps 分析至关重要的字段,随意添加或移除流程变量。如需了解如何将 Apigee 流变量数据映射到 SecOps 数据字段,请参阅将 Apigee 与 Google SecOps SIEM 集成。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <MessageLogging continueOnError="false" enabled="true" name="ML-CloudLoggingSecOps"> <DisplayName>ML-CloudLoggingSecOps</DisplayName> <CloudLogging> <LogName>projects/{organization.name}/logs/Apigee-SecOps-Integration-{environment.name}</LogName> <Message contentType="application/json">{ "apiproduct.name": "{apiproduct.name}", "app.name": "{developer.app.name}", "cachehit":"{cachehit}", "client.country": "{client.country}", "client.cn": "{client.cn}", "client.ip": "{proxy.client.ip}", "client.locality": "{client.locality}", "client.port": "{client.port}", "client.scheme": "{client.scheme}", "client.state": "{client.state}", "developer.email": "{developer.email}", "environment.name": "{environment.name}", "error":"{is.error}", "error.state":"{error.state}", "error.message":"{escapeJSON(error.message)}", "fault.name":"{fault.name}", "messageid":"{messageid}", "organization.name": "{organization.name}", "proxy.name": "{apiproxy.name}", "proxy.basepath": "{proxy.basepath}", "proxy.pathsuffix": "{proxy.pathsuffix}", "proxy.proxyendpoint.name": "{proxy.name}", "proxy.revision":"{apiproxy.revision}", "request.content-length":"{request_msg.header.content-length}", "request.content-type":"{request_msg.header.content-type}", "request.host":"{request_msg.header.host}", "request.httpversion": "{request.version}", "request.url": "{client.scheme}://{request_msg.header.host}{request_msg.uri}", "request.user-agent":"{request.header.user-agent}", "request.verb": "{request.verb}", "request.x-b3-traceid": "{request.header.x-b3-traceid}", "request.x-cloud-trace-context": "{request.header.x-cloud-trace-context}", "response.content-length":"{response.header.content-length}", "response.content-type":"{response.header.content-type}", "response.status.code": "{message.status.code}", "system.region.name": "{system.region.name}", "system.timestamp": "{system.timestamp}", "system.uuid": "{system.uuid}", "target.cn": "{target.cn}", "target.country": "{target.country}", "target.host": "{target.host}", "target.ip": "{target.ip}", "target.locality": "{target.locality}", "target.organization": "{target.organization}", "target.port": "{target.port}", "target.scheme": "{target.scheme}", "target.state": "{target.state}", "target.url": "{request.url}" } </Message> <ResourceType>api</ResourceType> </CloudLogging> </MessageLogging>
在 API 代理中将政策附加为条件步骤。一种方法是在 PostFlow 中的 FaultRule 中附加该政策,通常在 PostFlow 中会引发与安全相关的故障。例如:
<PostFlow name="PostFlow"> <Request> <Step> <Condition>flow.isError == true)</Condition> <Name>ML-CloudLoggingSecOps</Name> </Step> </Request> </PostFlow>
现在,当使用此政策的 API 代理执行时,Apigee 日志数据将流向 Google SecOps。
另一种常见做法是将 MessageLogging 政策放置在 ProxyEndpoint 响应的 PostClientFlow 中。
将 MessageLogging 政策附加到 API 代理时,请考虑以下建议:
- 将该政策放入 FaultRule 中。 建议在 FaultRule 中记录安全异常和违反政策的情况。
- 将政策放入 PostFlow 中。PostFlow 是另一个适合记录安全问题的位置。
- 避免记录成功的请求。对于侧重于威胁的安全监控,您通常会在出现问题(引发故障)时记录详细信息。记录包含完整消息内容的每个成功请求可能会生成过多日志并增加费用。
- 对于某些用例,不妨考虑使用自定义变量。例如,如果您需要在故障流程中捕获原始请求 URI,可以在请求预流程中使用 AssignMessage 政策将其复制到自定义变量(例如
original.request.uri
),然后在 MessageLogging 政策中记录该变量。
最佳做法
在使用 Google SecOps 配置 Apigee 时,请考虑以下最佳实践:
- 侧重于安全上下文:仅记录可为安全监控和威胁检测提供有价值上下文的流变量。避免过度记录与安全无关的数据。
- 使用一致的日志记录格式:在使用 SecOps 的 API 代理中保持一致的日志记录格式。
- 使用安全的服务账号:遵循安全最佳实践,管理和保护用于 SecOps 提取的 Google Cloud 服务账号。如果可能,请将权限限制为日志查看器。
- 监控 SecOps Feed:定期监控 SecOps Feed 的运行状况和状态,确保日志能够成功提取且没有错误。
- 使用 SecOps 规则和信息中心:将与安全相关的日志导入 SecOps 后,开发特定规则和信息中心,以便根据您正在记录的详细信息检测和直观呈现安全威胁。
问题排查
本部分介绍了在使用 SecOps 配置 Apigee 时可能会遇到的几种可能问题以及需要检查的事项。
问题:安全事件日志未显示在 Cloud Logging 中
需要检查的事项:
- 仔细检查您的 MessageLogging 政策是否已正确配置
Condition
,以便在发生安全事件时触发。 - 确保将 MessageLogging 政策附加到适当的流上下文,例如 FaultRule 或 PostFlow。
- 确认您的 Google Cloud 项目中已启用 Cloud Logging。
- 查看 Apigee 代理日志中与 MessageLogging 政策相关的任何错误消息。
问题:安全事件日志未显示在 SecOps 中
- 验证您的 SecOps Feed 是否已正确配置,并包含正确的项目 ID、日志过滤条件(确保它会捕获安全日志记录政策中的日志)和服务账号凭据。
- 在 SecOps 界面中检查 SecOps Feed 的状态,看看是否有任何错误消息或提取问题。
- 确保 SecOps 使用的服务账号在您的 Google Cloud 项目中具有 Logs Viewer 角色。
SecOps 中未正确解析与安全相关的字段
- 在 Cloud Logging 中查看日志的 JSON 结构,确保其格式正确且包含预期的字段名称。
- 确认已启用适当的 Google Cloud 解析器。
- 如果您怀疑存在解析问题,请检查 SecOps 原始数据中的示例日志条目,了解其在解析之前的提取方式。如果未按预期提取特定字段,您可能需要查看 SecOps 解析器文档,或考虑是否需要使用自定义解析器。
将 Apigee 与 Google SecOps SIEM 集成
下表将 Apigee 流变量名称与等效的 Google SecOps SIEM 字段名称进行了映射。例如,在 Cloud Logging 中查看 Apigee 日志数据时,client.id
流程变量会映射到名为 principle_ip
的 SecOps SIEM 字段。另请参阅收集 Apigee 日志。
Apigee 流变量 | SecOps SIEM 字段名称 | 说明 |
---|---|---|
client.country | principal.hostname | 与 ProxyEndpoint 收到的请求相关的 HTTP 主机 IP。 |
client.host | principal.location.country_or_region | 客户端应用提供的 TLS/SSL 证书中显示的国家/地区。 代理请求
principal.location.country_or_region 。 |
client.ip | principle.ip | 向负载均衡器发送消息的客户端或系统的 IP 地址。例如,该属性可以是原始客户端 IP,也可以是负载均衡器 IP。 |
client.locality | principal.location.city | 客户端提供的 TLS/SSL 证书中显示的市行政区(城市)。 |
client.port | principal.port | 与向 ProxyEndpoint 发出原始客户端请求相关的 HTTP 端口。 |
client.state | principal.location.state | 客户端提供的 TLS/SSL 证书中显示的状态。 |
organization.name | intermediary.cloud.project.name | Apigee 组织的名称。 |
proxy.client.ip | src.ip | 入站调用的 X-Forwarded-For 地址,即 Apigee 从上一个外部 TCP 握手收到的 IP 地址。这可以是调用客户端,也可以是负载均衡器。 |
proxy.name | intermediary.resource.name | 为 ProxyEndpoint 配置的名称属性。 |
proxy.pathsuffix | intermediary.resource.attribute.labels[pathsuffix] | “从客户端发送并在 ProxyEndpoint 接收的网址中的路径后缀值。 基本路径是最左侧的路径组件,可唯一标识环境组中的 API 代理。假设您配置了一个基本路径为 /v2/weatherapi 的 API 代理端点。在这种情况下,如果请求发送到 https://myhost.example.net/v2/weatherapi/forecastrss?w=12797282,proxy.pathsuffix 变量将保存字符串 /forecastrss。 |
proxy.url | intermediary.url | 获取与 ProxyEndpoint 收到的代理请求相关的完整网址,包括存在的任何查询参数。如需查看使用原始请求主机(而不是 proxy.url 中使用的路由器主机)构造请求网址的示例,请参阅访问请求消息。” |
request.uri | target.resource.name | 将响应返回到 API 代理的目标服务的域名。 |
request.verb | 用于请求的 HTTP 动词。例如,GET、PUT 和 DELETE。 | |
response.content | 目标返回的响应消息的载荷内容。 | |
response.status.code | 为请求返回的响应代码。您可以使用此变量替换存储在 message.status.code 中的响应状态代码。如需了解详情,请参阅相关消息。 | |
system.region.name | intermediary.location.name | 代理在其中运行的数据中心地区的名称。 |
system.timestamp | 64 位(长)整数,表示此变量被读取的时间。该值是从世界协调时间 (UTC) 1970 年 1 月 1 日午夜起到操作发生时所经过的毫秒数。例如,1534783015000。 | |
system.uuid | intermediary.process.pid 或 intermediary.process.product_specific_process_id | 处理代理的消息处理器的 UUID。 |
target.country | target.location.country_or_region | 目标服务器提供的 TLS/SSL 证书中显示的国家/地区 |
target.host | 将响应返回到 API 代理的目标服务的域名。 | |
target.ip | 将响应返回到 API 代理的目标服务的 IP 地址。 | |
target.locality | target.location.city | 目标服务器提供的 TLS/SSL 证书中显示的市行政区(城市) |
target.organization | 目标服务器提供的 TLS/SSL 证书中显示的组织。 | |
target.port | 将响应返回到 API 代理的目标服务的端口号。 | |
target.scheme | 根据请求消息返回 HTTP 或 HTTPS。 | |
target.state | target.location.state | 目标服务器提供的 TLS/SSL 证书中显示的状态。 |
target.url | 在 TargetEndpoint XML 文件或动态目标网址中配置的网址(前提是在消息流过程中已设置 target.url)。变量不包含任何其他路径元素或查询参数。如果调用超出范围或未设置,则返回 null。 注意:请使用附加到 TargetEndpoint 的 JavaScript 政策来设置此变量。 |