Kiln 使用四类凭据,各自只负责一类访问:公开端点无需凭据,登录会话用于管理控制台,管理员 API 令牌用于脚本和自动化,路径式播放密钥用于播放器和播放列表分发。不同凭据的权限互不继承,也不能相互转换。
凭据总览
| 凭据 | 格式 | 适用场景 | 生命周期 |
|---|---|---|---|
| 公开端点 | 不带凭据 | 健康检查、指标、EPG、台标 | 不适用 |
| 登录会话 JWT | Authorization: Bearer <jwt>,Ed25519 签名 |
管理控制台、交互式调试 | token_ttl_hours(默认 24 小时),修改登录凭据后立即失效 |
| 管理员 API 令牌 | kiln_v1_ 前缀 + 48 位随机字符 |
脚本、CI、外部管理工具 | 创建时设定有效期,可轮换、可撤销 |
| 路径式播放密钥 | v1 前缀 + 126 位随机字符,写在 URL 路径里 |
播放器与播放列表分发 | 创建时设定有效期,可吊销 |
用户与角色
用户写在配置文件的 [[auth.users]] 数组里,至少需要一个,否则启动时校验失败。每个用户必须提供 username、password_hash 和 role,用户名不可重复。
[[auth.users]]
username = "admin"
password_hash = "$2a$10$..."
role = "admin"
[[auth.users]]
username = "operator"
password_hash = "$2a$10$..."
role = "viewer"
channel_ids = ["demo-hls", "demo-dash"]role = "admin" 拥有全部权限,也是进入管理控制台的门槛:控制台在登录后会再查一次 /v1/me,角色不是 admin 就会被退回登录页。其它角色受 channel_ids 约束,只能在频道列表、播放列表和运行状态里看到并播放列出的频道;channel_ids 留空表示不限制频道。
口令以 bcrypt 哈希保存,配置里不出现明文。生成哈希:
make hash PASSWORD='your-password'go run scripts/hash-password.go 'your-password'会话 JWT
登录端点 POST /v1/auth/login 用用户名和口令换一枚 Ed25519 签名的 JWT,响应里同时给出过期时间、用户名和角色。
curl -s http://127.0.0.1:8080/v1/auth/login \
-H 'content-type: application/json' \
-d '{"username":"admin","password":"your-password"}'签名密钥
签名算法固定为 EdDSA,服务端按下面的顺序解析私钥,先命中者生效:
配置内联 PEM
auth.token_private_key,或环境变量 KILN_TOKEN_PRIVATE_KEY。
密钥文件路径
auth.token_private_key_file,或环境变量 KILN_TOKEN_PRIVATE_KEY_FILE。
数据目录自动生成
以上都没有时,读取 {data_dir}/auth/ed25519.pem;文件不存在就地生成一对新密钥,私钥权限 0600,公钥写到 {data_dir}/auth/ed25519.pub.pem。
公钥是可选的:不填就从私钥推导。如果同时提供了 token_public_key 或 token_public_key_file,服务端会校验它与私钥匹配,不匹配直接启动失败。私钥、私钥文件和 server.data_dir 三者必须至少有一个,否则配置校验不通过。
手动生成一对密钥:
go run scripts/gen-jwt-keys.go ./secrets # 写出 ed25519.pem / ed25519.pub.pem校验规则与限流
- 签发的令牌带
iss、aud、exp、iat、nbf、sub和唯一的随机jti;校验时四项时间断言全部生效,允许 30 秒时钟偏差。 token_issuer与token_audience默认都是kiln,校验时必须与签发时一致。改了这两项,历史令牌全部作废。token_ttl_hours默认 24,取值小于等于 0 时按 24 小时处理。- 登录限流按客户端 IP 计数,
login_rate_per_min默认每分钟 20 次,超出返回 429。修改登录凭据的接口另有一条按「用户名 + IP」计数的限流。 - 管理控制台用于「预览」的临时令牌是一种特殊会话:只绑定单个频道、默认 5 分钟过期,且被管理接口显式拒绝,只能用于播放。
管理员 API 令牌
会话 JWT 供浏览器使用,不适合交给脚本。长期自动化请在管理控制台的「设置 → 管理员 API 令牌」中创建独立凭据。
签发与保管
明文形如 kiln_v1_ 加 48 位随机字符,只在创建(或轮换)后展示一次。服务端只保存它的 SHA-256 摘要,外加一段用于识别的前缀,因此没有任何接口能把明文找回来,丢了就只能轮换。
curl -s http://127.0.0.1:8080/v1/admin/channels \
-H "authorization: Bearer kiln_v1_..." | jq四种权限
权限互不隐含,按用途勾选:
read
读取频道、设置、出口配置与各类日志。
write
新增与修改配置,包括导入导出 M3U,但不能删除。
delete
删除频道与出口条目、吊销播放密钥、清空访问日志。
refresh
探测节目源、刷新 EPG、预热与预览频道、停止会话、测试网络出口。
有效期、轮换与撤销
- 有效期在创建时设定,也可以后续调整,上限 10 年;不设则永不过期。
- 轮换保留名称、权限和有效期,只换掉随机值,旧值立即失效,新明文同样只显示一次。替换泄露的凭据优先用轮换。
- 撤销不可恢复,之后所有使用该 Token 的请求都会得到 401。
- 删除记录会让 Token 立即失效并从列表里消失,但审计日志中已记录的前缀快照仍会保留。
- 编辑、轮换、撤销、删除都要求携带
If-Match头传入当前revision,缺失或过期返回 409,避免两个管理端并发覆盖。
审计日志
每一次使用管理员 API 令牌的请求都会留下记录,无论获准还是被拒。记录包括令牌前缀、方法与路径、所需权限、判定结果与拒绝原因、HTTP 状态、客户端地址、User-Agent 和请求编号。控制台会在同一张卡片下方显示最近的调用记录。
拒绝原因是固定的几种,便于定位:
| 原因 | 状态 | 含义 |
|---|---|---|
revoked |
401 | Token 已撤销或被停用 |
expired |
401 | Token 已过期 |
session_required |
403 | 该路由只认登录会话 |
route_not_available |
403 | 该路由未登记给 API Token |
missing_scope |
403 | Token 缺少这条路由所需的权限 |
边界
修改登录凭据
PUT /v1/me/credentials 用于改用户名或口令,只接受管理员登录会话,API Token 调用会被拒绝。请求必须带当前口令,新口令长度为 8 到 72 字节,用户名不超过 64 个字符且不能含控制字符。
保存成功后会做三件事:把新凭据作为覆盖项写入状态库、递增该账户的凭据版本号、返回一枚全新的会话令牌。版本号递增意味着此前签发的所有会话立即作废,其他设备会被登出。在管理控制台里,这个操作在「系统设置 → 账户与语言」或右上角账户菜单里。
[security] 的安全语义
[security]
play_require_auth = true
allowed_hosts = []
# cors_origins = ["http://127.0.0.1:5173"]
# public_hosts = ["kiln.lan", "origin.example.com", "localhost"]
max_playlist_bytes = 8388608
max_body_bytes = 1048576| 键 | 作用 |
|---|---|
play_require_auth |
播放端点是否需要凭据,默认开启。关闭后 /v1/play/ 下的地址对任何人可用,仅供本机调试;环境变量 KILN_PLAY_OPEN=1 是同一个开关 |
allowed_hosts |
出站私网豁免列表。解析到回环或私有地址的源站主机名与 IP 必须显式加入,上游与频道声明不会自动豁免 |
public_hosts |
入站白名单,按请求的 Host 头判定。非空时不在列表内的请求一律 403,回环地址上的健康检查除外;留空表示不限制 |
cors_origins |
允许携带凭据跨源访问的来源列表。留空表示只允许同源,浏览器侧不会收到任何 CORS 响应头 |
max_playlist_bytes |
单个上游播放列表的读取上限,默认 8 MiB,防止超大清单拖垮内存 |
max_body_bytes |
管理接口请求体的读取上限,默认 1 MiB;导入类接口按倍数放宽 |
管理接口的响应还会带上 X-Content-Type-Options、Referrer-Policy、X-Frame-Options: DENY、严格的 Content-Security-Policy 与禁止存储的缓存策略。EPG、台标和不可变媒体响应使用各自的缓存规则。X-Frame-Options 可防止管理控制台被嵌入第三方页面。
播放密钥
播放密钥是给播放器和播放列表分发用的独立凭据:它出现在 URL 路径里(/p/{token}/...),可以限定频道范围与有效期,可以随时吊销,每次取用都会记入播放访问日志,日志中的路径只保留密钥前缀。它与登录凭据完全隔离,把播放地址交给第三方设备也不会泄露管理权限。
创建、吊销与访问日志都在管理控制台的「访问控制」里,用法见 播放与分发。
生产加固清单
换掉示例口令
示例配置里的 admin / admin 只用于第一次启动。用 make hash 生成新的 bcrypt 哈希替换 password_hash,或登录后直接在控制台里改。
固定 JWT 签名密钥
生产环境显式配置 token_private_key_file 或 KILN_TOKEN_PRIVATE_KEY_FILE,把密钥纳入备份与轮换流程。依赖数据目录自动生成的密钥会随目录一起丢失,届时所有会话失效。
保持 play_require_auth 开启
确认没有在环境里遗留 KILN_PLAY_OPEN=1。对外分发用播放密钥,不要关闭播放鉴权。
收紧主机白名单
用 public_hosts 限定对外域名。只有确需访问回环或私网源站时,才把对应主机名或 IP 显式加入 allowed_hosts;频道配置不会替代这一步。
给自动化独立 Token
脚本一律使用管理员 API 令牌,按用途授予最小权限并设置有效期,定期轮换,并通过审计日志核对调用来源。