Files
homelab-infra/apps/hydra/README.md
T
2026-09-29 15:45:21 +00:00

7.9 KiB
Raw Blame History

Hydra 与独立 IAM 登录接入

本目录提供独立 Hydra 签发服务。当前分支将实验性 Hydra 登录入口接至 Spring iam-login 开发实例,由其执行 AD 密码、WebAuthn 和授权确认;不改变 issuer、Gitea 登录源或数据库。 旧 Go OIDC 适配器继续部署以便回退,Gitea 的直接 Authelia 登录源也保留。 该配置需经 PR 合并与 Flux 应用后才生效;下面原有 Go/Authelia 说明保留为回退路径资料。

Gitea → Hydra → iam-login(Tailscale 开发实例)→ Samba AD + WebAuthn

Spring 开发路径验收

源码版本:iam-login 5f49a7c。 开发 UI 是 https://laptop.tail7e769.ts.net:18082,已有 Passkey RP ID 保持不变。 Hydra 回调为 /oauth2/start、/oauth2/consent、/oauth2/logout;默认注销回到 /signin。 浏览器需要 Tailscale 连通性;开发服务暂由本地 JVM 容器运行,并非生产 Native 部署。

开发服务通过 kubectl -n hydra port-forward --address 127.0.0.1 service/hydra-admin 18445:4445 访问私有 Admin API。转发需在 Hydra 滚动更新后重连;验收运行器会循环重建该通道。 该通道与本地容器是临时验收依赖,必须保持运行;不修改 NetworkPolicy、 不新增 Admin HTTPRoute。临时运行配置与旧版回退备份仅保存在受限本地运行目录,不提交秘密。

验收前已只读核对目标 Gitea 账号的现有 Hydra 外部关联,并将旧 sub 显式绑定到 AD 稳定主体;不按邮箱重建关联、不修改 Gitea 账号或仓库权限。客户端管理仅允许有效 MFA 且 直接属于 AD Domain Admins 的用户;这是验收期明确指定的粗粒度管理组。

从 Gitea /user/oauth2/hydra 发起,应进入新密码/Passkey 页,确认授权后返回原账号,核对 仓库权限。当前 Gitea client 未登记 front/back-channel 或 post-logout 回调,不能声称 Gitea 会话会 随 IAM 注销。应用的注销协议兼容性需单独验收。旧 authelia 登录源始终保留。

开发配置关闭 Boot 默认 LDAP health indicator:它未配置目录连接,不对应同用户 bind 的 AD 仓储。总健康检查仍验证数据库,真实 AD 认证由本次人类登录验收,不将 readiness 当作 AD 凭据有效性的证明。

Hydra 的 login/consent URL 是全局配置,本次影响全部经 Hydra 的登录请求(当前接入 Gitea), 不影响直接走 Authelia 的应用。不要在无法访问 Tailscale 开发实例时合并此切换。 验收失败时 revert 本次回调变更,恢复旧 Go 的 /login、/consent;不删除客户端、签名密钥、 数据库、用户关联或 Passkey。最终 auth.ddupan.top 同源部署另开 PR,不在此次切换范围内。

原 Go/Authelia 路径与回退资料

目标入口:

  • https://hydra.ad.ddupan.top:Hydra 公共 OAuth2/OIDC endpoint。
  • https://hydra-login.ad.ddupan.top:上游 OIDC 登录及 consent 适配器。
  • hydra-admin.hydra.svc.cluster.local:4445:仅集群内管理接口,无 HTTPRoute。

均为 LAN/Tailscale 入口,复用 Envoy eg/https wildcard TLS。没有增加公网 tunnel。 部署及实际验收状态以 wiki 和对应 PR 为准,文件存在不表示登录已验收。

首次使用与边界

在 Gitea 登录页选择 hydra,跳转到 Authelia 完成现有人类认证,再返回原有 Gitea 账号。旧 authelia 登录源保留。Gitea 的账号关联和资源权限仍由 Gitea 维护。

适配器要求验证上游 issuer、audience、签名、过期时间和 nonce,使用 PKCE S256, 并把单次 state 绑定到 Secure/HttpOnly/SameSite=Lax cookie。短期登录事务只存内存, 最多 1024 个、10 分钟过期;单副本重启后正在登录的用户需重试,不存人类密码或 token。

