土法炼钢兴趣小组的算法知识备份

【零信任安全架构】身份感知代理:Google IAP、Pomerium 与零信任的入口

文章导航

分类入口
architecturesecurity
标签入口
#iap#identity-aware-proxy#pomerium#google-iap#oauth2-proxy#jwt#header-injection#zero-trust

目录

在 Google BeyondCorp 的架构成熟之后,一个最直接的问题是:怎么让”每个请求都经过认证和授权”而不需要修改每个应用? 答案就是身份感知代理(Identity-Aware Proxy,IAP)——一个部署在应用前面的反向代理,承担所有认证和授权的逻辑,向后端传递已验证的用户身份。

前置阅读:NIST SP 800-207 架构拆解BeyondCorp 六篇论文全景

一、核心思想:把认证从应用中剥离

传统模型下,每个应用自己处理认证——检查 Cookie/Session、重定向到 SSO、处理回调。这个模型的累积成本很高:公司内有 50 个内部 Web 应用,就有 50 套认证逻辑(其中 45 套有 bug)。

IAP 把这个模型倒过来:

sequenceDiagram
    participant User as 用户浏览器
    participant IAP as IAP (反向代理)
    participant IdP as IdP (OIDC)
    participant App as 后端应用

    User->>IAP: GET /internal-tool
    IAP->>IAP: 检查 Session Cookie
    alt 无有效 Session
        IAP->>User: 302 重定向到 IdP
        User->>IdP: OIDC 登录 (可能含 MFA)
        IdP->>User: 302 携带 Authorization Code
        User->>IAP: GET /callback?code=xxx
        IAP->>IdP: 用 code 换 token
        IdP->>IAP: id_token + access_token
        IAP->>IAP: 创建 Session, 签发 Cookie
    end
    IAP->>IAP: 验证 Session, 查询授权策略
    alt 授权通过
        IAP->>App: 转发请求 (注入身份 Header)
        App->>IAP: 响应
        IAP->>User: 200 OK
    else 授权拒绝
        IAP->>User: 403 Forbidden
    end

这个模型的核心价值:应用代码里不再有认证逻辑。 应用只信任 IAP 注入的经过加密签名的身份信息。SSO 的集成、MFA 的启用、授权策略的变更,全部在 IAP 层完成,不需要应用发版。

二、Google IAP 的请求管线

Google IAP 是 Google Cloud 的内置服务,运行在 GCP 的全球负载均衡层——在请求到达后端之前就完成拦截。以下是它的完整请求管线。

2.1 OAuth2 认证阶段

当用户第一次访问受 IAP 保护的应用时:

  1. IAP 检查 Cookie(GCP_IAAP_AUTH_TOKEN)。
  2. 如果没有或已过期,重定向到 Google Accounts(accounts.google.com)执行 OAuth2 流程。
  3. 用户通过 Google 身份认证(包括 MFA,如果启用了)。
  4. Google Accounts 将 Authorization Code 通过浏览器重定向传回 IAP。
  5. IAP 用 code 向 Google Token Endpoint 换取 id_tokenaccess_token
  6. IAP 签发加密的 Session Cookie,设置在前端。

2.2 授权检查阶段

认证通过后,IAP 还执行一次 IAM 权限检查:

IAP 的授权模型是 IAM-based 的——简单但粗粒度。你可以在 IAM 中说”张三能访问这个应用”,但不能说”张三只能在周一到周五的 9-18 点访问”。

2.3 JWT 断言:IAP 向后端传递身份的核心机制

IAP 向后端应用注入 HTTP Header。关键 Header:

Header 签名 用途
X-Goog-IAP-JWT-Assertion ES256 签名 唯一可信的身份源
X-Goog-Authenticated-User-Email 无签名 显示/日志用途
X-Goog-Authenticated-User-ID 无签名 显示/日志用途

安全原则:后端应用绝对不能信任无签名的 Header。X-Goog-Authenticated-User-Email 在 IAP 被绕过时可以被攻击者随意伪造。唯一可信的是 X-Goog-IAP-JWT-Assertion 中的 ES256 签名 JWT。

JWT 验证的关键参数:

参数 用途
签名算法 ES256 (ECDSA P-256 + SHA-256) Google 选择的签名方案
iss https://cloud.google.com/iap 签发者验证
aud 项目/后端特定格式 防止跨服务 JWT 重放
JWKS URL https://www.gstatic.com/iap/verify/public_key-jwk 公钥获取
时钟偏差容忍 ±30 秒 exp/iat 的检查容差

2.4 后端的 JWT 验证实现

后端应用不能只读 Header——必须验证 JWT 签名。最小正确的实现(Go 示例):

import "google.golang.org/api/idtoken"

