PAYATHON 2026

Netdata API 启用 bearer token protection 后返回 412,如何解决?

数据阿明

结论

在 User Settings 中创建的 scope:all Token 用于 Cloud API。访问启用了 bearer token protection 的本地 Agent REST API,需要为目标 Agent 签发的 bearer token。scope:all 扩大的是 Cloud Token 的权限范围,不能将它直接用作本地 Agent 的访问凭据。官方 API Tokens 文档

原来的 Guzzle 写法已经设置了 Authorization: Bearer ...,而且 curl 在本机得到相同结果。应先检查凭据类型,再考虑 PHP 请求格式。

为什么页面能打开,API 却返回 412?

启用保护后,静态页面和少量用于初始化、认证的 API 仍可公开访问。因此,能打开仪表盘并不代表数据接口已经通过认证。Agent 的 bearer 保护依赖 Netdata Cloud 认证,要求 Agent 已完成 claim、ACLK 连接正常,并且用户有权访问 Agent 所属的 Space。官方 bearer token protection 文档

这里的 412 及错误正文表明认证要求未满足,不能仅按通用 HTTP 条件请求失败处理。Netdata 的排查文档也将这类 412 列为 bearer 认证问题。官方认证故障说明

获取目标 Agent 的 token

Netdata 官方仓库中的客户端先读取 Agent 身份信息,再使用 Cloud API Token 向 Cloud 换取该 Agent 的 bearer token,最后携带返回的 token 请求 Agent。官方客户端实现

下面的示例需要安装 jq,并提前在环境变量 NETDATA_CLOUD_TOKEN 中设置已有的 Cloud API Token。在 Agent 所在服务器上运行:

AGENT_URL='http://127.0.0.1:19999'

INFO=$(curl -fsS "$AGENT_URL/api/v3/info")
NODE_ID=$(printf '%s' "$INFO" | jq -er '.agents[0].nd')
MACHINE_GUID=$(printf '%s' "$INFO" | jq -er '.agents[0].mg')
CLAIM_ID=$(printf '%s' "$INFO" | jq -er '.agents[0].cloud.claim_id')

确认三项均已取得后,向 Cloud 换取凭据:

TOKEN_RESPONSE=$(curl -fsS --get \
  'https://app.netdata.cloud/api/v2/bearer_get_token' \
  -H "Authorization: Bearer ${NETDATA_CLOUD_TOKEN}" \
  --data-urlencode "node_id=${NODE_ID}" \
  --data-urlencode "machine_guid=${MACHINE_GUID}" \
  --data-urlencode "claim_id=${CLAIM_ID}")

NETDATA_AGENT_BEARER_TOKEN=$(printf '%s' "$TOKEN_RESPONSE" | jq -er '.token')
export NETDATA_AGENT_BEARER_TOKEN

curl -i \
  -H 'Accept: application/json' \
  -H "Authorization: Bearer ${NETDATA_AGENT_BEARER_TOKEN}" \
  "$AGENT_URL/api/v1/alarms"

如果某一步失败,先处理该步骤的问题,再继续请求,以免使用空变量。原问题没有提供 Netdata 版本;上述字段和换取流程依据当前官方实现。如果实际响应结构不同,应按所用版本确认接口,不要猜测字段或标识符。

在 Guzzle 中使用换取的凭据

PHP 请求应使用换取后的 Agent token。以下示例假设 PHP 进程已获得环境变量 NETDATA_AGENT_BEARER_TOKEN,并且与 Agent 运行在同一台主机:

$agentBearerToken = getenv('NETDATA_AGENT_BEARER_TOKEN');

if (!$agentBearerToken) {
    throw new RuntimeException('Missing Netdata Agent bearer token');
}

$client = new GuzzleHttp\Client();
$response = $client->get('http://127.0.0.1:19999/api/v1/alarms', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer ' . $agentBearerToken,
    ],
]);

终端中的 export 不会自动更新已经运行的 PHP-FPM、容器或其他服务的环境变量。需要通过应用实际使用的配置渠道传入凭据。

仍然失败时检查什么?

  • Agent 身份字段缺失:先确认 Agent 已完成 claim,并检查 Cloud 连接。可以使用 sudo netdatacli aclk-state 辅助诊断。
  • Cloud 换取请求失败:检查 Cloud Token、账号对目标 Space 的访问权限,以及三个身份参数是否属于当前目标 Agent。
  • 换取成功但本地仍返回 412:确认请求使用的是返回的 token,并检查 token 是否过期、目标是否一致。经过反向代理时,还要确认 Authorization 请求头被正确转发。

Agent token 有有效期,持续运行的程序应根据返回的过期信息管理缓存和更新。跨主机传输凭据时使用 HTTPS;示例中的 HTTP 地址仅用于本机回环访问。保留 bearer token protection = yes,通过认证流程访问即可,无需为了让请求成功而直接公开数据接口。

备注:内容仅供参考。