Hydra subject 为上游 (issuer, sub) 的 SHA-256 加 human: 前缀,与可变邮箱/用户名 分离。第一轮要求上游返回经过验证的 email 及 preferred_username;这些 claims 必须 明确配置进 ID token。更换 issuer 会改变本 PoC 的 subject,正式迁移前需要身份绑定设计。

仅为显式 ALLOWED_CLIENTS=gitea 自动 consent,scope 限于 openid/profile/email/groups; 拒绝额外 access-token audience,不发 refresh token。只按实际请求 scope 释放 claims。 这不是通用的无人确认授权服务。组当前透传,沿用 Gitea 的 gitea-admins 映射;统一组 模型和 agent 认证均在后续阶段。不存在对 Authelia 专有协议的调用。

NetworkPolicy 限制公共端口只接收 Envoy 流量,Hydra admin 只允许适配器访问。 Hydra 使用正式模式,TLS 由 Envoy 终止;不使用 --dev。管理操作使用受控 kubectl port-forward,不要将 admin 接口暴露到 Gateway。

依赖、秘密与初始化

依赖共享 CloudNativePG、OpenBao/ESO、Authelia OIDC、Envoy、Samba DNS、zot 镜像仓库。 Hydra 使用独立 hydra database/role,不与其他应用共享数据库角色。

kv/k8s/hydra 保存 dsn、system_secret、upstream_client_secret、upstream_client_digest、 gitea_client_secret;通过 ExternalSecret 投射,值不写入 Git。Bootstrap 创建角色及数据库 后才启动 Hydra migration。system_secret 必须持久保存,不得在重启时随机重建。

Authelia 中新增 confidential client hydra-login:

  • redirect URI:https://hydra-login.ad.ddupan.top/callback;
  • authorization policy:two_factor;grant:authorization_code;PKCE:S256;
  • token endpoint auth:client_secret_basic;scope:openid/profile/email/groups;
  • claims policy:把 preferred_username、name、email、email_verified、groups 放入 ID token;
  • client secret 的 PBKDF2 digest 存入 Authelia,原值仅供适配器使用。

Authelia 尚非 Flux 管理。修改 Helm values 时保留所有已有 clients 与 secret 引用, 通过 --reuse-values 和最小 overlay 增加客户端,不能以本目录配置覆盖其完整 values。

Hydra 中注册 confidential client gitea,redirect URI 为 https://git.ddupan.top/user/oauth2/hydra/callback,grant/response 为 authorization_code/code, scope 为 openid/profile/email/groups,token endpoint auth 为 client_secret_basic。 Gitea 启动时读取 OIDC discovery,所以应先确认 Hydra 健康和 discovery 可达,再接入 Gitea。

构建与检查

cd apps/hydra/login-consent
go test -race ./...
go vet ./...
CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o login-consent .
docker build -t hydra-login-consent:VERSION .

Go module 独立,依赖由 go.sum 锁定;Dockerfile 固定基础镜像 digest。 使用已授权的短期 SPIFFE zot 凭据发布镜像,部署使用匿名拉取入口与不可变 digest。 不把 registry 凭据写入源码或 build args。

kubectl kustomize apps/hydra
sudo k3s kubectl -n hydra get deployment,pod,externalsecret,httproute
sudo k3s kubectl -n hydra logs deployment/hydra -c migrate
sudo k3s kubectl -n hydra logs deployment/hydra-login

日志不输出上游 token、授权 code、challenge 或秘密。登录失败先查两端 Pod 状态、 DNS/discovery 连通性、client redirect URI 和 scope,再由用户重新发起登录。 不要在故障排查中关闭签名验证、MFA 或 state/nonce 校验。

恢复与回退

保留共享 PostgreSQL 中 Hydra 数据及 OpenBao 秘密;数据库持有 clients、会话及签名密钥, 单独重建 Deployment 不能替代恢复数据库。先恢复依赖,再启动 Hydra 和适配器。 当前恢复仍依赖 homelab 共享基础设施,不能声称已完成独立灾备。

第一轮不切换 Authelia 的主入口。撤回 Gitea 的新增 Hydra 登录源即可回到旧入口; 先撤消费者,再考虑停用 Hydra。不要删除旧 Authelia 登录源、用户或数据库作为回退手段。

跨服务设计见 独立 IAM 草案。