func authenticate(r *http.Request) (string, error) {
    iapJWT := r.Header.Get("X-Goog-IAP-JWT-Assertion")
    if iapJWT == "" {
        return "", fmt.Errorf("missing IAP assertion")
    }
    
    payload, err := idtoken.Validate(r.Context(), iapJWT, expectedAudience)
    if err != nil {
        return "", fmt.Errorf("JWT validation failed: %w", err)
    }
    
    email, ok := payload.Claims["email"].(string)
    if !ok {
        return "", fmt.Errorf("no email claim")
    }
    return email, nil
}

这个验证的三个关键步骤: 1. 从 Google 的 JWKS 端点获取 ES256 公钥(有内存缓存,每小时后台刷新) 2. 验证 iss = https://cloud.google.com/iapaud = 预配置值、exp 未过期 3. 提取 email 作为用户身份

2.5 认证逃逸(Auth Bypass)

一个被低估的安全风险:IAP 允许配置某些路径不需要认证(如 /health/public/*)。当应用本身的后端路由和 IAP 的路径白名单之间存在差异时,攻击者可以利用这种差异绕过 IAP:

IAP 配置: /internal/* → 需要认证
应用路由: /internal/admin/debug → 不需要鉴权(开发者留下的调试端点)

结果: IAP 对 /internal/admin/debug 放行(因为它匹配 /internal/*),
      但应用本身对这个路径没有认证——任何人都能访问。

防御措施:后端应用在 IAP 注入的 JWT 断言缺失时拒绝服务任何非公开路径。不要把”有 IAP”等同于”应用不需要做授权检查”。

三、Pomerium:开源 IAP 的完整实现

Pomerium 是基于 Envoy 构建的开源身份感知代理(Apache 2.0 许可),实现了一个功能上比 Google IAP 更灵活的替代方案。

3.1 四组件架构

Pomerium 由四个逻辑服务组成:

flowchart TD
    User["用户"] --> Proxy["Proxy Service<br/>(Envoy-based, 所有流量的入口)"]
    Proxy --> AuthN["Authentication Service<br/>(OAuth2/OIDC 流程)"]
    Proxy --> AuthZ["Authorization Service<br/>(每请求策略评估)"]
    Proxy --> Databroker["Databroker Service<br/>(状态存储, Session/Claims/Token)"]
    
    AuthN --> Databroker
    AuthZ --> Databroker
    AuthN --> IdP["IdP<br/>(Okta/Azure AD/Google/Keycloak/...)"]
    
    Proxy --> Upstream["上游应用"]

四个组件可以合并为单进程运行(开发环境),也可以分开部署(生产环境)。

3.2 与 Google IAP 的关键差异

维度 Google IAP Pomerium
部署范围 GCP only 任何环境(云/本地/混合)
IdP 支持 主要 Google Identity 任何 OIDC 兼容 IdP
授权模型 IAM 角色(粗粒度) 策略即代码(细粒度 context-aware)
协议支持 HTTP + TCP HTTP、TCP、gRPC、SSH、MCP
持续验证 每次请求 每次请求重新评估
流量隐私 Google 可解密你的流量 自托管,数据不外泄
多集群 依赖 VPN 隧道 原生多集群

授权策略的粒度差异是最关键的。Google IAP 的授权是”谁能访问这个应用”——Pomerium 的授权可以做到”张三只能在 Trusted 设备上、从中国 IP、在 9-18 点之间、访问 /api/orders 的 GET 方法”:

policy:
  - from: https://internal.example.com
    to: https://orders-api.internal
    allowed_users:
      - zhangsan@example.com
    allowed_idp_claims:
      groups:
        - engineering
    allow_any_authenticated_user: false

3.3 Envoy 代理的性能特征

Pomerium 基于 Envoy,这意味着它的数据平面继承了 Envoy 的性能特征——每秒百万级请求的处理能力、丰富的 HTTP 协议支持(HTTP/1.1、HTTP/2、gRPC),以及与非 HTTP 协议的兼容。但也意味着运维复杂度——Envoy 的配置文件和故障排查比 oauth2-proxy 复杂得多。

四、oauth2-proxy:简单的代价

oauth2-proxy 是最轻量的 IAP 实现——它是一个 Go 编写的单进程反向代理,从最初的 Google Auth Proxy 演化而来。它的设计哲学是”只做认证,不做授权”。

维度 oauth2-proxy Pomerium
授权模型 二元(登录/未登录) 策略即代码(context-aware)
持续验证 否(Session 持续到过期) 每请求重新评估
API 支持 Web only 全部 HTTP API
部署复杂度 极低(单二进制) 中(四个服务组件)

oauth2-proxy 适合简单的场景——一个内部 Wiki 或 Dashboard 需要登录控制。但一旦你需要”市场部的人不能访问财务 Dashboard”或者”在手机上不能访问生产环境的 API”,oauth2-proxy 就不够了。它的本质是”认证代理”而非”身份感知代理”——区别在于它不问”你是谁”之后就问”你能做什么”。

五、IAP 的工程坑点

5.1 Header Injection 的信任问题

所有 IAP 实现都面临同一个问题:后端怎么信任 IAP 注入的 Header?

如果 IAP 和后端之间的连接不是 mTLS 加密的,攻击者可以绕过 IAP 直接向后端发送伪造的 Header。防御方法:

5.2 长连接的 Session 续期

WebSocket、gRPC streaming、SSE(Server-Sent Events)等长连接在 IAP 后面有一个棘手问题:一次连接建立时通过了认证和授权,但 30 分钟后用户的角色变了(HR 系统显示该员工已离职),IAP 不能强行关闭这个已经建立的 WebSocket 连接。

当前的实践是折中:IAP 验证每个新连接,但不插手已建立的连接。长连接的应用需要自己在应用层做周期性权限检查(如每 5 分钟验证一次 JWT 的 iat 是否仍然在允许的窗口内)。

5.3 性能与延迟

IAP 在请求路径上引入了额外的处理——OAuth2 token 验证、Session 查找、策略评估。这些操作的延迟取决于 IAP 的实现方式和部署位置:

在生产中,10-20ms 的 IAP 延迟对大多数 Web 应用来说是微不足道的(远小于后端处理的延迟),但对高频 API 调用来说需要纳入设计考量。

六、选型建议

需求评估流程:

1. 你只需要"登录控制"(一个内部 Dashboard 不要让外部访问)?
   → oauth2-proxy 足够。

2. 你需要"谁 + 在什么设备/时间/位置 + 能访问什么 + 什么操作"?
   → Pomerium 或类似的开源 IAP。

3. 你的所有工作负载都在 GCP,且你接受 Google IAP 的 IAM 授权模型?
   → Google IAP。

4. 你需要多云/混合云,且不信任任何厂商持有你的流量?
   → Pomerium(自托管)。

5. 你的团队 < 20 人,想尽可能少运维基础设施?
   → Cloudflare Access(agentless ZTNA,下一篇文章讨论)。

下一篇:设备姿态与远程证明,拆解 TPM 2.0 远程证明协议和设备信任分数的计算。

参考资料

  1. Google Cloud. Identity-Aware Proxy Documentation. https://cloud.google.com/iap/docs
  2. Pomerium. Architecture Overview. https://www.pomerium.com/docs/internals/architecture
  3. oauth2-proxy. GitHub Repository. https://github.com/oauth2-proxy/oauth2-proxy
  4. Escobedo, V. et al. (2016). “BeyondCorp: The Access Proxy”. ;login:, Vol. 42, No. 4.

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-13 · architecture / security

【身份与访问控制工程】IAM 全景:为什么这是高价值赛道

从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。

2026-06-15 · architecture / security

【身份与访问控制工程】JWT、JWS、JWE、JWKS 一次讲透

JWT 不等于 JWS。JWS 是签名格式,JWE 是加密格式,JWK 是密钥表示,JWKS 是密钥集合——这四个规范共同构成了 JOSE(JSON Object Signing and Encryption)技术族。本文从 JOSE 体系全景出发,逐层拆解 JWT 的三段式结构、JWS 的签名算法选择(从 HS256 到 EdDSA 的选择逻辑)、JWE 的密钥加密与内容加密双层模型、JWKS 的密钥轮换与缓存策略。

2026-06-15 · architecture / security

【身份与访问控制工程】Session、Refresh Token 与吊销体系

JWT 的无状态设计带来了可扩展性,但让令牌吊销变成了系统性问题——签出去的 JWT 在到期之前全是活令牌。Refresh Token Rotation、Token Introspection、基于事件的吊销通知、撤销列表——这些机制构成了身份系统的'紧急刹车',各自的成本、延迟和覆盖范围完全不同。本文拆解四种吊销机制的工程权衡。

2026-06-17 · architecture / security

【身份与访问控制工程】服务身份:mTLS、SPIFFE/SPIRE 与 Workload Identity

前 9 篇讨论的都是'人'的身份——用户怎么登录、怎么验证。但微服务世界中,80% 的 API 调用是服务之间的。服务身份(Workload Identity)是整个 IAM 体系的另一半:mTLS 解决'传输层你是谁',SPIFFE/SPIRE 解决'在平台层你是谁且怎么证明',JWT Profile for OAuth 解决'我怎么拿到一个服务身份的 Token'。本文从这三条线拆解服务身份的工程实现。


By .