关于 ecs-field-mappings
用于在 Elastic 集成包中选择和定义 Elastic Common Schema(ECS)字段的 Skill,涵盖字段文件、映射、事件分类、时间戳及验证相关指引。
主要功能
- 01ECS 字段选择指引
- 02集成字段文件规范
- 03事件分类指引
- 04时间戳映射指引
- 05字段映射验证建议
适用场景
- 01为集成包添加字段
- 02将源事件映射到 ECS
- 03排查字段映射检查问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ elastic/ integration-skills --skill ecs-field-mappings安装后在 Claude Code 中输入/ecs-field-mappings确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/categorization-cheatsheet.mdcdr-field-requirements.mdfieldset-links.mdmapping-type-matrix.mdroot-and-core-fields.md详细介绍
ecs-field-mappings
适用场景
在以下任务中使用此技能:
- 添加或修改
data_stream/<stream>/fields/下的文件 - 使用 ECS 字段引用填充
ecs.yml - 选择
event.kind、event.category、event.type和event.outcome的值 - 选择字段
type和映射属性(metric_type、dimension、multi_fields及相关选项) - 添加自定义字段前,检查 ECS 中是否已存在该字段
- 排查
elastic-package check、elastic-package lint或管道测试架构检查导致的映射验证/构建失败
ECS 依赖配置
每个 package 都需要在 package 根目录下有 _dev/build/build.yml。此文件会固定用于字段解析的 ECS 架构版本。
dependencies:
ecs:
reference: "[email protected]"
只要 package 中有任何字段文件,此文件就是必需的。脚手架不会生成此文件 — 请手动创建。如果缺少此文件或其中的版本过时,测试会将 ECS 字段报告为未定义(例如,field "destination.ip" is undefined)。
字段文件及其职责
数据流的 fields/ 目录包含少量 YAML 文件,各自负责不同的内容:
base-fields.yml
固定的路由常量和 @timestamp。这六个字段都是 ECS 字段,因此每个条目都使用 external: ecs。当数据流需要使用固定值的 constant_keyword 时,覆盖 type 和 value — 描述会自动继承自 ECS。
- name: data_stream.type
external: ecs
- name: data_stream.dataset
external: ecs
- name: data_stream.namespace
external: ecs
- name: event.module
external: ecs
type: constant_keyword
value: <package_name>
- name: event.dataset
external: ecs
type: constant_keyword
value: <package_name>.<stream_name>
- name: '@timestamp'
external: ecs
不要在此处添加其他字段。base-fields.yml 中只能包含这些路由常量和 @timestamp。
constant_keyword 候选字段
对于数据流中的每个文档都只有一个值的字段,应使用 constant_keyword。除 base-fields.yml 中的路由常量外,还应评估以下字段:
| 字段 | 使用 constant_keyword 的原因 |
|---|---|
event.dataset | 按定义,每个数据流只有一个值 |
event.module | 每个 package 只有一个值 |
data_stream.type | 每个数据流固定为 logs/metrics |
data_stream.dataset | 每个数据流固定 |
data_stream.namespace | 在部署时设置,在索引中保持不变 |
observer.vendor | 一个 package 对应一个供应商 |
observer.product | 一个 package 对应一个产品 |
当 constant_keyword 字段也是 ECS 字段时(例如 observer.vendor),请使用 external: ecs 并覆盖类型。这样会继承 ECS 中的描述,并避免手动重复。请将定义放在相应的字段文件中(大多数 ECS 字段放在 ecs.yml 中,路由常量放在 base-fields.yml 中):
- name: observer.vendor
external: ecs
type: constant_keyword
value: Acme Corp
**remove_from_source 选项:**由于 constant_keyword 会将值存储一次在索引元数据中,因此不需要在每个文档的 _source 中都包含该值。Elasticsearch 会自动处理 — 无需显式配置 _source.excludes。当值始终相同时,这可以节省存储空间。
ecs.yml
在此文件中填入流水线设置的、动态映射无法推断的 ECS 字段。 每个条目只能使用 name 和 external: ecs,不要添加类型或描述。类型会通过 _dev/build/build.yml 从 ECS 架构解析。
对于 conditions.kibana.version 下限 >= 8.13.0 的软件包,ecs@mappings 组件模板会动态映射标准 keyword/date 字段以及标准前缀的地理位置 ECS 字段,因此只有对于无法推断的类型(非标准父级前缀上的 geo_point、geo_shape、nested、flattened),或 elastic-package验证失败的情况,才需要显式声明。判断依据是 Kibana 版本约束,而非软件包规范版本——从 8.13 起,安装时由 Stack 应用ecs@mappings;如果某个 spec-3.x 软件包仍允许安装 8.11/8.12,那么这些版本不会应用该模板,因此此类软件包仍需声明流水线设置的所有 ECS 字段。对于构建器而言,声明更多字段没有坏处,但审核者绝不能要求添加这些声明;现有声明也不应被认定为可删除的冗余内容(参见 review-integration/references/conflict-resolutions.md`)。
如果要声明名称已存在于 ECS 中的字段,必须使用 external: ecs(Wiki 参考)。这适用于所有字段文件——ecs.yml、base-fields.yml,以及任何定义 ECS 字段的文件。仍可覆盖属性(例如 type: constant_keyword、value:),同时使用 external: ecs;描述会继承自 ECS。不要在 fields.yml、agent.yml 或 beats.yml 中使用 external: ecs——这些文件定义的是非 ECS 字段。
- name: event.kind
external: ecs
- name: event.category
external: ecs
- name: event.type
external: ecs
- name: event.outcome
external: ecs
- name: event.action
external: ecs
- name: source.ip
external: ecs
- name: source.port
external: ecs
- name: destination.ip
external: ecs
- name: user.name
external: ecs
- name: related.ip
external: ecs
- name: related.user
external: ecs
为 ECS 字段添加额外元数据时(例如将字段设为 TSDB 维度,或设为具有固定值的 constant_keyword),应将 external: ecs 与该元数据合并使用。描述会继承自 ECS。将定义放在 ecs.yml 中(路由常量则放在 base-fields.yml 中):
- name: observer.vendor
external: ecs
type: constant_keyword
value: Acme Corp
fields.yml
仅包含集成专属的自定义(非 ECS)字段。使用嵌套的 group 层级表示供应商命名空间:
- name: acme.firewall
type: group
fields:
- name: rule_id
type: keyword
- name: policy_name
type: keyword
- name: bytes_in
type: long
unit: byte
metric_type: gauge
无需将组声明为 type: object——定义带有嵌套 fields 的 group 即可。对象结构是隐式的。
labels.* 例外
labels 是 ECS 核心对象(type: object、object_type: keyword),专为临时键值元数据设计。labels.* 下的子键无需使用供应商命名空间——这是供应商前缀规则的唯一例外。
简单的 keyword 标记或集成内部标记(例如 labels.is_ioc_transform_source)应使用 labels.*。来自上游数据源的结构化或嵌套数据应使用供应商命名空间。
标记与结构化数据
布尔标记和简单标签可以直接放在供应商组下:
- name: acme.firewall
type: group
fields:
- name: is_encrypted
type: boolean
- name: policy_name
type: keyword
来自数据源的结构化数据应使用子组构建逻辑层级:
- name: acme.firewall
type: group
fields:
- name: rule
type: group
fields:
- name: id
type: keyword
- name: name
type: keyword
- name: action
type: keyword
agent.yml
由 Elastic Agent 或 Beats 框架填充、但 ECS 未涵盖的非 ECS 字段。仅在输入类型会生成这些字段时添加。常见字段:cloud.image.id、cloud.instance.id、host.containerized、host.os.build、host.os.codename、input.type、log.offset。
完整 YAML 示例请参见 references/root-and-core-fields.md。
beats.yml
ECS 未涵盖的 Filebeat/Beats 专属字段。最简形式包含 input.type 和 log.offset。某些输入还会生成 log.flags 或 log.file.* 子字段。
完整 YAML 示例请参见 references/root-and-core-fields.md。
ECS 字段选择
只要语义相符,就优先使用 ECS 字段。如果数据没有对应的 ECS 字段,则在 fields.yml 中将其添加到软件包命名空间下。
分类速查
| 字段 | 类型 | 说明 |
|---|---|---|
event.kind | keyword | 最高级别的分类。 |
event.category | keyword[] | 广泛的领域类别——始终为数组。 |
event.type | keyword[] | 类别下的子类别——始终为数组。 |
event.outcome | keyword | success、failure、unknown;仅在有意义时设置。 |
event.kind:alert、asset、enrichment、event、metric、pipeline_error、signal、stateevent.category:api、authentication、configuration、database、driver、email、file、host、iam、intrusion_detection、library、malware、network、package、process、registry、session、threat、vulnerability、webevent.type:access、admin、allowed、change、connection、creation、deletion、denied、device、end、error、group、indicator、info、installation、protocol、start、user
决策流程:
event.kind:普通日志使用event,测量值使用metric,关于某个事物的定期分类观察结果使用state(例如 CDR 状况/合规性发现),实体/清单快照记录使用asset——每个集合周期、每个实体对应一份文档(参见entity-mappings技能),on_failure中使用pipeline_errorevent.category:选择一个或多个值(数组),表示广泛的领域event.type:选择一个或多个值(数组),表示操作类型event.outcome:仅在明确适用成功/失败/未知时设置;信息类/指标类事件应省略- 如果没有符合条件的值,请将字段留空——不要自行编造值
对于源特有的动词(blocked、dropped、authenticated),请使用 event.action。
完整示例请参见 references/categorization-cheatsheet.md。
时间戳字段
ECS 定义了多个语义各异的时间戳字段。请正确使用:
| 字段 | 使用时机 | 设置方 |
|---|---|---|
@timestamp | 主要事件时间戳。从源事件数据中解析。必填。 | 集成管道 |
event.created | 如果与 @timestamp 不同,则表示源系统首次创建或记录事件的时间。 | 集成管道 |
event.start | 活动或时段开始的时间(例如,会话开始、连接开始)。 | 集成管道 |
event.end | 活动或时段结束的时间(例如,会话结束、连接关闭)。 | 集成管道 |
event.ingested | 事件写入 Elasticsearch 的时间。 | Elasticsearch(集成之外) |
集成管道绝不能设置 event.ingested。 该字段由 Elasticsearch 的最终管道自动管理。不要为 event.ingested 添加 set 处理器。
当源数据包含多个时间戳时:
- 将主要事件时间戳映射到
@timestamp。 - 如果另一个时间戳表示事件首次记录/创建的时间,则将其映射到
event.created。 - 如果时间戳表示活动的开始或结束,则将其映射到
event.start和event.end。 - 如果某个时间戳不符合上述任何字段的语义,则将其映射到供应商命名空间下的自定义字段,并在
fields.yml中将type设为date。
可复用的字段集嵌套规则
某些 ECS 字段集必须嵌套在父实体下,不能放在文档根级别。
geo — 必须嵌套在以下字段下:client.geo、destination.geo、host.geo、observer.geo、server.geo、source.geo、threat.indicator.geo
根级别的 geo.* 字段无法识别,会显示为未映射。务必在 geoip 处理器上设置 target_field:
- geoip:
field: source.ip
target_field: source.geo
ignore_missing: true
as(自治系统)— 嵌套在以下字段下:client.as、destination.as、server.as、source.as
使用 geoip 进行地理定位时,务必同时使用 GeoLite2-ASN.mmdb 执行 ASN 查询,并将原始输出字段重命名为 ECS 字段名。geoip ASN 处理器会输出 asn 和 organization_name,必须将它们重命名为 as.number 和 as.organization.name:
- geoip:
database_file: GeoLite2-ASN.mmdb
field: source.ip
target_field: source.as
properties:
- asn
- organization_name
ignore_missing: true
- rename:
field: source.as.asn
target_field: source.as.number
ignore_missing: true
- rename:
field: source.as.organization_name
target_field: source.as.organization.name
ignore_missing: true
有关同时包含源和目标的完整 geo+ASN 模式,请参阅 ingest-pipelines 技能 → references/processor-cookbook.md。
os — 嵌套在以下字段下:host.os、observer.os、user_agent.os
entity(测试版;叶字段要求 ECS v9.4.0+)— 嵌套在以下字段下:user.entity、host.entity、service.entity、cloud.entity、orchestrator.entity、根级别 entity、entity.target。切勿臆造 device.entity.*,它不是有效的父字段。对于实体数据流(即 event.kind: asset 的数据流),请参阅 entity-mappings 技能,了解完整的字段目录、管道模式和 ECS 可用性矩阵。
嵌套(对象数组)ECS 字段
部分 ECS 字段使用 type: nested,表示它们包含一个对象数组,其中每个对象会将相关子字段组合在一起。管道必须生成这种结构,不要将其扁平化为并行的标量数组。
使用 nested 类型的 ECS 字段:
| 字段 | 包含内容 |
|---|---|
email.attachments | file.name、file.size、file.extension、file.mime_type、file.hash.* |
threat.enrichments | indicator.*、matched.* |
threat.indicator.file.elf.sections | name、physical_size、virtual_size 等 |
threat.indicator.file.pe.sections | name、physical_size、virtual_size 等 |
process.elf.sections | name、physical_size、virtual_size 等 |
process.pe.sections | name、physical_size、virtual_size 等 |
反面示例 — 并行数组(错误):
{
"email": {
"attachments": {
"file": {
"name": ["a.pdf", "b.pdf"],
"size": [1024, 2048]
}
}
}
}
这会丢失每个附件的名称与大小之间的对应关系,查询也无法单独筛选各个对象。
正确示例 — 对象数组:
{
"email": {
"attachments": [
{ "file": { "name": "a.pdf", "size": 1024 } },
{ "file": { "name": "b.pdf", "size": 2048 } }
]
}
}
**ecs.yml 声明:**仅声明父级 nested 字段,并设置 external: ecs。子字段(email.attachments.file.name 等)会继承 ECS 架构中的类型,不要逐一重新声明。
- name: email.attachments
external: ecs
**管道构建:**如果源数据以单独的并行数组形式提供附件元数据(例如,以逗号分隔的文件名列表和单独的大小列表),请使用 script 处理器将它们合并为对象数组。有关数组构建模式,请参阅 ingest-pipelines → references/painless-patterns.md;有关遍历数组元素,请参阅 references/processor-cookbook.md → Foreach 语义。
- script:
tag: build_email_attachments
description: Build email.attachments as array of nested objects from parallel source arrays.
lang: painless
if: ctx.json?.file_names instanceof List && ctx.json?.file_sizes instanceof List
source: |-
def names = ctx.json.file_names;
def sizes = ctx.json.file_sizes;
int len = Math.min(names.size(), sizes.size());
def attachments = new ArrayList(len);
for (int i = 0; i < len; i++) {
def attachment = new HashMap();
def file = new HashMap();
file.put('name', names.get(i));
file.put('size', sizes.get(i));
attachment.put('file', file);
attachments.add(attachment);
}
ctx.email = ctx.email ?: [:];
ctx.email.attachments = attachments;
如果源数据已经将每个附件作为单独对象提供(例如,附件对象的 JSON 数组),则无需合并数组,可直接使用 rename 或带有 copy_from 的 set 将数组放入 email.attachments。
自定义字段类型
对于 fields.yml 中的非 ECS 字段:
- 标识符和精确匹配的字符串使用
keyword - 固定值(数据集/模块常量)使用
constant_keyword - 指标和数值使用
long、double、scaled_float - 时间戳使用
date/date_nanos(仅在确实需要亚毫秒精度时使用date_nanos) - IP 地址使用
ip - true/false 值使用
boolean(避免在管道中使用字符串形式的布尔值) - 经纬度坐标使用
geo_point - 逻辑结构使用带有嵌套
fields的group——无需单独声明中间object节点 - 键未知的任意键值集合使用
flattened - 每个对象都需要独立查询隔离的对象数组使用
nested(开销高于group) - 全文内容使用
text/match_only_text;如果还需要聚合,则通过multi_fields添加keyword子字段
数值字段的实用属性:metric_type(gauge 或 counter)、unit(例如 byte、percent、ms)、用于低基数 TSDB 字段的 dimension。
完整类型参考请参阅 references/mapping-type-matrix.md。
字段命名约定
| 规则 | 应该 | 不应该 |
|---|---|---|
| 使用 snake_case | user_name、request_count | userName、RequestCount |
| 使用小写字母 | source_ip | Source_IP |
| 名称中不含星号 | network.bytes | network.*(字面星号) |
| 使用分组表示层级 | vendor.module.field 作为嵌套分组 | vendor.module.field 作为扁平点分隔名称 |
字段名绝不能包含字面字符 *。字段名中的星号几乎总是从文档或通配符模式中复制粘贴时出错所致。对于动态键,请改用包含已知子字段的 group 或 flattened。
点分隔字段名与嵌套分组
这两种形式在字段文件中都有效:
# Dotted (flat) — common for ECS fields in ecs.yml
- name: source.ip
external: ecs
# Nested group — common for custom fields
- name: acme.firewall
type: group
fields:
- name: rule_id
type: keyword
无论源数据如何表示字段,管道预期输出(*-expected.json)始终使用嵌套对象形式。源数据 "host.name": "myhost" 会在输出中生成 {"host": {"name": "myhost"}}。
当源数据包含 Elasticsearch 原本会展开的字面点分隔键时,请使用 dot_expander:
- dot_expander:
field: "*"
override: true
geo_point 字段处理
在管道测试预期输出中,geo_point 字段以包含 lat 和 lon 键的对象形式出现:
"source": {
"geo": {
"location": { "lat": 51.5142, "lon": -0.0931 },
"city_name": "London",
"country_iso_code": "GB"
}
}
这些子字段无需在 fields.yml 中配置条目——它们属于 geo_point 类型映射的一部分。对于 ecs@mappings 未涵盖的非标准父级前缀,只有 *.geo.location 字段(类型为 geo_point)需要写入 ecs.yml。(安装时,版本 >= 8.13 的 stacks 会应用 ecs@mappings;只有当 conditions.kibana.version 的下限 >= 8.13.0 时才能保证应用。)
常见管道分类模式
Web 访问
- set:
field: event.kind
value: event
- append:
field: event.category
value: web
- append:
field: event.type
value: access
根据 HTTP 状态确定结果
- set:
field: event.outcome
value: success
if: "ctx?.http?.response?.status_code != null && ctx.http.response.status_code < 400"
- set:
field: event.outcome
value: failure
if: "ctx?.http?.response?.status_code != null && ctx.http.response.status_code >= 400"
管道错误回退
on_failure:
- set:
field: event.kind
value: pipeline_error
故障排查:“ECS 字段 field X 未定义”
当测试报告标准 ECS 字段 field "destination.ip" is undefined 时:
- 检查包根目录中是否存在
_dev/build/build.yml - 检查是否已设置
dependencies.ecs.reference(使用[email protected]) - 检查
ecs.yml中是否列出了该字段,且设置了external: ecs
请修复根本原因。不要通过以下方式绕过问题:
- 在
fields.yml中添加完整类型定义的 ECS 字段,却不设置external: ecs - 跳过
external: ecs,手动定义 ECS 字段类型/描述
例外: 被报告为未定义的自定义(非 ECS)字段必须在 fields.yml 中定义。
常见失败模式
- 缺少
_dev/build/build.yml— 所有 ECS 字段都报告为未定义;创建该文件并添加dependencies.ecs.reference build.yml中的 ECS 版本过旧 — 较新 ECS 版本中的字段未定义;将引用更新为[email protected]- 流水线中设置了 ECS 字段,但
ecs.yml中缺少该字段 — 测试架构验证中该字段未定义;将其添加到ecs.yml - 定义 ECS 字段时未设置
external: ecs— 描述和类型会与 ECS 不一致;ECS 字段始终使用external: ecs,并按需覆盖 - 在非数值字段上使用
metric_type— lint 错误 - 在文档根级别使用
geo.*— 无法映射;始终将其嵌套在父实体下 - 将
event.category或event.type设置为标量 — 必须使用append处理器,而非set - 将 ECS
nested字段映射为并行数组 —email.attachments、threat.enrichments及类似的nested字段必须是对象数组,而不能是包含并行标量数组的对象;请参阅上文的 Nested(对象数组)ECS 字段部分 - 在
[email protected]中为entity.attributes.*/entity.relationships.*设置external: ecs— 这些叶字段在 ECS v9.3.0 中不存在(attributes是普通的object;entity_reference字段集不存在)。这些字段最早出现在 v9.4.0。在[email protected]中对它们使用external: ecs会导致field is undefined错误。包含实体数据流的包必须在_dev/build/build.yml中固定使用[email protected],并在流水线中匹配设置ecs.version: 9.5.0。请参阅entity-mappings技能。
验证循环
elastic-package lint
elastic-package check
elastic-package test pipeline --data-streams <stream>
参考资料
references/mapping-type-matrix.mdreferences/categorization-cheatsheet.mdreferences/root-and-core-fields.mdreferences/fieldset-links.mdreferences/cdr-field-requirements.md— 仅适用于云安全 / CDR 集成(cloudsecurity_cdr类别)entity-mappings/references/entity-field-catalog.md— ECSentity.*字段;仅适用于实体 / 清单数据流- ECS 字段参考